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