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