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 129 MIRBuilder.setInstr(MI); 130 131 switch (MI.getOpcode()) { 132 default: 133 return UnableToLegalize; 134 case TargetOpcode::G_ADD: { 135 // Expand in terms of carry-setting/consuming G_ADDE instructions. 136 unsigned NarrowSize = NarrowTy.getSizeInBits(); 137 int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / 138 NarrowTy.getSizeInBits(); 139 140 SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; 141 SmallVector<uint64_t, 2> Indexes; 142 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); 143 extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); 144 145 unsigned CarryIn = MRI.createGenericVirtualRegister(LLT::scalar(1)); 146 MIRBuilder.buildConstant(CarryIn, 0); 147 148 for (int i = 0; i < NumParts; ++i) { 149 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 150 unsigned CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1)); 151 152 MIRBuilder.buildUAdde(DstReg, CarryOut, Src1Regs[i], 153 Src2Regs[i], CarryIn); 154 155 DstRegs.push_back(DstReg); 156 Indexes.push_back(i * NarrowSize); 157 CarryIn = CarryOut; 158 } 159 unsigned DstReg = MI.getOperand(0).getReg(); 160 MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); 161 MI.eraseFromParent(); 162 return Legalized; 163 } 164 case TargetOpcode::G_STORE: { 165 unsigned NarrowSize = NarrowTy.getSizeInBits(); 166 int NumParts = 167 MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize; 168 LLT NarrowPtrTy = LLT::pointer( 169 MRI.getType(MI.getOperand(1).getReg()).getAddressSpace(), NarrowSize); 170 171 SmallVector<unsigned, 2> SrcRegs; 172 extractParts(MI.getOperand(0).getReg(), NarrowTy, NumParts, SrcRegs); 173 174 for (int i = 0; i < NumParts; ++i) { 175 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowPtrTy); 176 unsigned Offset = MRI.createGenericVirtualRegister(LLT::scalar(64)); 177 MIRBuilder.buildConstant(Offset, i * NarrowSize / 8); 178 MIRBuilder.buildGEP(DstReg, MI.getOperand(1).getReg(), Offset); 179 MIRBuilder.buildStore(SrcRegs[i], DstReg, **MI.memoperands_begin()); 180 } 181 MI.eraseFromParent(); 182 return Legalized; 183 } 184 } 185 } 186 187 LegalizerHelper::LegalizeResult 188 LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { 189 MIRBuilder.setInstr(MI); 190 191 switch (MI.getOpcode()) { 192 default: 193 return UnableToLegalize; 194 case TargetOpcode::G_ADD: 195 case TargetOpcode::G_AND: 196 case TargetOpcode::G_MUL: 197 case TargetOpcode::G_OR: 198 case TargetOpcode::G_XOR: 199 case TargetOpcode::G_SUB: { 200 // Perform operation at larger width (any extension is fine here, high bits 201 // don't affect the result) and then truncate the result back to the 202 // original type. 203 unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy); 204 unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy); 205 MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg()); 206 MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg()); 207 208 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 209 MIRBuilder.buildInstr(MI.getOpcode()) 210 .addDef(DstExt) 211 .addUse(Src1Ext) 212 .addUse(Src2Ext); 213 214 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 215 MI.eraseFromParent(); 216 return Legalized; 217 } 218 case TargetOpcode::G_SDIV: 219 case TargetOpcode::G_UDIV: { 220 unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV 221 ? TargetOpcode::G_SEXT 222 : TargetOpcode::G_ZEXT; 223 224 unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy); 225 MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse( 226 MI.getOperand(1).getReg()); 227 228 unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy); 229 MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse( 230 MI.getOperand(2).getReg()); 231 232 unsigned ResExt = MRI.createGenericVirtualRegister(WideTy); 233 MIRBuilder.buildInstr(MI.getOpcode()) 234 .addDef(ResExt) 235 .addUse(LHSExt) 236 .addUse(RHSExt); 237 238 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt); 239 MI.eraseFromParent(); 240 return Legalized; 241 } 242 case TargetOpcode::G_LOAD: { 243 assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) == 244 WideTy.getSizeInBits() && 245 "illegal to increase number of bytes loaded"); 246 247 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 248 MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(), 249 **MI.memoperands_begin()); 250 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 251 MI.eraseFromParent(); 252 return Legalized; 253 } 254 case TargetOpcode::G_STORE: { 255 assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) == 256 WideTy.getSizeInBits() && 257 "illegal to increase number of bytes modified by a store"); 258 259 unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); 260 MIRBuilder.buildAnyExt(SrcExt, MI.getOperand(0).getReg()); 261 MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(), 262 **MI.memoperands_begin()); 263 MI.eraseFromParent(); 264 return Legalized; 265 } 266 case TargetOpcode::G_CONSTANT: { 267 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 268 MIRBuilder.buildConstant(DstExt, *MI.getOperand(1).getCImm()); 269 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 270 MI.eraseFromParent(); 271 return Legalized; 272 } 273 case TargetOpcode::G_FCONSTANT: { 274 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 275 MIRBuilder.buildFConstant(DstExt, *MI.getOperand(1).getFPImm()); 276 MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), DstExt); 277 MI.eraseFromParent(); 278 return Legalized; 279 } 280 case TargetOpcode::G_BRCOND: { 281 unsigned TstExt = MRI.createGenericVirtualRegister(WideTy); 282 MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg()); 283 MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB()); 284 MI.eraseFromParent(); 285 return Legalized; 286 } 287 case TargetOpcode::G_ICMP: { 288 assert(TypeIdx == 1 && "unable to legalize predicate"); 289 bool IsSigned = CmpInst::isSigned( 290 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate())); 291 unsigned Op0Ext = MRI.createGenericVirtualRegister(WideTy); 292 unsigned Op1Ext = MRI.createGenericVirtualRegister(WideTy); 293 if (IsSigned) { 294 MIRBuilder.buildSExt(Op0Ext, MI.getOperand(2).getReg()); 295 MIRBuilder.buildSExt(Op1Ext, MI.getOperand(3).getReg()); 296 } else { 297 MIRBuilder.buildZExt(Op0Ext, MI.getOperand(2).getReg()); 298 MIRBuilder.buildZExt(Op1Ext, MI.getOperand(3).getReg()); 299 } 300 MIRBuilder.buildICmp( 301 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()), 302 MI.getOperand(0).getReg(), Op0Ext, Op1Ext); 303 MI.eraseFromParent(); 304 return Legalized; 305 } 306 case TargetOpcode::G_GEP: { 307 assert(TypeIdx == 1 && "unable to legalize pointer of GEP"); 308 unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy); 309 MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg()); 310 MI.getOperand(2).setReg(OffsetExt); 311 return Legalized; 312 } 313 } 314 } 315 316 LegalizerHelper::LegalizeResult 317 LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { 318 using namespace TargetOpcode; 319 MIRBuilder.setInstr(MI); 320 321 switch(MI.getOpcode()) { 322 default: 323 return UnableToLegalize; 324 case TargetOpcode::G_SREM: 325 case TargetOpcode::G_UREM: { 326 unsigned QuotReg = MRI.createGenericVirtualRegister(Ty); 327 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV) 328 .addDef(QuotReg) 329 .addUse(MI.getOperand(1).getReg()) 330 .addUse(MI.getOperand(2).getReg()); 331 332 unsigned ProdReg = MRI.createGenericVirtualRegister(Ty); 333 MIRBuilder.buildMul(ProdReg, QuotReg, MI.getOperand(2).getReg()); 334 MIRBuilder.buildSub(MI.getOperand(0).getReg(), MI.getOperand(1).getReg(), 335 ProdReg); 336 MI.eraseFromParent(); 337 return Legalized; 338 } 339 } 340 } 341 342 LegalizerHelper::LegalizeResult 343 LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, 344 LLT NarrowTy) { 345 // FIXME: Don't know how to handle secondary types yet. 346 if (TypeIdx != 0) 347 return UnableToLegalize; 348 switch (MI.getOpcode()) { 349 default: 350 return UnableToLegalize; 351 case TargetOpcode::G_ADD: { 352 unsigned NarrowSize = NarrowTy.getSizeInBits(); 353 unsigned DstReg = MI.getOperand(0).getReg(); 354 int NumParts = MRI.getType(DstReg).getSizeInBits() / NarrowSize; 355 356 MIRBuilder.setInstr(MI); 357 358 SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; 359 SmallVector<uint64_t, 2> Indexes; 360 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); 361 extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); 362 363 for (int i = 0; i < NumParts; ++i) { 364 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 365 MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]); 366 DstRegs.push_back(DstReg); 367 Indexes.push_back(i * NarrowSize); 368 } 369 370 MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); 371 MI.eraseFromParent(); 372 return Legalized; 373 } 374 } 375 } 376