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:
FusionFeature(FusionKind Kind,bool HasFeature,int Index,const FusionOpSet & First,const FusionOpSet & Second)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
hasOp1(unsigned Opc) const55 bool hasOp1(unsigned Opc) const { return OpSet1.contains(Opc); }
hasOp2(unsigned Opc) const56 bool hasOp2(unsigned Opc) const { return OpSet2.contains(Opc); }
isSupported() const57 bool isSupported() const { return Supported; }
depOpIdx() const58 Optional<unsigned> depOpIdx() const {
59 if (DepOpIdx < 0)
60 return None;
61 return DepOpIdx;
62 }
63
getKind() const64 FusionKind getKind() const { return Kd; }
65 };
66
matchingRegOps(const MachineInstr & FirstMI,int FirstMIOpIndex,const MachineInstr & SecondMI,int SecondMIOpIndex)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
matchingImmOps(const MachineInstr & MI,int MIOpIndex,int64_t Expect,unsigned ExtendFrom=64)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.
checkOpConstraints(FusionFeature::FusionKind Kd,const MachineInstr & FirstMI,const MachineInstr & SecondMI)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.
shouldScheduleAdjacent(const TargetInstrInfo & TII,const TargetSubtargetInfo & TSI,const MachineInstr * FirstMI,const MachineInstr & SecondMI)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
createPowerPCMacroFusionDAGMutation()290 std::unique_ptr<ScheduleDAGMutation> createPowerPCMacroFusionDAGMutation () {
291 return createMacroFusionDAGMutation(shouldScheduleAdjacent);
292 }
293
294 } // end namespace llvm
295