xref: /freebsd/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMacroFusion.cpp (revision d30a1689f5b37e78ea189232a8b94a7011dc0dc8)
1 //===- PPCMacroFusion.cpp - PowerPC Macro Fusion --------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file This file contains the PowerPC implementation of the DAG scheduling
10 ///  mutation to pair instructions back to back.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "PPC.h"
15 #include "PPCSubtarget.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include "llvm/CodeGen/MacroFusion.h"
18 
19 using namespace llvm;
20 namespace {
21 
22 class FusionFeature {
23 public:
24   typedef SmallDenseSet<unsigned> FusionOpSet;
25 
26   enum FusionKind {
27   #define FUSION_KIND(KIND) FK_##KIND
28   #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) \
29     FUSION_KIND(KIND),
30   #include "PPCMacroFusion.def"
31   FUSION_KIND(END)
32   };
33 private:
34   // Each fusion feature is assigned with one fusion kind. All the
35   // instructions with the same fusion kind have the same fusion characteristic.
36   FusionKind Kd;
37   // True if this feature is enabled.
38   bool Supported;
39   // li rx, si
40   // load rt, ra, rx
41   // The dependent operand index in the second op(load). And the negative means
42   // it could be any one.
43   int DepOpIdx;
44   // The first fusion op set.
45   FusionOpSet OpSet1;
46   // The second fusion op set.
47   FusionOpSet OpSet2;
48 public:
49   FusionFeature(FusionKind Kind, bool HasFeature, int Index,
50                 const FusionOpSet &First, const FusionOpSet &Second) :
51     Kd(Kind), Supported(HasFeature), DepOpIdx(Index), OpSet1(First),
52     OpSet2(Second) {}
53 
54   bool hasOp1(unsigned Opc) const { return OpSet1.contains(Opc); }
55   bool hasOp2(unsigned Opc) const { return OpSet2.contains(Opc); }
56   bool isSupported() const { return Supported; }
57   Optional<unsigned> depOpIdx() const {
58     if (DepOpIdx < 0)
59       return None;
60     return DepOpIdx;
61   }
62 
63   FusionKind getKind() const { return Kd; }
64 };
65 
66 static bool matchingRegOps(const MachineInstr &FirstMI,
67                            int FirstMIOpIndex,
68                            const MachineInstr &SecondMI,
69                            int SecondMIOpIndex) {
70   const MachineOperand &Op1 = FirstMI.getOperand(FirstMIOpIndex);
71   const MachineOperand &Op2 = SecondMI.getOperand(SecondMIOpIndex);
72   if (!Op1.isReg() || !Op2.isReg())
73     return false;
74 
75   return Op1.getReg() == Op2.getReg();
76 }
77 
78 static bool matchingImmOps(const MachineInstr &MI,
79                            int MIOpIndex,
80                            int64_t Expect,
81                            unsigned ExtendFrom = 64) {
82   const MachineOperand &Op = MI.getOperand(MIOpIndex);
83   if (!Op.isImm())
84     return false;
85   int64_t Imm = Op.getImm();
86   if (ExtendFrom < 64)
87     Imm = SignExtend64(Imm, ExtendFrom);
88   return Imm == Expect;
89 }
90 
91 // Return true if the FirstMI meets the constraints of SecondMI according to
92 // fusion specification.
93 static bool checkOpConstraints(FusionFeature::FusionKind Kd,
94                                const MachineInstr &FirstMI,
95                                const MachineInstr &SecondMI) {
96   switch (Kd) {
97   // The hardware didn't require any specific check for the fused instructions'
98   // operands. Therefore, return true to indicate that, it is fusable.
99   default: return true;
100   // [addi rt,ra,si - lxvd2x xt,ra,rb] etc.
101   case FusionFeature::FK_AddiLoad: {
102     // lxvd2x(ra) cannot be zero
103     const MachineOperand &RA = SecondMI.getOperand(1);
104     if (!RA.isReg())
105       return true;
106 
107     return Register::isVirtualRegister(RA.getReg()) ||
108       (RA.getReg() != PPC::ZERO && RA.getReg() != PPC::ZERO8);
109   }
110   // [addis rt,ra,si - ld rt,ds(ra)] etc.
111   case FusionFeature::FK_AddisLoad: {
112     const MachineOperand &RT = SecondMI.getOperand(0);
113     if (!RT.isReg())
114       return true;
115 
116     // Only check it for non-virtual register.
117     if (!Register::isVirtualRegister(RT.getReg()))
118       // addis(rt) = ld(ra) = ld(rt)
119       // ld(rt) cannot be zero
120       if (!matchingRegOps(SecondMI, 0, SecondMI, 2) ||
121           (RT.getReg() == PPC::ZERO || RT.getReg() == PPC::ZERO8))
122           return false;
123 
124     // addis(si) first 12 bits must be all 1s or all 0s
125     const MachineOperand &SI = FirstMI.getOperand(2);
126     if (!SI.isImm())
127       return true;
128     int64_t Imm = SI.getImm();
129     if (((Imm & 0xFFF0) != 0) && ((Imm & 0xFFF0) != 0xFFF0))
130       return false;
131 
132     // If si = 1111111111110000 and the msb of the d/ds field of the load equals
133     // 1, then fusion does not occur.
134     if ((Imm & 0xFFF0) == 0xFFF0) {
135       const MachineOperand &D = SecondMI.getOperand(1);
136       if (!D.isImm())
137         return true;
138 
139       // 14 bit for DS field, while 16 bit for D field.
140       int MSB = 15;
141       if (SecondMI.getOpcode() == PPC::LD)
142         MSB = 13;
143 
144       return (D.getImm() & (1ULL << MSB)) == 0;
145     }
146     return true;
147   }
148 
149   case FusionFeature::FK_SldiAdd:
150     return (matchingImmOps(FirstMI, 2, 3) && matchingImmOps(FirstMI, 3, 60)) ||
151            (matchingImmOps(FirstMI, 2, 6) && matchingImmOps(FirstMI, 3, 57));
152 
153   // rldicl rx, ra, 1, 0  - xor
154   case FusionFeature::FK_RotateLeftXor:
155     return matchingImmOps(FirstMI, 2, 1) && matchingImmOps(FirstMI, 3, 0);
156 
157   // rldicr rx, ra, 1, 63 - xor
158   case FusionFeature::FK_RotateRightXor:
159     return matchingImmOps(FirstMI, 2, 1) && matchingImmOps(FirstMI, 3, 63);
160 
161   // We actually use CMPW* and CMPD*, 'l' doesn't exist as an operand in instr.
162 
163   // { lbz,lbzx,lhz,lhzx,lwz,lwzx } - cmpi 0,1,rx,{ 0,1,-1 }
164   // { lbz,lbzx,lhz,lhzx,lwz,lwzx } - cmpli 0,L,rx,{ 0,1 }
165   case FusionFeature::FK_LoadCmp1:
166   // { ld,ldx } - cmpi 0,1,rx,{ 0,1,-1 }
167   // { ld,ldx } - cmpli 0,1,rx,{ 0,1 }
168   case FusionFeature::FK_LoadCmp2: {
169     const MachineOperand &BT = SecondMI.getOperand(0);
170     if (!BT.isReg() ||
171         (!Register::isVirtualRegister(BT.getReg()) && BT.getReg() != PPC::CR0))
172       return false;
173     if (SecondMI.getOpcode() == PPC::CMPDI &&
174         matchingImmOps(SecondMI, 2, -1, 16))
175       return true;
176     return matchingImmOps(SecondMI, 2, 0) || matchingImmOps(SecondMI, 2, 1);
177   }
178 
179   // { lha,lhax,lwa,lwax } - cmpi 0,L,rx,{ 0,1,-1 }
180   case FusionFeature::FK_LoadCmp3: {
181     const MachineOperand &BT = SecondMI.getOperand(0);
182     if (!BT.isReg() ||
183         (!Register::isVirtualRegister(BT.getReg()) && BT.getReg() != PPC::CR0))
184       return false;
185     return matchingImmOps(SecondMI, 2, 0) || matchingImmOps(SecondMI, 2, 1) ||
186            matchingImmOps(SecondMI, 2, -1, 16);
187   }
188 
189   // mtctr - { bcctr,bcctrl }
190   case FusionFeature::FK_ZeroMoveCTR:
191     // ( mtctr rx ) is alias of ( mtspr 9, rx )
192     return (FirstMI.getOpcode() != PPC::MTSPR &&
193             FirstMI.getOpcode() != PPC::MTSPR8) ||
194            matchingImmOps(FirstMI, 0, 9);
195 
196   // mtlr - { bclr,bclrl }
197   case FusionFeature::FK_ZeroMoveLR:
198     // ( mtlr rx ) is alias of ( mtspr 8, rx )
199     return (FirstMI.getOpcode() != PPC::MTSPR &&
200             FirstMI.getOpcode() != PPC::MTSPR8) ||
201            matchingImmOps(FirstMI, 0, 8);
202 
203   // addis rx,ra,si - addi rt,rx,SI, SI >= 0
204   case FusionFeature::FK_AddisAddi: {
205     const MachineOperand &RA = FirstMI.getOperand(1);
206     const MachineOperand &SI = SecondMI.getOperand(2);
207     if (!SI.isImm() || !RA.isReg())
208       return false;
209     if (RA.getReg() == PPC::ZERO || RA.getReg() == PPC::ZERO8)
210       return false;
211     return SignExtend64(SI.getImm(), 16) >= 0;
212   }
213 
214   // addi rx,ra,si - addis rt,rx,SI, ra > 0, SI >= 2
215   case FusionFeature::FK_AddiAddis: {
216     const MachineOperand &RA = FirstMI.getOperand(1);
217     const MachineOperand &SI = FirstMI.getOperand(2);
218     if (!SI.isImm() || !RA.isReg())
219       return false;
220     if (RA.getReg() == PPC::ZERO || RA.getReg() == PPC::ZERO8)
221       return false;
222     int64_t ExtendedSI = SignExtend64(SI.getImm(), 16);
223     return ExtendedSI >= 2;
224   }
225   }
226 
227   llvm_unreachable("All the cases should have been handled");
228   return true;
229 }
230 
231 /// Check if the instr pair, FirstMI and SecondMI, should be fused together.
232 /// Given SecondMI, when FirstMI is unspecified, then check if SecondMI may be
233 /// part of a fused pair at all.
234 static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
235                                    const TargetSubtargetInfo &TSI,
236                                    const MachineInstr *FirstMI,
237                                    const MachineInstr &SecondMI) {
238   // We use the PPC namespace to avoid the need to prefix opcodes with PPC:: in
239   // the def file.
240   using namespace PPC;
241 
242   const PPCSubtarget &ST = static_cast<const PPCSubtarget&>(TSI);
243   static const FusionFeature FusionFeatures[] = {
244   #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) { \
245     FusionFeature::FUSION_KIND(KIND), ST.HAS_FEATURE(), DEP_OP_IDX, { OPSET1 },\
246     { OPSET2 } },
247    #include "PPCMacroFusion.def"
248   };
249   #undef FUSION_KIND
250 
251   for (auto &Feature : FusionFeatures) {
252     // Skip if the feature is not supported.
253     if (!Feature.isSupported())
254       continue;
255 
256     // Only when the SecondMI is fusable, we are starting to look for the
257     // fusable FirstMI.
258     if (Feature.hasOp2(SecondMI.getOpcode())) {
259       // If FirstMI == nullptr, that means, we're only checking whether SecondMI
260       // can be fused at all.
261       if (!FirstMI)
262         return true;
263 
264       // Checking if the FirstMI is fusable with the SecondMI.
265       if (!Feature.hasOp1(FirstMI->getOpcode()))
266         continue;
267 
268       auto DepOpIdx = Feature.depOpIdx();
269       if (DepOpIdx.hasValue()) {
270         // Checking if the result of the FirstMI is the desired operand of the
271         // SecondMI if the DepOpIdx is set. Otherwise, ignore it.
272         if (!matchingRegOps(*FirstMI, 0, SecondMI, *DepOpIdx))
273           return false;
274       }
275 
276       // Checking more on the instruction operands.
277       if (checkOpConstraints(Feature.getKind(), *FirstMI, SecondMI))
278         return true;
279     }
280   }
281 
282   return false;
283 }
284 
285 } // end anonymous namespace
286 
287 namespace llvm {
288 
289 std::unique_ptr<ScheduleDAGMutation> createPowerPCMacroFusionDAGMutation () {
290   return createMacroFusionDAGMutation(shouldScheduleAdjacent);
291 }
292 
293 } // end namespace llvm
294