1 //===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 /// \file This file implements the LegalizerHelper class to legalize 11 /// individual instructions and the LegalizeMachineIR wrapper pass for the 12 /// primary legalization. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 17 #include "llvm/CodeGen/GlobalISel/CallLowering.h" 18 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" 19 #include "llvm/CodeGen/MachineRegisterInfo.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include "llvm/Target/TargetLowering.h" 23 #include "llvm/Target/TargetSubtargetInfo.h" 24 25 #include <sstream> 26 27 #define DEBUG_TYPE "legalize-mir" 28 29 using namespace llvm; 30 31 LegalizerHelper::LegalizerHelper(MachineFunction &MF) 32 : MRI(MF.getRegInfo()) { 33 MIRBuilder.setMF(MF); 34 } 35 36 LegalizerHelper::LegalizeResult 37 LegalizerHelper::legalizeInstrStep(MachineInstr &MI, 38 const LegalizerInfo &LegalizerInfo) { 39 auto Action = LegalizerInfo.getAction(MI, MRI); 40 switch (std::get<0>(Action)) { 41 case LegalizerInfo::Legal: 42 return AlreadyLegal; 43 case LegalizerInfo::Libcall: 44 return libcall(MI); 45 case LegalizerInfo::NarrowScalar: 46 return narrowScalar(MI, std::get<1>(Action), std::get<2>(Action)); 47 case LegalizerInfo::WidenScalar: 48 return widenScalar(MI, std::get<1>(Action), std::get<2>(Action)); 49 case LegalizerInfo::Lower: 50 return lower(MI, std::get<1>(Action), std::get<2>(Action)); 51 case LegalizerInfo::FewerElements: 52 return fewerElementsVector(MI, std::get<1>(Action), std::get<2>(Action)); 53 default: 54 return UnableToLegalize; 55 } 56 } 57 58 LegalizerHelper::LegalizeResult 59 LegalizerHelper::legalizeInstr(MachineInstr &MI, 60 const LegalizerInfo &LegalizerInfo) { 61 SmallVector<MachineInstr *, 4> WorkList; 62 MIRBuilder.recordInsertions( 63 [&](MachineInstr *MI) { WorkList.push_back(MI); }); 64 WorkList.push_back(&MI); 65 66 bool Changed = false; 67 LegalizeResult Res; 68 unsigned Idx = 0; 69 do { 70 Res = legalizeInstrStep(*WorkList[Idx], LegalizerInfo); 71 if (Res == UnableToLegalize) { 72 MIRBuilder.stopRecordingInsertions(); 73 return UnableToLegalize; 74 } 75 Changed |= Res == Legalized; 76 ++Idx; 77 } while (Idx < WorkList.size()); 78 79 MIRBuilder.stopRecordingInsertions(); 80 81 return Changed ? Legalized : AlreadyLegal; 82 } 83 84 void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts, 85 SmallVectorImpl<unsigned> &VRegs) { 86 unsigned Size = Ty.getSizeInBits(); 87 SmallVector<uint64_t, 4> Indexes; 88 for (int i = 0; i < NumParts; ++i) { 89 VRegs.push_back(MRI.createGenericVirtualRegister(Ty)); 90 Indexes.push_back(i * Size); 91 } 92 MIRBuilder.buildExtract(VRegs, Indexes, Reg); 93 } 94 95 LegalizerHelper::LegalizeResult 96 LegalizerHelper::libcall(MachineInstr &MI) { 97 LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 98 unsigned Size = Ty.getSizeInBits(); 99 MIRBuilder.setInstr(MI); 100 101 switch (MI.getOpcode()) { 102 default: 103 return UnableToLegalize; 104 case TargetOpcode::G_FREM: { 105 auto &Ctx = MIRBuilder.getMF().getFunction()->getContext(); 106 Type *Ty = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx); 107 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering(); 108 auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); 109 const char *Name = 110 TLI.getLibcallName(Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32); 111 112 CLI.lowerCall( 113 MIRBuilder, MachineOperand::CreateES(Name), 114 {MI.getOperand(0).getReg(), Ty}, 115 {{MI.getOperand(1).getReg(), Ty}, {MI.getOperand(2).getReg(), Ty}}); 116 MI.eraseFromParent(); 117 return Legalized; 118 } 119 } 120 } 121 122 LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, 123 unsigned TypeIdx, 124 LLT NarrowTy) { 125 // FIXME: Don't know how to handle secondary types yet. 126 if (TypeIdx != 0) 127 return UnableToLegalize; 128 switch (MI.getOpcode()) { 129 default: 130 return UnableToLegalize; 131 case TargetOpcode::G_ADD: { 132 // Expand in terms of carry-setting/consuming G_ADDE instructions. 133 unsigned NarrowSize = NarrowTy.getSizeInBits(); 134 int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / 135 NarrowTy.getSizeInBits(); 136 137 MIRBuilder.setInstr(MI); 138 139 SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; 140 SmallVector<uint64_t, 2> Indexes; 141 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); 142 extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); 143 144 unsigned CarryIn = MRI.createGenericVirtualRegister(LLT::scalar(1)); 145 MIRBuilder.buildConstant(CarryIn, 0); 146 147 for (int i = 0; i < NumParts; ++i) { 148 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 149 unsigned CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1)); 150 151 MIRBuilder.buildUAdde(DstReg, CarryOut, Src1Regs[i], 152 Src2Regs[i], CarryIn); 153 154 DstRegs.push_back(DstReg); 155 Indexes.push_back(i * NarrowSize); 156 CarryIn = CarryOut; 157 } 158 unsigned DstReg = MI.getOperand(0).getReg(); 159 MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); 160 MI.eraseFromParent(); 161 return Legalized; 162 } 163 } 164 } 165 166 LegalizerHelper::LegalizeResult 167 LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { 168 MIRBuilder.setInstr(MI); 169 170 switch (MI.getOpcode()) { 171 default: 172 return UnableToLegalize; 173 case TargetOpcode::G_ADD: 174 case TargetOpcode::G_AND: 175 case TargetOpcode::G_MUL: 176 case TargetOpcode::G_OR: 177 case TargetOpcode::G_XOR: 178 case TargetOpcode::G_SUB: { 179 // Perform operation at larger width (any extension is fine here, high bits 180 // don't affect the result) and then truncate the result back to the 181 // original type. 182 unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy); 183 unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy); 184 MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg()); 185 MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg()); 186 187 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 188 MIRBuilder.buildInstr(MI.getOpcode()) 189 .addDef(DstExt) 190 .addUse(Src1Ext) 191 .addUse(Src2Ext); 192 193 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 194 MI.eraseFromParent(); 195 return Legalized; 196 } 197 case TargetOpcode::G_SDIV: 198 case TargetOpcode::G_UDIV: { 199 unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV 200 ? TargetOpcode::G_SEXT 201 : TargetOpcode::G_ZEXT; 202 203 unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy); 204 MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse( 205 MI.getOperand(1).getReg()); 206 207 unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy); 208 MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse( 209 MI.getOperand(2).getReg()); 210 211 unsigned ResExt = MRI.createGenericVirtualRegister(WideTy); 212 MIRBuilder.buildInstr(MI.getOpcode()) 213 .addDef(ResExt) 214 .addUse(LHSExt) 215 .addUse(RHSExt); 216 217 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt); 218 MI.eraseFromParent(); 219 return Legalized; 220 } 221 case TargetOpcode::G_LOAD: { 222 assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) == 223 WideTy.getSizeInBits() && 224 "illegal to increase number of bytes loaded"); 225 226 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 227 MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(), 228 **MI.memoperands_begin()); 229 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 230 MI.eraseFromParent(); 231 return Legalized; 232 } 233 case TargetOpcode::G_STORE: { 234 assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) == 235 WideTy.getSizeInBits() && 236 "illegal to increase number of bytes modified by a store"); 237 238 unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); 239 MIRBuilder.buildAnyExt(SrcExt, MI.getOperand(0).getReg()); 240 MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(), 241 **MI.memoperands_begin()); 242 MI.eraseFromParent(); 243 return Legalized; 244 } 245 case TargetOpcode::G_CONSTANT: { 246 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 247 MIRBuilder.buildConstant(DstExt, MI.getOperand(1).getImm()); 248 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 249 MI.eraseFromParent(); 250 return Legalized; 251 } 252 case TargetOpcode::G_FCONSTANT: { 253 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 254 MIRBuilder.buildFConstant(DstExt, *MI.getOperand(1).getFPImm()); 255 MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), DstExt); 256 MI.eraseFromParent(); 257 return Legalized; 258 } 259 case TargetOpcode::G_BRCOND: { 260 unsigned TstExt = MRI.createGenericVirtualRegister(WideTy); 261 MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg()); 262 MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB()); 263 MI.eraseFromParent(); 264 return Legalized; 265 } 266 case TargetOpcode::G_ICMP: { 267 assert(TypeIdx == 1 && "unable to legalize predicate"); 268 bool IsSigned = CmpInst::isSigned( 269 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate())); 270 unsigned Op0Ext = MRI.createGenericVirtualRegister(WideTy); 271 unsigned Op1Ext = MRI.createGenericVirtualRegister(WideTy); 272 if (IsSigned) { 273 MIRBuilder.buildSExt(Op0Ext, MI.getOperand(2).getReg()); 274 MIRBuilder.buildSExt(Op1Ext, MI.getOperand(3).getReg()); 275 } else { 276 MIRBuilder.buildZExt(Op0Ext, MI.getOperand(2).getReg()); 277 MIRBuilder.buildZExt(Op1Ext, MI.getOperand(3).getReg()); 278 } 279 MIRBuilder.buildICmp( 280 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()), 281 MI.getOperand(0).getReg(), Op0Ext, Op1Ext); 282 MI.eraseFromParent(); 283 return Legalized; 284 } 285 case TargetOpcode::G_GEP: { 286 assert(TypeIdx == 1 && "unable to legalize pointer of GEP"); 287 unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy); 288 MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg()); 289 MI.getOperand(2).setReg(OffsetExt); 290 return Legalized; 291 } 292 } 293 } 294 295 LegalizerHelper::LegalizeResult 296 LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { 297 using namespace TargetOpcode; 298 MIRBuilder.setInstr(MI); 299 300 switch(MI.getOpcode()) { 301 default: 302 return UnableToLegalize; 303 case TargetOpcode::G_SREM: 304 case TargetOpcode::G_UREM: { 305 unsigned QuotReg = MRI.createGenericVirtualRegister(Ty); 306 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV) 307 .addDef(QuotReg) 308 .addUse(MI.getOperand(1).getReg()) 309 .addUse(MI.getOperand(2).getReg()); 310 311 unsigned ProdReg = MRI.createGenericVirtualRegister(Ty); 312 MIRBuilder.buildMul(ProdReg, QuotReg, MI.getOperand(2).getReg()); 313 MIRBuilder.buildSub(MI.getOperand(0).getReg(), MI.getOperand(1).getReg(), 314 ProdReg); 315 MI.eraseFromParent(); 316 return Legalized; 317 } 318 } 319 } 320 321 LegalizerHelper::LegalizeResult 322 LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, 323 LLT NarrowTy) { 324 // FIXME: Don't know how to handle secondary types yet. 325 if (TypeIdx != 0) 326 return UnableToLegalize; 327 switch (MI.getOpcode()) { 328 default: 329 return UnableToLegalize; 330 case TargetOpcode::G_ADD: { 331 unsigned NarrowSize = NarrowTy.getSizeInBits(); 332 unsigned DstReg = MI.getOperand(0).getReg(); 333 int NumParts = MRI.getType(DstReg).getSizeInBits() / NarrowSize; 334 335 MIRBuilder.setInstr(MI); 336 337 SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; 338 SmallVector<uint64_t, 2> Indexes; 339 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); 340 extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); 341 342 for (int i = 0; i < NumParts; ++i) { 343 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 344 MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]); 345 DstRegs.push_back(DstReg); 346 Indexes.push_back(i * NarrowSize); 347 } 348 349 MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); 350 MI.eraseFromParent(); 351 return Legalized; 352 } 353 } 354 } 355