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/CodeGen/TargetLowering.h" 21 #include "llvm/CodeGen/TargetSubtargetInfo.h" 22 #include "llvm/Support/Debug.h" 23 #include "llvm/Support/raw_ostream.h" 24 25 26 #define DEBUG_TYPE "legalizer" 27 28 using namespace llvm; 29 using namespace LegalizeActions; 30 31 LegalizerHelper::LegalizerHelper(MachineFunction &MF) 32 : MRI(MF.getRegInfo()), LI(*MF.getSubtarget().getLegalizerInfo()) { 33 MIRBuilder.setMF(MF); 34 } 35 36 LegalizerHelper::LegalizeResult 37 LegalizerHelper::legalizeInstrStep(MachineInstr &MI) { 38 DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs())); 39 40 auto Step = LI.getAction(MI, MRI); 41 switch (Step.Action) { 42 case Legal: 43 DEBUG(dbgs() << ".. Already legal\n"); 44 return AlreadyLegal; 45 case Libcall: 46 DEBUG(dbgs() << ".. Convert to libcall\n"); 47 return libcall(MI); 48 case NarrowScalar: 49 DEBUG(dbgs() << ".. Narrow scalar\n"); 50 return narrowScalar(MI, Step.TypeIdx, Step.NewType); 51 case WidenScalar: 52 DEBUG(dbgs() << ".. Widen scalar\n"); 53 return widenScalar(MI, Step.TypeIdx, Step.NewType); 54 case Lower: 55 DEBUG(dbgs() << ".. Lower\n"); 56 return lower(MI, Step.TypeIdx, Step.NewType); 57 case FewerElements: 58 DEBUG(dbgs() << ".. Reduce number of elements\n"); 59 return fewerElementsVector(MI, Step.TypeIdx, Step.NewType); 60 case Custom: 61 DEBUG(dbgs() << ".. Custom legalization\n"); 62 return LI.legalizeCustom(MI, MRI, MIRBuilder) ? Legalized 63 : UnableToLegalize; 64 default: 65 DEBUG(dbgs() << ".. Unable to legalize\n"); 66 return UnableToLegalize; 67 } 68 } 69 70 void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts, 71 SmallVectorImpl<unsigned> &VRegs) { 72 for (int i = 0; i < NumParts; ++i) 73 VRegs.push_back(MRI.createGenericVirtualRegister(Ty)); 74 MIRBuilder.buildUnmerge(VRegs, Reg); 75 } 76 77 static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) { 78 switch (Opcode) { 79 case TargetOpcode::G_SDIV: 80 assert(Size == 32 && "Unsupported size"); 81 return RTLIB::SDIV_I32; 82 case TargetOpcode::G_UDIV: 83 assert(Size == 32 && "Unsupported size"); 84 return RTLIB::UDIV_I32; 85 case TargetOpcode::G_SREM: 86 assert(Size == 32 && "Unsupported size"); 87 return RTLIB::SREM_I32; 88 case TargetOpcode::G_UREM: 89 assert(Size == 32 && "Unsupported size"); 90 return RTLIB::UREM_I32; 91 case TargetOpcode::G_FADD: 92 assert((Size == 32 || Size == 64) && "Unsupported size"); 93 return Size == 64 ? RTLIB::ADD_F64 : RTLIB::ADD_F32; 94 case TargetOpcode::G_FSUB: 95 assert((Size == 32 || Size == 64) && "Unsupported size"); 96 return Size == 64 ? RTLIB::SUB_F64 : RTLIB::SUB_F32; 97 case TargetOpcode::G_FMUL: 98 assert((Size == 32 || Size == 64) && "Unsupported size"); 99 return Size == 64 ? RTLIB::MUL_F64 : RTLIB::MUL_F32; 100 case TargetOpcode::G_FDIV: 101 assert((Size == 32 || Size == 64) && "Unsupported size"); 102 return Size == 64 ? RTLIB::DIV_F64 : RTLIB::DIV_F32; 103 case TargetOpcode::G_FREM: 104 return Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32; 105 case TargetOpcode::G_FPOW: 106 return Size == 64 ? RTLIB::POW_F64 : RTLIB::POW_F32; 107 case TargetOpcode::G_FMA: 108 assert((Size == 32 || Size == 64) && "Unsupported size"); 109 return Size == 64 ? RTLIB::FMA_F64 : RTLIB::FMA_F32; 110 } 111 llvm_unreachable("Unknown libcall function"); 112 } 113 114 LegalizerHelper::LegalizeResult 115 llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall, 116 const CallLowering::ArgInfo &Result, 117 ArrayRef<CallLowering::ArgInfo> Args) { 118 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering(); 119 auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); 120 const char *Name = TLI.getLibcallName(Libcall); 121 122 MIRBuilder.getMF().getFrameInfo().setHasCalls(true); 123 if (!CLI.lowerCall(MIRBuilder, TLI.getLibcallCallingConv(Libcall), 124 MachineOperand::CreateES(Name), Result, Args)) 125 return LegalizerHelper::UnableToLegalize; 126 127 return LegalizerHelper::Legalized; 128 } 129 130 // Useful for libcalls where all operands have the same type. 131 static LegalizerHelper::LegalizeResult 132 simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, 133 Type *OpType) { 134 auto Libcall = getRTLibDesc(MI.getOpcode(), Size); 135 136 SmallVector<CallLowering::ArgInfo, 3> Args; 137 for (unsigned i = 1; i < MI.getNumOperands(); i++) 138 Args.push_back({MI.getOperand(i).getReg(), OpType}); 139 return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), OpType}, 140 Args); 141 } 142 143 static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType, 144 Type *FromType) { 145 auto ToMVT = MVT::getVT(ToType); 146 auto FromMVT = MVT::getVT(FromType); 147 148 switch (Opcode) { 149 case TargetOpcode::G_FPEXT: 150 return RTLIB::getFPEXT(FromMVT, ToMVT); 151 case TargetOpcode::G_FPTRUNC: 152 return RTLIB::getFPROUND(FromMVT, ToMVT); 153 case TargetOpcode::G_FPTOSI: 154 return RTLIB::getFPTOSINT(FromMVT, ToMVT); 155 case TargetOpcode::G_FPTOUI: 156 return RTLIB::getFPTOUINT(FromMVT, ToMVT); 157 case TargetOpcode::G_SITOFP: 158 return RTLIB::getSINTTOFP(FromMVT, ToMVT); 159 case TargetOpcode::G_UITOFP: 160 return RTLIB::getUINTTOFP(FromMVT, ToMVT); 161 } 162 llvm_unreachable("Unsupported libcall function"); 163 } 164 165 static LegalizerHelper::LegalizeResult 166 conversionLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, Type *ToType, 167 Type *FromType) { 168 RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType); 169 return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), ToType}, 170 {{MI.getOperand(1).getReg(), FromType}}); 171 } 172 173 LegalizerHelper::LegalizeResult 174 LegalizerHelper::libcall(MachineInstr &MI) { 175 LLT LLTy = MRI.getType(MI.getOperand(0).getReg()); 176 unsigned Size = LLTy.getSizeInBits(); 177 auto &Ctx = MIRBuilder.getMF().getFunction().getContext(); 178 179 MIRBuilder.setInstr(MI); 180 181 switch (MI.getOpcode()) { 182 default: 183 return UnableToLegalize; 184 case TargetOpcode::G_SDIV: 185 case TargetOpcode::G_UDIV: 186 case TargetOpcode::G_SREM: 187 case TargetOpcode::G_UREM: { 188 Type *HLTy = Type::getInt32Ty(Ctx); 189 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy); 190 if (Status != Legalized) 191 return Status; 192 break; 193 } 194 case TargetOpcode::G_FADD: 195 case TargetOpcode::G_FSUB: 196 case TargetOpcode::G_FMUL: 197 case TargetOpcode::G_FDIV: 198 case TargetOpcode::G_FMA: 199 case TargetOpcode::G_FPOW: 200 case TargetOpcode::G_FREM: { 201 Type *HLTy = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx); 202 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy); 203 if (Status != Legalized) 204 return Status; 205 break; 206 } 207 case TargetOpcode::G_FPEXT: { 208 // FIXME: Support other floating point types (half, fp128 etc) 209 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); 210 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); 211 if (ToSize != 64 || FromSize != 32) 212 return UnableToLegalize; 213 LegalizeResult Status = conversionLibcall( 214 MI, MIRBuilder, Type::getDoubleTy(Ctx), Type::getFloatTy(Ctx)); 215 if (Status != Legalized) 216 return Status; 217 break; 218 } 219 case TargetOpcode::G_FPTRUNC: { 220 // FIXME: Support other floating point types (half, fp128 etc) 221 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); 222 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); 223 if (ToSize != 32 || FromSize != 64) 224 return UnableToLegalize; 225 LegalizeResult Status = conversionLibcall( 226 MI, MIRBuilder, Type::getFloatTy(Ctx), Type::getDoubleTy(Ctx)); 227 if (Status != Legalized) 228 return Status; 229 break; 230 } 231 case TargetOpcode::G_FPTOSI: 232 case TargetOpcode::G_FPTOUI: { 233 // FIXME: Support other types 234 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); 235 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); 236 if (ToSize != 32 || (FromSize != 32 && FromSize != 64)) 237 return UnableToLegalize; 238 LegalizeResult Status = conversionLibcall( 239 MI, MIRBuilder, Type::getInt32Ty(Ctx), 240 FromSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx)); 241 if (Status != Legalized) 242 return Status; 243 break; 244 } 245 case TargetOpcode::G_SITOFP: 246 case TargetOpcode::G_UITOFP: { 247 // FIXME: Support other types 248 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); 249 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); 250 if (FromSize != 32 || (ToSize != 32 && ToSize != 64)) 251 return UnableToLegalize; 252 LegalizeResult Status = conversionLibcall( 253 MI, MIRBuilder, 254 ToSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx), 255 Type::getInt32Ty(Ctx)); 256 if (Status != Legalized) 257 return Status; 258 break; 259 } 260 } 261 262 MI.eraseFromParent(); 263 return Legalized; 264 } 265 266 LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, 267 unsigned TypeIdx, 268 LLT NarrowTy) { 269 // FIXME: Don't know how to handle secondary types yet. 270 if (TypeIdx != 0 && MI.getOpcode() != TargetOpcode::G_EXTRACT) 271 return UnableToLegalize; 272 273 MIRBuilder.setInstr(MI); 274 275 int64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); 276 int64_t NarrowSize = NarrowTy.getSizeInBits(); 277 278 switch (MI.getOpcode()) { 279 default: 280 return UnableToLegalize; 281 case TargetOpcode::G_IMPLICIT_DEF: { 282 // FIXME: add support for when SizeOp0 isn't an exact multiple of 283 // NarrowSize. 284 if (SizeOp0 % NarrowSize != 0) 285 return UnableToLegalize; 286 int NumParts = SizeOp0 / NarrowSize; 287 288 SmallVector<unsigned, 2> DstRegs; 289 for (int i = 0; i < NumParts; ++i) 290 DstRegs.push_back( 291 MIRBuilder.buildUndef(NarrowTy)->getOperand(0).getReg()); 292 MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs); 293 MI.eraseFromParent(); 294 return Legalized; 295 } 296 case TargetOpcode::G_ADD: { 297 // FIXME: add support for when SizeOp0 isn't an exact multiple of 298 // NarrowSize. 299 if (SizeOp0 % NarrowSize != 0) 300 return UnableToLegalize; 301 // Expand in terms of carry-setting/consuming G_ADDE instructions. 302 int NumParts = SizeOp0 / NarrowTy.getSizeInBits(); 303 304 SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; 305 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); 306 extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); 307 308 unsigned CarryIn = MRI.createGenericVirtualRegister(LLT::scalar(1)); 309 MIRBuilder.buildConstant(CarryIn, 0); 310 311 for (int i = 0; i < NumParts; ++i) { 312 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 313 unsigned CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1)); 314 315 MIRBuilder.buildUAdde(DstReg, CarryOut, Src1Regs[i], 316 Src2Regs[i], CarryIn); 317 318 DstRegs.push_back(DstReg); 319 CarryIn = CarryOut; 320 } 321 unsigned DstReg = MI.getOperand(0).getReg(); 322 MIRBuilder.buildMerge(DstReg, DstRegs); 323 MI.eraseFromParent(); 324 return Legalized; 325 } 326 case TargetOpcode::G_EXTRACT: { 327 if (TypeIdx != 1) 328 return UnableToLegalize; 329 330 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); 331 // FIXME: add support for when SizeOp1 isn't an exact multiple of 332 // NarrowSize. 333 if (SizeOp1 % NarrowSize != 0) 334 return UnableToLegalize; 335 int NumParts = SizeOp1 / NarrowSize; 336 337 SmallVector<unsigned, 2> SrcRegs, DstRegs; 338 SmallVector<uint64_t, 2> Indexes; 339 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs); 340 341 unsigned OpReg = MI.getOperand(0).getReg(); 342 int64_t OpStart = MI.getOperand(2).getImm(); 343 int64_t OpSize = MRI.getType(OpReg).getSizeInBits(); 344 for (int i = 0; i < NumParts; ++i) { 345 unsigned SrcStart = i * NarrowSize; 346 347 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) { 348 // No part of the extract uses this subregister, ignore it. 349 continue; 350 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) { 351 // The entire subregister is extracted, forward the value. 352 DstRegs.push_back(SrcRegs[i]); 353 continue; 354 } 355 356 // OpSegStart is where this destination segment would start in OpReg if it 357 // extended infinitely in both directions. 358 int64_t ExtractOffset, SegSize; 359 if (OpStart < SrcStart) { 360 ExtractOffset = 0; 361 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart); 362 } else { 363 ExtractOffset = OpStart - SrcStart; 364 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize); 365 } 366 367 unsigned SegReg = SrcRegs[i]; 368 if (ExtractOffset != 0 || SegSize != NarrowSize) { 369 // A genuine extract is needed. 370 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize)); 371 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset); 372 } 373 374 DstRegs.push_back(SegReg); 375 } 376 377 MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs); 378 MI.eraseFromParent(); 379 return Legalized; 380 } 381 case TargetOpcode::G_INSERT: { 382 // FIXME: add support for when SizeOp0 isn't an exact multiple of 383 // NarrowSize. 384 if (SizeOp0 % NarrowSize != 0) 385 return UnableToLegalize; 386 387 int NumParts = SizeOp0 / NarrowSize; 388 389 SmallVector<unsigned, 2> SrcRegs, DstRegs; 390 SmallVector<uint64_t, 2> Indexes; 391 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs); 392 393 unsigned OpReg = MI.getOperand(2).getReg(); 394 int64_t OpStart = MI.getOperand(3).getImm(); 395 int64_t OpSize = MRI.getType(OpReg).getSizeInBits(); 396 for (int i = 0; i < NumParts; ++i) { 397 unsigned DstStart = i * NarrowSize; 398 399 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) { 400 // No part of the insert affects this subregister, forward the original. 401 DstRegs.push_back(SrcRegs[i]); 402 continue; 403 } else if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) { 404 // The entire subregister is defined by this insert, forward the new 405 // value. 406 DstRegs.push_back(OpReg); 407 continue; 408 } 409 410 // OpSegStart is where this destination segment would start in OpReg if it 411 // extended infinitely in both directions. 412 int64_t ExtractOffset, InsertOffset, SegSize; 413 if (OpStart < DstStart) { 414 InsertOffset = 0; 415 ExtractOffset = DstStart - OpStart; 416 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart); 417 } else { 418 InsertOffset = OpStart - DstStart; 419 ExtractOffset = 0; 420 SegSize = 421 std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart); 422 } 423 424 unsigned SegReg = OpReg; 425 if (ExtractOffset != 0 || SegSize != OpSize) { 426 // A genuine extract is needed. 427 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize)); 428 MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset); 429 } 430 431 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 432 MIRBuilder.buildInsert(DstReg, SrcRegs[i], SegReg, InsertOffset); 433 DstRegs.push_back(DstReg); 434 } 435 436 assert(DstRegs.size() == (unsigned)NumParts && "not all parts covered"); 437 MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs); 438 MI.eraseFromParent(); 439 return Legalized; 440 } 441 case TargetOpcode::G_LOAD: { 442 // FIXME: add support for when SizeOp0 isn't an exact multiple of 443 // NarrowSize. 444 if (SizeOp0 % NarrowSize != 0) 445 return UnableToLegalize; 446 int NumParts = SizeOp0 / NarrowSize; 447 LLT OffsetTy = LLT::scalar( 448 MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits()); 449 450 SmallVector<unsigned, 2> DstRegs; 451 for (int i = 0; i < NumParts; ++i) { 452 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 453 unsigned SrcReg = 0; 454 unsigned Adjustment = i * NarrowSize / 8; 455 456 MIRBuilder.materializeGEP(SrcReg, MI.getOperand(1).getReg(), OffsetTy, 457 Adjustment); 458 459 // TODO: This is conservatively correct, but we probably want to split the 460 // memory operands in the future. 461 MIRBuilder.buildLoad(DstReg, SrcReg, **MI.memoperands_begin()); 462 463 DstRegs.push_back(DstReg); 464 } 465 unsigned DstReg = MI.getOperand(0).getReg(); 466 MIRBuilder.buildMerge(DstReg, DstRegs); 467 MI.eraseFromParent(); 468 return Legalized; 469 } 470 case TargetOpcode::G_STORE: { 471 // FIXME: add support for when SizeOp0 isn't an exact multiple of 472 // NarrowSize. 473 if (SizeOp0 % NarrowSize != 0) 474 return UnableToLegalize; 475 int NumParts = SizeOp0 / NarrowSize; 476 LLT OffsetTy = LLT::scalar( 477 MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits()); 478 479 SmallVector<unsigned, 2> SrcRegs; 480 extractParts(MI.getOperand(0).getReg(), NarrowTy, NumParts, SrcRegs); 481 482 for (int i = 0; i < NumParts; ++i) { 483 unsigned DstReg = 0; 484 unsigned Adjustment = i * NarrowSize / 8; 485 486 MIRBuilder.materializeGEP(DstReg, MI.getOperand(1).getReg(), OffsetTy, 487 Adjustment); 488 489 // TODO: This is conservatively correct, but we probably want to split the 490 // memory operands in the future. 491 MIRBuilder.buildStore(SrcRegs[i], DstReg, **MI.memoperands_begin()); 492 } 493 MI.eraseFromParent(); 494 return Legalized; 495 } 496 case TargetOpcode::G_CONSTANT: { 497 // FIXME: add support for when SizeOp0 isn't an exact multiple of 498 // NarrowSize. 499 if (SizeOp0 % NarrowSize != 0) 500 return UnableToLegalize; 501 int NumParts = SizeOp0 / NarrowSize; 502 const APInt &Cst = MI.getOperand(1).getCImm()->getValue(); 503 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); 504 505 SmallVector<unsigned, 2> DstRegs; 506 for (int i = 0; i < NumParts; ++i) { 507 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 508 ConstantInt *CI = 509 ConstantInt::get(Ctx, Cst.lshr(NarrowSize * i).trunc(NarrowSize)); 510 MIRBuilder.buildConstant(DstReg, *CI); 511 DstRegs.push_back(DstReg); 512 } 513 unsigned DstReg = MI.getOperand(0).getReg(); 514 MIRBuilder.buildMerge(DstReg, DstRegs); 515 MI.eraseFromParent(); 516 return Legalized; 517 } 518 case TargetOpcode::G_OR: { 519 // Legalize bitwise operation: 520 // A = BinOp<Ty> B, C 521 // into: 522 // B1, ..., BN = G_UNMERGE_VALUES B 523 // C1, ..., CN = G_UNMERGE_VALUES C 524 // A1 = BinOp<Ty/N> B1, C2 525 // ... 526 // AN = BinOp<Ty/N> BN, CN 527 // A = G_MERGE_VALUES A1, ..., AN 528 529 // FIXME: add support for when SizeOp0 isn't an exact multiple of 530 // NarrowSize. 531 if (SizeOp0 % NarrowSize != 0) 532 return UnableToLegalize; 533 int NumParts = SizeOp0 / NarrowSize; 534 535 // List the registers where the destination will be scattered. 536 SmallVector<unsigned, 2> DstRegs; 537 // List the registers where the first argument will be split. 538 SmallVector<unsigned, 2> SrcsReg1; 539 // List the registers where the second argument will be split. 540 SmallVector<unsigned, 2> SrcsReg2; 541 // Create all the temporary registers. 542 for (int i = 0; i < NumParts; ++i) { 543 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 544 unsigned SrcReg1 = MRI.createGenericVirtualRegister(NarrowTy); 545 unsigned SrcReg2 = MRI.createGenericVirtualRegister(NarrowTy); 546 547 DstRegs.push_back(DstReg); 548 SrcsReg1.push_back(SrcReg1); 549 SrcsReg2.push_back(SrcReg2); 550 } 551 // Explode the big arguments into smaller chunks. 552 MIRBuilder.buildUnmerge(SrcsReg1, MI.getOperand(1).getReg()); 553 MIRBuilder.buildUnmerge(SrcsReg2, MI.getOperand(2).getReg()); 554 555 // Do the operation on each small part. 556 for (int i = 0; i < NumParts; ++i) 557 MIRBuilder.buildOr(DstRegs[i], SrcsReg1[i], SrcsReg2[i]); 558 559 // Gather the destination registers into the final destination. 560 unsigned DstReg = MI.getOperand(0).getReg(); 561 MIRBuilder.buildMerge(DstReg, DstRegs); 562 MI.eraseFromParent(); 563 return Legalized; 564 } 565 } 566 } 567 568 LegalizerHelper::LegalizeResult 569 LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { 570 MIRBuilder.setInstr(MI); 571 572 switch (MI.getOpcode()) { 573 default: 574 return UnableToLegalize; 575 case TargetOpcode::G_ADD: 576 case TargetOpcode::G_AND: 577 case TargetOpcode::G_MUL: 578 case TargetOpcode::G_OR: 579 case TargetOpcode::G_XOR: 580 case TargetOpcode::G_SUB: 581 case TargetOpcode::G_SHL: { 582 // Perform operation at larger width (any extension is fine here, high bits 583 // don't affect the result) and then truncate the result back to the 584 // original type. 585 unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy); 586 unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy); 587 MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg()); 588 MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg()); 589 590 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 591 MIRBuilder.buildInstr(MI.getOpcode()) 592 .addDef(DstExt) 593 .addUse(Src1Ext) 594 .addUse(Src2Ext); 595 596 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 597 MI.eraseFromParent(); 598 return Legalized; 599 } 600 case TargetOpcode::G_SDIV: 601 case TargetOpcode::G_UDIV: 602 case TargetOpcode::G_SREM: 603 case TargetOpcode::G_UREM: 604 case TargetOpcode::G_ASHR: 605 case TargetOpcode::G_LSHR: { 606 unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV || 607 MI.getOpcode() == TargetOpcode::G_SREM || 608 MI.getOpcode() == TargetOpcode::G_ASHR 609 ? TargetOpcode::G_SEXT 610 : TargetOpcode::G_ZEXT; 611 612 unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy); 613 MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse( 614 MI.getOperand(1).getReg()); 615 616 unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy); 617 MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse( 618 MI.getOperand(2).getReg()); 619 620 unsigned ResExt = MRI.createGenericVirtualRegister(WideTy); 621 MIRBuilder.buildInstr(MI.getOpcode()) 622 .addDef(ResExt) 623 .addUse(LHSExt) 624 .addUse(RHSExt); 625 626 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt); 627 MI.eraseFromParent(); 628 return Legalized; 629 } 630 case TargetOpcode::G_SELECT: { 631 if (TypeIdx != 0) 632 return UnableToLegalize; 633 634 // Perform operation at larger width (any extension is fine here, high bits 635 // don't affect the result) and then truncate the result back to the 636 // original type. 637 unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy); 638 unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy); 639 MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(2).getReg()); 640 MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(3).getReg()); 641 642 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 643 MIRBuilder.buildInstr(TargetOpcode::G_SELECT) 644 .addDef(DstExt) 645 .addReg(MI.getOperand(1).getReg()) 646 .addUse(Src1Ext) 647 .addUse(Src2Ext); 648 649 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 650 MI.eraseFromParent(); 651 return Legalized; 652 } 653 case TargetOpcode::G_FPTOSI: 654 case TargetOpcode::G_FPTOUI: { 655 if (TypeIdx != 0) 656 return UnableToLegalize; 657 658 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 659 MIRBuilder.buildInstr(MI.getOpcode()) 660 .addDef(DstExt) 661 .addUse(MI.getOperand(1).getReg()); 662 663 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 664 MI.eraseFromParent(); 665 return Legalized; 666 } 667 case TargetOpcode::G_SITOFP: 668 case TargetOpcode::G_UITOFP: { 669 if (TypeIdx != 1) 670 return UnableToLegalize; 671 672 unsigned Src = MI.getOperand(1).getReg(); 673 unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); 674 675 if (MI.getOpcode() == TargetOpcode::G_SITOFP) { 676 MIRBuilder.buildSExt(SrcExt, Src); 677 } else { 678 assert(MI.getOpcode() == TargetOpcode::G_UITOFP && "Unexpected conv op"); 679 MIRBuilder.buildZExt(SrcExt, Src); 680 } 681 682 MIRBuilder.buildInstr(MI.getOpcode()) 683 .addDef(MI.getOperand(0).getReg()) 684 .addUse(SrcExt); 685 686 MI.eraseFromParent(); 687 return Legalized; 688 } 689 case TargetOpcode::G_INSERT: { 690 if (TypeIdx != 0) 691 return UnableToLegalize; 692 693 unsigned Src = MI.getOperand(1).getReg(); 694 unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); 695 MIRBuilder.buildAnyExt(SrcExt, Src); 696 697 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 698 auto MIB = MIRBuilder.buildInsert(DstExt, SrcExt, MI.getOperand(2).getReg(), 699 MI.getOperand(3).getImm()); 700 for (unsigned OpNum = 4; OpNum < MI.getNumOperands(); OpNum += 2) { 701 MIB.addReg(MI.getOperand(OpNum).getReg()); 702 MIB.addImm(MI.getOperand(OpNum + 1).getImm()); 703 } 704 705 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 706 MI.eraseFromParent(); 707 return Legalized; 708 } 709 case TargetOpcode::G_LOAD: { 710 // For some types like i24, we might try to widen to i32. To properly handle 711 // this we should be using a dedicated extending load, until then avoid 712 // trying to legalize. 713 if (alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) != 714 WideTy.getSizeInBits()) 715 return UnableToLegalize; 716 717 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 718 MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(), 719 **MI.memoperands_begin()); 720 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 721 MI.eraseFromParent(); 722 return Legalized; 723 } 724 case TargetOpcode::G_STORE: { 725 if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(1) || 726 WideTy != LLT::scalar(8)) 727 return UnableToLegalize; 728 729 auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); 730 auto Content = TLI.getBooleanContents(false, false); 731 732 unsigned ExtOp = TargetOpcode::G_ANYEXT; 733 if (Content == TargetLoweringBase::ZeroOrOneBooleanContent) 734 ExtOp = TargetOpcode::G_ZEXT; 735 else if (Content == TargetLoweringBase::ZeroOrNegativeOneBooleanContent) 736 ExtOp = TargetOpcode::G_SEXT; 737 else 738 ExtOp = TargetOpcode::G_ANYEXT; 739 740 unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); 741 MIRBuilder.buildInstr(ExtOp).addDef(SrcExt).addUse( 742 MI.getOperand(0).getReg()); 743 MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(), 744 **MI.memoperands_begin()); 745 MI.eraseFromParent(); 746 return Legalized; 747 } 748 case TargetOpcode::G_CONSTANT: { 749 unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); 750 MIRBuilder.buildConstant(DstExt, *MI.getOperand(1).getCImm()); 751 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); 752 MI.eraseFromParent(); 753 return Legalized; 754 } 755 case TargetOpcode::G_FCONSTANT: { 756 const ConstantFP *CFP = MI.getOperand(1).getFPImm(); 757 APFloat Val = CFP->getValueAPF(); 758 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); 759 auto LLT2Sem = [](LLT Ty) { 760 switch (Ty.getSizeInBits()) { 761 case 32: 762 return &APFloat::IEEEsingle(); 763 break; 764 case 64: 765 return &APFloat::IEEEdouble(); 766 break; 767 default: 768 llvm_unreachable("Unhandled fp widen type"); 769 } 770 }; 771 bool LosesInfo; 772 Val.convert(*LLT2Sem(WideTy), APFloat::rmTowardZero, &LosesInfo); 773 auto Cst = MIRBuilder.buildFConstant(WideTy, *ConstantFP::get(Ctx, Val)); 774 MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), Cst); 775 MI.eraseFromParent(); 776 return Legalized; 777 } 778 case TargetOpcode::G_BRCOND: { 779 unsigned TstExt = MRI.createGenericVirtualRegister(WideTy); 780 MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg()); 781 MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB()); 782 MI.eraseFromParent(); 783 return Legalized; 784 } 785 case TargetOpcode::G_FCMP: { 786 unsigned Op0Ext, Op1Ext, DstReg; 787 unsigned Cmp1 = MI.getOperand(2).getReg(); 788 unsigned Cmp2 = MI.getOperand(3).getReg(); 789 if (TypeIdx == 0) { 790 Op0Ext = Cmp1; 791 Op1Ext = Cmp2; 792 DstReg = MRI.createGenericVirtualRegister(WideTy); 793 } else { 794 Op0Ext = MRI.createGenericVirtualRegister(WideTy); 795 Op1Ext = MRI.createGenericVirtualRegister(WideTy); 796 DstReg = MI.getOperand(0).getReg(); 797 MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op0Ext, Cmp1); 798 MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op1Ext, Cmp2); 799 } 800 MIRBuilder.buildFCmp( 801 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()), 802 DstReg, Op0Ext, Op1Ext); 803 if (TypeIdx == 0) 804 MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(), 805 DstReg); 806 MI.eraseFromParent(); 807 return Legalized; 808 } 809 case TargetOpcode::G_ICMP: { 810 bool IsSigned = CmpInst::isSigned( 811 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate())); 812 unsigned Cmp1 = MI.getOperand(2).getReg(); 813 unsigned Cmp2 = MI.getOperand(3).getReg(); 814 unsigned Op0Ext, Op1Ext, DstReg; 815 if (TypeIdx == 0) { 816 Op0Ext = Cmp1; 817 Op1Ext = Cmp2; 818 DstReg = MRI.createGenericVirtualRegister(WideTy); 819 } else { 820 Op0Ext = MRI.createGenericVirtualRegister(WideTy); 821 Op1Ext = MRI.createGenericVirtualRegister(WideTy); 822 DstReg = MI.getOperand(0).getReg(); 823 if (IsSigned) { 824 MIRBuilder.buildSExt(Op0Ext, Cmp1); 825 MIRBuilder.buildSExt(Op1Ext, Cmp2); 826 } else { 827 MIRBuilder.buildZExt(Op0Ext, Cmp1); 828 MIRBuilder.buildZExt(Op1Ext, Cmp2); 829 } 830 } 831 MIRBuilder.buildICmp( 832 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()), 833 DstReg, Op0Ext, Op1Ext); 834 if (TypeIdx == 0) 835 MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(), 836 DstReg); 837 MI.eraseFromParent(); 838 return Legalized; 839 } 840 case TargetOpcode::G_GEP: { 841 assert(TypeIdx == 1 && "unable to legalize pointer of GEP"); 842 unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy); 843 MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg()); 844 MI.getOperand(2).setReg(OffsetExt); 845 return Legalized; 846 } 847 case TargetOpcode::G_PHI: { 848 assert(TypeIdx == 0 && "Expecting only Idx 0"); 849 auto getExtendedReg = [&](unsigned Reg, MachineBasicBlock &MBB) { 850 auto FirstTermIt = MBB.getFirstTerminator(); 851 MIRBuilder.setInsertPt(MBB, FirstTermIt); 852 MachineInstr *DefMI = MRI.getVRegDef(Reg); 853 MachineInstrBuilder MIB; 854 if (DefMI->getOpcode() == TargetOpcode::G_TRUNC) 855 MIB = MIRBuilder.buildAnyExtOrTrunc(WideTy, 856 DefMI->getOperand(1).getReg()); 857 else 858 MIB = MIRBuilder.buildAnyExt(WideTy, Reg); 859 return MIB->getOperand(0).getReg(); 860 }; 861 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_PHI, WideTy); 862 for (auto OpIt = MI.operands_begin() + 1, OpE = MI.operands_end(); 863 OpIt != OpE;) { 864 unsigned Reg = OpIt++->getReg(); 865 MachineBasicBlock *OpMBB = OpIt++->getMBB(); 866 MIB.addReg(getExtendedReg(Reg, *OpMBB)); 867 MIB.addMBB(OpMBB); 868 } 869 auto *MBB = MI.getParent(); 870 MIRBuilder.setInsertPt(*MBB, MBB->getFirstNonPHI()); 871 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), 872 MIB->getOperand(0).getReg()); 873 MI.eraseFromParent(); 874 return Legalized; 875 } 876 } 877 } 878 879 LegalizerHelper::LegalizeResult 880 LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { 881 using namespace TargetOpcode; 882 MIRBuilder.setInstr(MI); 883 884 switch(MI.getOpcode()) { 885 default: 886 return UnableToLegalize; 887 case TargetOpcode::G_SREM: 888 case TargetOpcode::G_UREM: { 889 unsigned QuotReg = MRI.createGenericVirtualRegister(Ty); 890 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV) 891 .addDef(QuotReg) 892 .addUse(MI.getOperand(1).getReg()) 893 .addUse(MI.getOperand(2).getReg()); 894 895 unsigned ProdReg = MRI.createGenericVirtualRegister(Ty); 896 MIRBuilder.buildMul(ProdReg, QuotReg, MI.getOperand(2).getReg()); 897 MIRBuilder.buildSub(MI.getOperand(0).getReg(), MI.getOperand(1).getReg(), 898 ProdReg); 899 MI.eraseFromParent(); 900 return Legalized; 901 } 902 case TargetOpcode::G_SMULO: 903 case TargetOpcode::G_UMULO: { 904 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the 905 // result. 906 unsigned Res = MI.getOperand(0).getReg(); 907 unsigned Overflow = MI.getOperand(1).getReg(); 908 unsigned LHS = MI.getOperand(2).getReg(); 909 unsigned RHS = MI.getOperand(3).getReg(); 910 911 MIRBuilder.buildMul(Res, LHS, RHS); 912 913 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO 914 ? TargetOpcode::G_SMULH 915 : TargetOpcode::G_UMULH; 916 917 unsigned HiPart = MRI.createGenericVirtualRegister(Ty); 918 MIRBuilder.buildInstr(Opcode) 919 .addDef(HiPart) 920 .addUse(LHS) 921 .addUse(RHS); 922 923 unsigned Zero = MRI.createGenericVirtualRegister(Ty); 924 MIRBuilder.buildConstant(Zero, 0); 925 926 // For *signed* multiply, overflow is detected by checking: 927 // (hi != (lo >> bitwidth-1)) 928 if (Opcode == TargetOpcode::G_SMULH) { 929 unsigned Shifted = MRI.createGenericVirtualRegister(Ty); 930 unsigned ShiftAmt = MRI.createGenericVirtualRegister(Ty); 931 MIRBuilder.buildConstant(ShiftAmt, Ty.getSizeInBits() - 1); 932 MIRBuilder.buildInstr(TargetOpcode::G_ASHR) 933 .addDef(Shifted) 934 .addUse(Res) 935 .addUse(ShiftAmt); 936 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted); 937 } else { 938 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero); 939 } 940 MI.eraseFromParent(); 941 return Legalized; 942 } 943 case TargetOpcode::G_FNEG: { 944 // TODO: Handle vector types once we are able to 945 // represent them. 946 if (Ty.isVector()) 947 return UnableToLegalize; 948 unsigned Res = MI.getOperand(0).getReg(); 949 Type *ZeroTy; 950 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); 951 switch (Ty.getSizeInBits()) { 952 case 16: 953 ZeroTy = Type::getHalfTy(Ctx); 954 break; 955 case 32: 956 ZeroTy = Type::getFloatTy(Ctx); 957 break; 958 case 64: 959 ZeroTy = Type::getDoubleTy(Ctx); 960 break; 961 case 128: 962 ZeroTy = Type::getFP128Ty(Ctx); 963 break; 964 default: 965 llvm_unreachable("unexpected floating-point type"); 966 } 967 ConstantFP &ZeroForNegation = 968 *cast<ConstantFP>(ConstantFP::getZeroValueForNegation(ZeroTy)); 969 auto Zero = MIRBuilder.buildFConstant(Ty, ZeroForNegation); 970 MIRBuilder.buildInstr(TargetOpcode::G_FSUB) 971 .addDef(Res) 972 .addUse(Zero->getOperand(0).getReg()) 973 .addUse(MI.getOperand(1).getReg()); 974 MI.eraseFromParent(); 975 return Legalized; 976 } 977 case TargetOpcode::G_FSUB: { 978 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)). 979 // First, check if G_FNEG is marked as Lower. If so, we may 980 // end up with an infinite loop as G_FSUB is used to legalize G_FNEG. 981 if (LI.getAction({G_FNEG, {Ty}}).Action == Lower) 982 return UnableToLegalize; 983 unsigned Res = MI.getOperand(0).getReg(); 984 unsigned LHS = MI.getOperand(1).getReg(); 985 unsigned RHS = MI.getOperand(2).getReg(); 986 unsigned Neg = MRI.createGenericVirtualRegister(Ty); 987 MIRBuilder.buildInstr(TargetOpcode::G_FNEG).addDef(Neg).addUse(RHS); 988 MIRBuilder.buildInstr(TargetOpcode::G_FADD) 989 .addDef(Res) 990 .addUse(LHS) 991 .addUse(Neg); 992 MI.eraseFromParent(); 993 return Legalized; 994 } 995 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: { 996 unsigned OldValRes = MI.getOperand(0).getReg(); 997 unsigned SuccessRes = MI.getOperand(1).getReg(); 998 unsigned Addr = MI.getOperand(2).getReg(); 999 unsigned CmpVal = MI.getOperand(3).getReg(); 1000 unsigned NewVal = MI.getOperand(4).getReg(); 1001 MIRBuilder.buildAtomicCmpXchg(OldValRes, Addr, CmpVal, NewVal, 1002 **MI.memoperands_begin()); 1003 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, OldValRes, CmpVal); 1004 MI.eraseFromParent(); 1005 return Legalized; 1006 } 1007 } 1008 } 1009 1010 LegalizerHelper::LegalizeResult 1011 LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, 1012 LLT NarrowTy) { 1013 // FIXME: Don't know how to handle secondary types yet. 1014 if (TypeIdx != 0) 1015 return UnableToLegalize; 1016 switch (MI.getOpcode()) { 1017 default: 1018 return UnableToLegalize; 1019 case TargetOpcode::G_ADD: { 1020 unsigned NarrowSize = NarrowTy.getSizeInBits(); 1021 unsigned DstReg = MI.getOperand(0).getReg(); 1022 unsigned Size = MRI.getType(DstReg).getSizeInBits(); 1023 int NumParts = Size / NarrowSize; 1024 // FIXME: Don't know how to handle the situation where the small vectors 1025 // aren't all the same size yet. 1026 if (Size % NarrowSize != 0) 1027 return UnableToLegalize; 1028 1029 MIRBuilder.setInstr(MI); 1030 1031 SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; 1032 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); 1033 extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); 1034 1035 for (int i = 0; i < NumParts; ++i) { 1036 unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); 1037 MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]); 1038 DstRegs.push_back(DstReg); 1039 } 1040 1041 MIRBuilder.buildMerge(DstReg, DstRegs); 1042 MI.eraseFromParent(); 1043 return Legalized; 1044 } 1045 } 1046 } 1047