File indexing completed on 2026-05-10 08:43:24
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZATIONARTIFACTCOMBINER_H
0015 #define LLVM_CODEGEN_GLOBALISEL_LEGALIZATIONARTIFACTCOMBINER_H
0016
0017 #include "llvm/ADT/SmallBitVector.h"
0018 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
0019 #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
0020 #include "llvm/CodeGen/GlobalISel/Legalizer.h"
0021 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
0022 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
0023 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
0024 #include "llvm/CodeGen/GlobalISel/Utils.h"
0025 #include "llvm/CodeGen/MachineRegisterInfo.h"
0026 #include "llvm/CodeGen/Register.h"
0027 #include "llvm/CodeGen/TargetOpcodes.h"
0028 #include "llvm/IR/Constants.h"
0029 #include "llvm/IR/DebugInfoMetadata.h"
0030 #include "llvm/Support/Debug.h"
0031
0032 #define DEBUG_TYPE "legalizer"
0033
0034 namespace llvm {
0035 class LegalizationArtifactCombiner {
0036 MachineIRBuilder &Builder;
0037 MachineRegisterInfo &MRI;
0038 const LegalizerInfo &LI;
0039 GISelKnownBits *KB;
0040
0041 static bool isArtifactCast(unsigned Opc) {
0042 switch (Opc) {
0043 case TargetOpcode::G_TRUNC:
0044 case TargetOpcode::G_SEXT:
0045 case TargetOpcode::G_ZEXT:
0046 case TargetOpcode::G_ANYEXT:
0047 return true;
0048 default:
0049 return false;
0050 }
0051 }
0052
0053 public:
0054 LegalizationArtifactCombiner(MachineIRBuilder &B, MachineRegisterInfo &MRI,
0055 const LegalizerInfo &LI,
0056 GISelKnownBits *KB = nullptr)
0057 : Builder(B), MRI(MRI), LI(LI), KB(KB) {}
0058
0059 bool tryCombineAnyExt(MachineInstr &MI,
0060 SmallVectorImpl<MachineInstr *> &DeadInsts,
0061 SmallVectorImpl<Register> &UpdatedDefs,
0062 GISelObserverWrapper &Observer) {
0063 using namespace llvm::MIPatternMatch;
0064 assert(MI.getOpcode() == TargetOpcode::G_ANYEXT);
0065
0066 Builder.setInstrAndDebugLoc(MI);
0067 Register DstReg = MI.getOperand(0).getReg();
0068 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
0069
0070
0071 Register TruncSrc;
0072 if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc)))) {
0073 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI);
0074 if (MRI.getType(DstReg) == MRI.getType(TruncSrc))
0075 replaceRegOrBuildCopy(DstReg, TruncSrc, MRI, Builder, UpdatedDefs,
0076 Observer);
0077 else
0078 Builder.buildAnyExtOrTrunc(DstReg, TruncSrc);
0079 UpdatedDefs.push_back(DstReg);
0080 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
0081 return true;
0082 }
0083
0084
0085 Register ExtSrc;
0086 MachineInstr *ExtMI;
0087 if (mi_match(SrcReg, MRI,
0088 m_all_of(m_MInstr(ExtMI), m_any_of(m_GAnyExt(m_Reg(ExtSrc)),
0089 m_GSExt(m_Reg(ExtSrc)),
0090 m_GZExt(m_Reg(ExtSrc)))))) {
0091 Builder.buildInstr(ExtMI->getOpcode(), {DstReg}, {ExtSrc});
0092 UpdatedDefs.push_back(DstReg);
0093 markInstAndDefDead(MI, *ExtMI, DeadInsts);
0094 return true;
0095 }
0096
0097
0098 auto *SrcMI = MRI.getVRegDef(SrcReg);
0099 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
0100 const LLT DstTy = MRI.getType(DstReg);
0101 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
0102 auto &CstVal = SrcMI->getOperand(1);
0103 auto *MergedLocation = DILocation::getMergedLocation(
0104 MI.getDebugLoc().get(), SrcMI->getDebugLoc().get());
0105
0106
0107 Builder.setDebugLoc(MergedLocation);
0108 Builder.buildConstant(
0109 DstReg, CstVal.getCImm()->getValue().sext(DstTy.getSizeInBits()));
0110 UpdatedDefs.push_back(DstReg);
0111 markInstAndDefDead(MI, *SrcMI, DeadInsts);
0112 return true;
0113 }
0114 }
0115 return tryFoldImplicitDef(MI, DeadInsts, UpdatedDefs, Observer);
0116 }
0117
0118 bool tryCombineZExt(MachineInstr &MI,
0119 SmallVectorImpl<MachineInstr *> &DeadInsts,
0120 SmallVectorImpl<Register> &UpdatedDefs,
0121 GISelObserverWrapper &Observer) {
0122 using namespace llvm::MIPatternMatch;
0123 assert(MI.getOpcode() == TargetOpcode::G_ZEXT);
0124
0125 Builder.setInstrAndDebugLoc(MI);
0126 Register DstReg = MI.getOperand(0).getReg();
0127 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
0128
0129
0130
0131 Register TruncSrc;
0132 Register SextSrc;
0133 if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc))) ||
0134 mi_match(SrcReg, MRI, m_GSExt(m_Reg(SextSrc)))) {
0135 LLT DstTy = MRI.getType(DstReg);
0136 if (isInstUnsupported({TargetOpcode::G_AND, {DstTy}}) ||
0137 isConstantUnsupported(DstTy))
0138 return false;
0139 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI);
0140 LLT SrcTy = MRI.getType(SrcReg);
0141 APInt MaskVal = APInt::getAllOnes(SrcTy.getScalarSizeInBits());
0142 if (SextSrc && (DstTy != MRI.getType(SextSrc)))
0143 SextSrc = Builder.buildSExtOrTrunc(DstTy, SextSrc).getReg(0);
0144 if (TruncSrc && (DstTy != MRI.getType(TruncSrc)))
0145 TruncSrc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrc).getReg(0);
0146 APInt ExtMaskVal = MaskVal.zext(DstTy.getScalarSizeInBits());
0147 Register AndSrc = SextSrc ? SextSrc : TruncSrc;
0148
0149
0150
0151
0152
0153
0154 if (KB && (KB->getKnownZeroes(AndSrc) | ExtMaskVal).isAllOnes()) {
0155 replaceRegOrBuildCopy(DstReg, AndSrc, MRI, Builder, UpdatedDefs,
0156 Observer);
0157 } else {
0158 auto Mask = Builder.buildConstant(DstTy, ExtMaskVal);
0159 Builder.buildAnd(DstReg, AndSrc, Mask);
0160 }
0161 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
0162 return true;
0163 }
0164
0165
0166 Register ZextSrc;
0167 if (mi_match(SrcReg, MRI, m_GZExt(m_Reg(ZextSrc)))) {
0168 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI);
0169 Observer.changingInstr(MI);
0170 MI.getOperand(1).setReg(ZextSrc);
0171 Observer.changedInstr(MI);
0172 UpdatedDefs.push_back(DstReg);
0173 markDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
0174 return true;
0175 }
0176
0177
0178 auto *SrcMI = MRI.getVRegDef(SrcReg);
0179 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
0180 const LLT DstTy = MRI.getType(DstReg);
0181 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
0182 auto &CstVal = SrcMI->getOperand(1);
0183 Builder.buildConstant(
0184 DstReg, CstVal.getCImm()->getValue().zext(DstTy.getSizeInBits()));
0185 UpdatedDefs.push_back(DstReg);
0186 markInstAndDefDead(MI, *SrcMI, DeadInsts);
0187 return true;
0188 }
0189 }
0190 return tryFoldImplicitDef(MI, DeadInsts, UpdatedDefs, Observer);
0191 }
0192
0193 bool tryCombineSExt(MachineInstr &MI,
0194 SmallVectorImpl<MachineInstr *> &DeadInsts,
0195 SmallVectorImpl<Register> &UpdatedDefs,
0196 GISelObserverWrapper &Observer) {
0197 using namespace llvm::MIPatternMatch;
0198 assert(MI.getOpcode() == TargetOpcode::G_SEXT);
0199
0200 Builder.setInstrAndDebugLoc(MI);
0201 Register DstReg = MI.getOperand(0).getReg();
0202 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
0203
0204
0205 Register TruncSrc;
0206 if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc)))) {
0207 LLT DstTy = MRI.getType(DstReg);
0208 if (isInstUnsupported({TargetOpcode::G_SEXT_INREG, {DstTy}}))
0209 return false;
0210 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI);
0211 LLT SrcTy = MRI.getType(SrcReg);
0212 uint64_t SizeInBits = SrcTy.getScalarSizeInBits();
0213 if (DstTy != MRI.getType(TruncSrc))
0214 TruncSrc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrc).getReg(0);
0215
0216
0217 if (KB && KB->computeNumSignBits(TruncSrc) >
0218 DstTy.getScalarSizeInBits() - SizeInBits)
0219 replaceRegOrBuildCopy(DstReg, TruncSrc, MRI, Builder, UpdatedDefs,
0220 Observer);
0221 else
0222 Builder.buildSExtInReg(DstReg, TruncSrc, SizeInBits);
0223 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
0224 return true;
0225 }
0226
0227
0228
0229 Register ExtSrc;
0230 MachineInstr *ExtMI;
0231 if (mi_match(SrcReg, MRI,
0232 m_all_of(m_MInstr(ExtMI), m_any_of(m_GZExt(m_Reg(ExtSrc)),
0233 m_GSExt(m_Reg(ExtSrc)))))) {
0234 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI);
0235 Builder.buildInstr(ExtMI->getOpcode(), {DstReg}, {ExtSrc});
0236 UpdatedDefs.push_back(DstReg);
0237 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
0238 return true;
0239 }
0240
0241
0242 auto *SrcMI = MRI.getVRegDef(SrcReg);
0243 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
0244 const LLT DstTy = MRI.getType(DstReg);
0245 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
0246 auto &CstVal = SrcMI->getOperand(1);
0247 Builder.buildConstant(
0248 DstReg, CstVal.getCImm()->getValue().sext(DstTy.getSizeInBits()));
0249 UpdatedDefs.push_back(DstReg);
0250 markInstAndDefDead(MI, *SrcMI, DeadInsts);
0251 return true;
0252 }
0253 }
0254
0255 return tryFoldImplicitDef(MI, DeadInsts, UpdatedDefs, Observer);
0256 }
0257
0258 bool tryCombineTrunc(MachineInstr &MI,
0259 SmallVectorImpl<MachineInstr *> &DeadInsts,
0260 SmallVectorImpl<Register> &UpdatedDefs,
0261 GISelObserverWrapper &Observer) {
0262 using namespace llvm::MIPatternMatch;
0263 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
0264
0265 Builder.setInstr(MI);
0266 Register DstReg = MI.getOperand(0).getReg();
0267 const LLT DstTy = MRI.getType(DstReg);
0268 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
0269
0270
0271 auto *SrcMI = MRI.getVRegDef(SrcReg);
0272 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
0273 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
0274 auto &CstVal = SrcMI->getOperand(1);
0275 Builder.buildConstant(
0276 DstReg, CstVal.getCImm()->getValue().trunc(DstTy.getSizeInBits()));
0277 UpdatedDefs.push_back(DstReg);
0278 markInstAndDefDead(MI, *SrcMI, DeadInsts);
0279 return true;
0280 }
0281 }
0282
0283
0284
0285 if (auto *SrcMerge = dyn_cast<GMerge>(SrcMI)) {
0286 const Register MergeSrcReg = SrcMerge->getSourceReg(0);
0287 const LLT MergeSrcTy = MRI.getType(MergeSrcReg);
0288
0289
0290 const unsigned DstSize = DstTy.getSizeInBits();
0291 const unsigned MergeSrcSize = MergeSrcTy.getSizeInBits();
0292 if (!DstTy.isScalar() || !MergeSrcTy.isScalar())
0293 return false;
0294
0295 if (DstSize < MergeSrcSize) {
0296
0297
0298 if (isInstUnsupported({TargetOpcode::G_TRUNC, {DstTy, MergeSrcTy}}))
0299 return false;
0300
0301 LLVM_DEBUG(dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_TRUNC: "
0302 << MI);
0303
0304 Builder.buildTrunc(DstReg, MergeSrcReg);
0305 UpdatedDefs.push_back(DstReg);
0306 } else if (DstSize == MergeSrcSize) {
0307
0308 LLVM_DEBUG(
0309 dbgs() << "Replacing G_TRUNC(G_MERGE_VALUES) with merge input: "
0310 << MI);
0311 replaceRegOrBuildCopy(DstReg, MergeSrcReg, MRI, Builder, UpdatedDefs,
0312 Observer);
0313 } else if (DstSize % MergeSrcSize == 0) {
0314
0315
0316 if (isInstUnsupported(
0317 {TargetOpcode::G_MERGE_VALUES, {DstTy, MergeSrcTy}}))
0318 return false;
0319
0320 LLVM_DEBUG(
0321 dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_MERGE_VALUES: "
0322 << MI);
0323
0324 const unsigned NumSrcs = DstSize / MergeSrcSize;
0325 assert(NumSrcs < SrcMI->getNumOperands() - 1 &&
0326 "trunc(merge) should require less inputs than merge");
0327 SmallVector<Register, 8> SrcRegs(NumSrcs);
0328 for (unsigned i = 0; i < NumSrcs; ++i)
0329 SrcRegs[i] = SrcMerge->getSourceReg(i);
0330
0331 Builder.buildMergeValues(DstReg, SrcRegs);
0332 UpdatedDefs.push_back(DstReg);
0333 } else {
0334
0335 return false;
0336 }
0337
0338 markInstAndDefDead(MI, *SrcMerge, DeadInsts);
0339 return true;
0340 }
0341
0342
0343 Register TruncSrc;
0344 if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc)))) {
0345
0346
0347
0348 LLVM_DEBUG(dbgs() << ".. Combine G_TRUNC(G_TRUNC): " << MI);
0349
0350 Builder.buildTrunc(DstReg, TruncSrc);
0351 UpdatedDefs.push_back(DstReg);
0352 markInstAndDefDead(MI, *MRI.getVRegDef(TruncSrc), DeadInsts);
0353 return true;
0354 }
0355
0356
0357 ArtifactValueFinder Finder(MRI, Builder, LI);
0358 if (Register FoundReg =
0359 Finder.findValueFromDef(DstReg, 0, DstTy.getSizeInBits())) {
0360 LLT FoundRegTy = MRI.getType(FoundReg);
0361 if (DstTy == FoundRegTy) {
0362 LLVM_DEBUG(dbgs() << ".. Combine G_TRUNC(G_[S,Z,ANY]EXT/G_TRUNC...): "
0363 << MI);
0364
0365 replaceRegOrBuildCopy(DstReg, FoundReg, MRI, Builder, UpdatedDefs,
0366 Observer);
0367 UpdatedDefs.push_back(DstReg);
0368 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
0369 return true;
0370 }
0371 }
0372
0373 return false;
0374 }
0375
0376
0377 bool tryFoldImplicitDef(MachineInstr &MI,
0378 SmallVectorImpl<MachineInstr *> &DeadInsts,
0379 SmallVectorImpl<Register> &UpdatedDefs,
0380 GISelObserverWrapper &Observer) {
0381 unsigned Opcode = MI.getOpcode();
0382 assert(Opcode == TargetOpcode::G_ANYEXT || Opcode == TargetOpcode::G_ZEXT ||
0383 Opcode == TargetOpcode::G_SEXT);
0384
0385 if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
0386 MI.getOperand(1).getReg(), MRI)) {
0387 Builder.setInstr(MI);
0388 Register DstReg = MI.getOperand(0).getReg();
0389 LLT DstTy = MRI.getType(DstReg);
0390
0391 if (Opcode == TargetOpcode::G_ANYEXT) {
0392
0393 if (!isInstLegal({TargetOpcode::G_IMPLICIT_DEF, {DstTy}}))
0394 return false;
0395 LLVM_DEBUG(dbgs() << ".. Combine G_ANYEXT(G_IMPLICIT_DEF): " << MI);
0396 auto Impl = Builder.buildUndef(DstTy);
0397 replaceRegOrBuildCopy(DstReg, Impl.getReg(0), MRI, Builder, UpdatedDefs,
0398 Observer);
0399 UpdatedDefs.push_back(DstReg);
0400 } else {
0401
0402
0403 if (isConstantUnsupported(DstTy))
0404 return false;
0405 LLVM_DEBUG(dbgs() << ".. Combine G_[SZ]EXT(G_IMPLICIT_DEF): " << MI);
0406 auto Cnst = Builder.buildConstant(DstTy, 0);
0407 replaceRegOrBuildCopy(DstReg, Cnst.getReg(0), MRI, Builder, UpdatedDefs,
0408 Observer);
0409 UpdatedDefs.push_back(DstReg);
0410 }
0411
0412 markInstAndDefDead(MI, *DefMI, DeadInsts);
0413 return true;
0414 }
0415 return false;
0416 }
0417
0418 bool tryFoldUnmergeCast(MachineInstr &MI, MachineInstr &CastMI,
0419 SmallVectorImpl<MachineInstr *> &DeadInsts,
0420 SmallVectorImpl<Register> &UpdatedDefs) {
0421
0422 assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
0423
0424 const unsigned CastOpc = CastMI.getOpcode();
0425
0426 if (!isArtifactCast(CastOpc))
0427 return false;
0428
0429 const unsigned NumDefs = MI.getNumOperands() - 1;
0430
0431 const Register CastSrcReg = CastMI.getOperand(1).getReg();
0432 const LLT CastSrcTy = MRI.getType(CastSrcReg);
0433 const LLT DestTy = MRI.getType(MI.getOperand(0).getReg());
0434 const LLT SrcTy = MRI.getType(MI.getOperand(NumDefs).getReg());
0435
0436 const unsigned CastSrcSize = CastSrcTy.getSizeInBits();
0437 const unsigned DestSize = DestTy.getSizeInBits();
0438
0439 if (CastOpc == TargetOpcode::G_TRUNC) {
0440 if (SrcTy.isVector() && SrcTy.getScalarType() == DestTy.getScalarType()) {
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450 unsigned UnmergeNumElts =
0451 DestTy.isVector() ? CastSrcTy.getNumElements() / NumDefs : 1;
0452 LLT UnmergeTy = CastSrcTy.changeElementCount(
0453 ElementCount::getFixed(UnmergeNumElts));
0454 LLT SrcWideTy =
0455 SrcTy.changeElementCount(ElementCount::getFixed(UnmergeNumElts));
0456
0457 if (isInstUnsupported(
0458 {TargetOpcode::G_UNMERGE_VALUES, {UnmergeTy, CastSrcTy}}) ||
0459 LI.getAction({TargetOpcode::G_TRUNC, {SrcWideTy, UnmergeTy}})
0460 .Action == LegalizeActions::MoreElements)
0461 return false;
0462
0463 Builder.setInstr(MI);
0464 auto NewUnmerge = Builder.buildUnmerge(UnmergeTy, CastSrcReg);
0465
0466 for (unsigned I = 0; I != NumDefs; ++I) {
0467 Register DefReg = MI.getOperand(I).getReg();
0468 UpdatedDefs.push_back(DefReg);
0469 Builder.buildTrunc(DefReg, NewUnmerge.getReg(I));
0470 }
0471
0472 markInstAndDefDead(MI, CastMI, DeadInsts);
0473 return true;
0474 }
0475
0476 if (CastSrcTy.isScalar() && SrcTy.isScalar() && !DestTy.isVector()) {
0477
0478
0479
0480
0481
0482
0483
0484 if (CastSrcSize % DestSize != 0)
0485 return false;
0486
0487
0488 if (isInstUnsupported(
0489 {TargetOpcode::G_UNMERGE_VALUES, {DestTy, CastSrcTy}}))
0490 return false;
0491
0492
0493
0494 const unsigned NewNumDefs = CastSrcSize / DestSize;
0495 SmallVector<Register, 8> DstRegs(NewNumDefs);
0496 for (unsigned Idx = 0; Idx < NewNumDefs; ++Idx) {
0497 if (Idx < NumDefs)
0498 DstRegs[Idx] = MI.getOperand(Idx).getReg();
0499 else
0500 DstRegs[Idx] = MRI.createGenericVirtualRegister(DestTy);
0501 }
0502
0503
0504 Builder.setInstr(MI);
0505 Builder.buildUnmerge(DstRegs, CastSrcReg);
0506 UpdatedDefs.append(DstRegs.begin(), DstRegs.begin() + NewNumDefs);
0507 markInstAndDefDead(MI, CastMI, DeadInsts);
0508 return true;
0509 }
0510 }
0511
0512
0513 return false;
0514 }
0515
0516 static bool canFoldMergeOpcode(unsigned MergeOp, unsigned ConvertOp,
0517 LLT OpTy, LLT DestTy) {
0518
0519 switch (MergeOp) {
0520 default:
0521 return false;
0522 case TargetOpcode::G_BUILD_VECTOR:
0523 case TargetOpcode::G_MERGE_VALUES:
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546 if (ConvertOp == 0)
0547 return true;
0548 return !DestTy.isVector() && OpTy.isVector() &&
0549 DestTy == OpTy.getElementType();
0550 case TargetOpcode::G_CONCAT_VECTORS: {
0551 if (ConvertOp == 0)
0552 return true;
0553 if (!DestTy.isVector())
0554 return false;
0555
0556 const unsigned OpEltSize = OpTy.getElementType().getSizeInBits();
0557
0558
0559
0560
0561 if (ConvertOp == TargetOpcode::G_TRUNC)
0562 return DestTy.getSizeInBits() <= OpEltSize;
0563 return DestTy.getSizeInBits() >= OpEltSize;
0564 }
0565 }
0566 }
0567
0568
0569
0570 static void replaceRegOrBuildCopy(Register DstReg, Register SrcReg,
0571 MachineRegisterInfo &MRI,
0572 MachineIRBuilder &Builder,
0573 SmallVectorImpl<Register> &UpdatedDefs,
0574 GISelChangeObserver &Observer) {
0575 if (!llvm::canReplaceReg(DstReg, SrcReg, MRI)) {
0576 Builder.buildCopy(DstReg, SrcReg);
0577 UpdatedDefs.push_back(DstReg);
0578 return;
0579 }
0580 SmallVector<MachineInstr *, 4> UseMIs;
0581
0582 for (auto &UseMI : MRI.use_instructions(DstReg)) {
0583 UseMIs.push_back(&UseMI);
0584 Observer.changingInstr(UseMI);
0585 }
0586
0587 MRI.replaceRegWith(DstReg, SrcReg);
0588 UpdatedDefs.push_back(SrcReg);
0589
0590 for (auto *UseMI : UseMIs)
0591 Observer.changedInstr(*UseMI);
0592 }
0593
0594
0595 static unsigned getDefIndex(const MachineInstr &MI, Register SearchDef) {
0596 unsigned DefIdx = 0;
0597 for (const MachineOperand &Def : MI.defs()) {
0598 if (Def.getReg() == SearchDef)
0599 break;
0600 ++DefIdx;
0601 }
0602
0603 return DefIdx;
0604 }
0605
0606
0607
0608
0609
0610 class ArtifactValueFinder {
0611 MachineRegisterInfo &MRI;
0612 MachineIRBuilder &MIB;
0613 const LegalizerInfo &LI;
0614
0615
0616 Register CurrentBest = Register();
0617
0618
0619
0620
0621
0622
0623 Register findValueFromConcat(GConcatVectors &Concat, unsigned StartBit,
0624 unsigned Size) {
0625 assert(Size > 0);
0626
0627
0628 Register Src1Reg = Concat.getSourceReg(0);
0629 unsigned SrcSize = MRI.getType(Src1Reg).getSizeInBits();
0630
0631
0632 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
0633
0634 unsigned InRegOffset = StartBit % SrcSize;
0635
0636
0637
0638 if (InRegOffset + Size > SrcSize)
0639 return CurrentBest;
0640
0641 Register SrcReg = Concat.getReg(StartSrcIdx);
0642 if (InRegOffset == 0 && Size == SrcSize) {
0643 CurrentBest = SrcReg;
0644 return findValueFromDefImpl(SrcReg, 0, Size);
0645 }
0646
0647 return findValueFromDefImpl(SrcReg, InRegOffset, Size);
0648 }
0649
0650
0651
0652
0653
0654
0655 Register findValueFromBuildVector(GBuildVector &BV, unsigned StartBit,
0656 unsigned Size) {
0657 assert(Size > 0);
0658
0659
0660 Register Src1Reg = BV.getSourceReg(0);
0661 unsigned SrcSize = MRI.getType(Src1Reg).getSizeInBits();
0662
0663
0664 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
0665
0666 unsigned InRegOffset = StartBit % SrcSize;
0667
0668 if (InRegOffset != 0)
0669 return CurrentBest;
0670 if (Size < SrcSize)
0671 return CurrentBest;
0672
0673
0674
0675 if (Size > SrcSize) {
0676 if (Size % SrcSize > 0)
0677 return CurrentBest;
0678
0679 unsigned NumSrcsUsed = Size / SrcSize;
0680
0681 if (NumSrcsUsed == BV.getNumSources())
0682 return BV.getReg(0);
0683
0684 LLT SrcTy = MRI.getType(Src1Reg);
0685 LLT NewBVTy = LLT::fixed_vector(NumSrcsUsed, SrcTy);
0686
0687
0688 LegalizeActionStep ActionStep =
0689 LI.getAction({TargetOpcode::G_BUILD_VECTOR, {NewBVTy, SrcTy}});
0690 if (ActionStep.Action != LegalizeActions::Legal)
0691 return CurrentBest;
0692
0693 SmallVector<Register> NewSrcs;
0694 for (unsigned SrcIdx = StartSrcIdx; SrcIdx < StartSrcIdx + NumSrcsUsed;
0695 ++SrcIdx)
0696 NewSrcs.push_back(BV.getReg(SrcIdx));
0697 MIB.setInstrAndDebugLoc(BV);
0698 return MIB.buildBuildVector(NewBVTy, NewSrcs).getReg(0);
0699 }
0700
0701 return BV.getReg(StartSrcIdx);
0702 }
0703
0704
0705
0706
0707
0708
0709 Register findValueFromInsert(MachineInstr &MI, unsigned StartBit,
0710 unsigned Size) {
0711 assert(MI.getOpcode() == TargetOpcode::G_INSERT);
0712 assert(Size > 0);
0713
0714 Register ContainerSrcReg = MI.getOperand(1).getReg();
0715 Register InsertedReg = MI.getOperand(2).getReg();
0716 LLT InsertedRegTy = MRI.getType(InsertedReg);
0717 unsigned InsertOffset = MI.getOperand(3).getImm();
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755 unsigned InsertedEndBit = InsertOffset + InsertedRegTy.getSizeInBits();
0756 unsigned EndBit = StartBit + Size;
0757 unsigned NewStartBit;
0758 Register SrcRegToUse;
0759 if (EndBit <= InsertOffset || InsertedEndBit <= StartBit) {
0760 SrcRegToUse = ContainerSrcReg;
0761 NewStartBit = StartBit;
0762 return findValueFromDefImpl(SrcRegToUse, NewStartBit, Size);
0763 }
0764 if (InsertOffset <= StartBit && EndBit <= InsertedEndBit) {
0765 SrcRegToUse = InsertedReg;
0766 NewStartBit = StartBit - InsertOffset;
0767 if (NewStartBit == 0 &&
0768 Size == MRI.getType(SrcRegToUse).getSizeInBits())
0769 CurrentBest = SrcRegToUse;
0770 return findValueFromDefImpl(SrcRegToUse, NewStartBit, Size);
0771 }
0772
0773 return Register();
0774 }
0775
0776
0777
0778
0779
0780
0781
0782 Register findValueFromExt(MachineInstr &MI, unsigned StartBit,
0783 unsigned Size) {
0784 assert(MI.getOpcode() == TargetOpcode::G_SEXT ||
0785 MI.getOpcode() == TargetOpcode::G_ZEXT ||
0786 MI.getOpcode() == TargetOpcode::G_ANYEXT);
0787 assert(Size > 0);
0788
0789 Register SrcReg = MI.getOperand(1).getReg();
0790 LLT SrcType = MRI.getType(SrcReg);
0791 unsigned SrcSize = SrcType.getSizeInBits();
0792
0793
0794 if (!SrcType.isScalar())
0795 return CurrentBest;
0796
0797 if (StartBit + Size > SrcSize)
0798 return CurrentBest;
0799
0800 if (StartBit == 0 && SrcType.getSizeInBits() == Size)
0801 CurrentBest = SrcReg;
0802 return findValueFromDefImpl(SrcReg, StartBit, Size);
0803 }
0804
0805
0806
0807
0808
0809
0810 Register findValueFromTrunc(MachineInstr &MI, unsigned StartBit,
0811 unsigned Size) {
0812 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
0813 assert(Size > 0);
0814
0815 Register SrcReg = MI.getOperand(1).getReg();
0816 LLT SrcType = MRI.getType(SrcReg);
0817
0818
0819 if (!SrcType.isScalar())
0820 return CurrentBest;
0821
0822 return findValueFromDefImpl(SrcReg, StartBit, Size);
0823 }
0824
0825
0826
0827
0828 Register findValueFromDefImpl(Register DefReg, unsigned StartBit,
0829 unsigned Size) {
0830 std::optional<DefinitionAndSourceRegister> DefSrcReg =
0831 getDefSrcRegIgnoringCopies(DefReg, MRI);
0832 MachineInstr *Def = DefSrcReg->MI;
0833 DefReg = DefSrcReg->Reg;
0834
0835
0836
0837 switch (Def->getOpcode()) {
0838 case TargetOpcode::G_CONCAT_VECTORS:
0839 return findValueFromConcat(cast<GConcatVectors>(*Def), StartBit, Size);
0840 case TargetOpcode::G_UNMERGE_VALUES: {
0841 unsigned DefStartBit = 0;
0842 unsigned DefSize = MRI.getType(DefReg).getSizeInBits();
0843 for (const auto &MO : Def->defs()) {
0844 if (MO.getReg() == DefReg)
0845 break;
0846 DefStartBit += DefSize;
0847 }
0848 Register SrcReg = Def->getOperand(Def->getNumOperands() - 1).getReg();
0849 Register SrcOriginReg =
0850 findValueFromDefImpl(SrcReg, StartBit + DefStartBit, Size);
0851 if (SrcOriginReg)
0852 return SrcOriginReg;
0853
0854
0855
0856 if (StartBit == 0 && Size == DefSize)
0857 return DefReg;
0858 return CurrentBest;
0859 }
0860 case TargetOpcode::G_BUILD_VECTOR:
0861 return findValueFromBuildVector(cast<GBuildVector>(*Def), StartBit,
0862 Size);
0863 case TargetOpcode::G_INSERT:
0864 return findValueFromInsert(*Def, StartBit, Size);
0865 case TargetOpcode::G_TRUNC:
0866 return findValueFromTrunc(*Def, StartBit, Size);
0867 case TargetOpcode::G_SEXT:
0868 case TargetOpcode::G_ZEXT:
0869 case TargetOpcode::G_ANYEXT:
0870 return findValueFromExt(*Def, StartBit, Size);
0871 default:
0872 return CurrentBest;
0873 }
0874 }
0875
0876 public:
0877 ArtifactValueFinder(MachineRegisterInfo &Mri, MachineIRBuilder &Builder,
0878 const LegalizerInfo &Info)
0879 : MRI(Mri), MIB(Builder), LI(Info) {}
0880
0881
0882
0883
0884
0885 Register findValueFromDef(Register DefReg, unsigned StartBit,
0886 unsigned Size) {
0887 CurrentBest = Register();
0888 Register FoundReg = findValueFromDefImpl(DefReg, StartBit, Size);
0889 return FoundReg != DefReg ? FoundReg : Register();
0890 }
0891
0892
0893
0894
0895 bool tryCombineUnmergeDefs(GUnmerge &MI, GISelChangeObserver &Observer,
0896 SmallVectorImpl<Register> &UpdatedDefs) {
0897 unsigned NumDefs = MI.getNumDefs();
0898 LLT DestTy = MRI.getType(MI.getReg(0));
0899
0900 SmallBitVector DeadDefs(NumDefs);
0901 for (unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
0902 Register DefReg = MI.getReg(DefIdx);
0903 if (MRI.use_nodbg_empty(DefReg)) {
0904 DeadDefs[DefIdx] = true;
0905 continue;
0906 }
0907 Register FoundVal = findValueFromDef(DefReg, 0, DestTy.getSizeInBits());
0908 if (!FoundVal)
0909 continue;
0910 if (MRI.getType(FoundVal) != DestTy)
0911 continue;
0912
0913 replaceRegOrBuildCopy(DefReg, FoundVal, MRI, MIB, UpdatedDefs,
0914 Observer);
0915
0916 Observer.changingInstr(MI);
0917 MI.getOperand(DefIdx).setReg(DefReg);
0918 Observer.changedInstr(MI);
0919 DeadDefs[DefIdx] = true;
0920 }
0921 return DeadDefs.all();
0922 }
0923
0924 GUnmerge *findUnmergeThatDefinesReg(Register Reg, unsigned Size,
0925 unsigned &DefOperandIdx) {
0926 if (Register Def = findValueFromDefImpl(Reg, 0, Size)) {
0927 if (auto *Unmerge = dyn_cast<GUnmerge>(MRI.getVRegDef(Def))) {
0928 DefOperandIdx =
0929 Unmerge->findRegisterDefOperandIdx(Def, nullptr);
0930 return Unmerge;
0931 }
0932 }
0933 return nullptr;
0934 }
0935
0936
0937
0938
0939 bool isSequenceFromUnmerge(GMergeLikeInstr &MI, unsigned MergeStartIdx,
0940 GUnmerge *Unmerge, unsigned UnmergeIdxStart,
0941 unsigned NumElts, unsigned EltSize,
0942 bool AllowUndef) {
0943 assert(MergeStartIdx + NumElts <= MI.getNumSources());
0944 for (unsigned i = MergeStartIdx; i < MergeStartIdx + NumElts; ++i) {
0945 unsigned EltUnmergeIdx;
0946 GUnmerge *EltUnmerge = findUnmergeThatDefinesReg(
0947 MI.getSourceReg(i), EltSize, EltUnmergeIdx);
0948
0949 if (EltUnmerge == Unmerge) {
0950
0951 if (i - MergeStartIdx != EltUnmergeIdx - UnmergeIdxStart)
0952 return false;
0953 } else if (!AllowUndef ||
0954 MRI.getVRegDef(MI.getSourceReg(i))->getOpcode() !=
0955 TargetOpcode::G_IMPLICIT_DEF)
0956 return false;
0957 }
0958 return true;
0959 }
0960
0961 bool tryCombineMergeLike(GMergeLikeInstr &MI,
0962 SmallVectorImpl<MachineInstr *> &DeadInsts,
0963 SmallVectorImpl<Register> &UpdatedDefs,
0964 GISelChangeObserver &Observer) {
0965 Register Elt0 = MI.getSourceReg(0);
0966 LLT EltTy = MRI.getType(Elt0);
0967 unsigned EltSize = EltTy.getSizeInBits();
0968
0969 unsigned Elt0UnmergeIdx;
0970
0971 auto *Unmerge = findUnmergeThatDefinesReg(Elt0, EltSize, Elt0UnmergeIdx);
0972 if (!Unmerge)
0973 return false;
0974
0975 unsigned NumMIElts = MI.getNumSources();
0976 Register Dst = MI.getReg(0);
0977 LLT DstTy = MRI.getType(Dst);
0978 Register UnmergeSrc = Unmerge->getSourceReg();
0979 LLT UnmergeSrcTy = MRI.getType(UnmergeSrc);
0980
0981
0982
0983
0984
0985
0986
0987
0988 if ((DstTy == UnmergeSrcTy) && (Elt0UnmergeIdx == 0)) {
0989 if (!isSequenceFromUnmerge(MI, 0, Unmerge, 0, NumMIElts, EltSize,
0990 DstTy.isVector()))
0991 return false;
0992
0993 replaceRegOrBuildCopy(Dst, UnmergeSrc, MRI, MIB, UpdatedDefs, Observer);
0994 DeadInsts.push_back(&MI);
0995 return true;
0996 }
0997
0998
0999
1000
1001
1002
1003
1004
1005
1006
1007
1008 if ((DstTy.isVector() == UnmergeSrcTy.isVector()) &&
1009 (Elt0UnmergeIdx % NumMIElts == 0) &&
1010 getCoverTy(UnmergeSrcTy, DstTy) == UnmergeSrcTy) {
1011 if (!isSequenceFromUnmerge(MI, 0, Unmerge, Elt0UnmergeIdx, NumMIElts,
1012 EltSize, false))
1013 return false;
1014 MIB.setInstrAndDebugLoc(MI);
1015 auto NewUnmerge = MIB.buildUnmerge(DstTy, Unmerge->getSourceReg());
1016 unsigned DstIdx = (Elt0UnmergeIdx * EltSize) / DstTy.getSizeInBits();
1017 replaceRegOrBuildCopy(Dst, NewUnmerge.getReg(DstIdx), MRI, MIB,
1018 UpdatedDefs, Observer);
1019 DeadInsts.push_back(&MI);
1020 return true;
1021 }
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033 if ((DstTy.isVector() == UnmergeSrcTy.isVector()) &&
1034 getCoverTy(DstTy, UnmergeSrcTy) == DstTy) {
1035 SmallVector<Register, 4> ConcatSources;
1036 unsigned NumElts = Unmerge->getNumDefs();
1037 for (unsigned i = 0; i < MI.getNumSources(); i += NumElts) {
1038 unsigned EltUnmergeIdx;
1039 auto *UnmergeI = findUnmergeThatDefinesReg(MI.getSourceReg(i),
1040 EltSize, EltUnmergeIdx);
1041
1042 if ((!UnmergeI) || (UnmergeI->getNumDefs() != NumElts) ||
1043 (EltUnmergeIdx != 0))
1044 return false;
1045 if (!isSequenceFromUnmerge(MI, i, UnmergeI, 0, NumElts, EltSize,
1046 false))
1047 return false;
1048 ConcatSources.push_back(UnmergeI->getSourceReg());
1049 }
1050
1051 MIB.setInstrAndDebugLoc(MI);
1052 MIB.buildMergeLikeInstr(Dst, ConcatSources);
1053 DeadInsts.push_back(&MI);
1054 return true;
1055 }
1056
1057 return false;
1058 }
1059 };
1060
1061 bool tryCombineUnmergeValues(GUnmerge &MI,
1062 SmallVectorImpl<MachineInstr *> &DeadInsts,
1063 SmallVectorImpl<Register> &UpdatedDefs,
1064 GISelChangeObserver &Observer) {
1065 unsigned NumDefs = MI.getNumDefs();
1066 Register SrcReg = MI.getSourceReg();
1067 MachineInstr *SrcDef = getDefIgnoringCopies(SrcReg, MRI);
1068 if (!SrcDef)
1069 return false;
1070
1071 LLT OpTy = MRI.getType(SrcReg);
1072 LLT DestTy = MRI.getType(MI.getReg(0));
1073 unsigned SrcDefIdx = getDefIndex(*SrcDef, SrcReg);
1074
1075 Builder.setInstrAndDebugLoc(MI);
1076
1077 ArtifactValueFinder Finder(MRI, Builder, LI);
1078 if (Finder.tryCombineUnmergeDefs(MI, Observer, UpdatedDefs)) {
1079 markInstAndDefDead(MI, *SrcDef, DeadInsts, SrcDefIdx);
1080 return true;
1081 }
1082
1083 if (auto *SrcUnmerge = dyn_cast<GUnmerge>(SrcDef)) {
1084
1085
1086
1087
1088
1089 Register SrcUnmergeSrc = SrcUnmerge->getSourceReg();
1090 LLT SrcUnmergeSrcTy = MRI.getType(SrcUnmergeSrc);
1091
1092
1093
1094
1095 LegalizeActionStep ActionStep = LI.getAction(
1096 {TargetOpcode::G_UNMERGE_VALUES, {OpTy, SrcUnmergeSrcTy}});
1097 switch (ActionStep.Action) {
1098 case LegalizeActions::Legal:
1099 if (!OpTy.isVector() || !LI.isLegal({TargetOpcode::G_UNMERGE_VALUES,
1100 {DestTy, SrcUnmergeSrcTy}}))
1101 return false;
1102 break;
1103 case LegalizeActions::Lower:
1104 case LegalizeActions::Unsupported:
1105 break;
1106 case LegalizeActions::FewerElements:
1107 case LegalizeActions::NarrowScalar:
1108 if (ActionStep.TypeIdx == 1)
1109 return false;
1110 break;
1111 default:
1112 return false;
1113 }
1114
1115 auto NewUnmerge = Builder.buildUnmerge(DestTy, SrcUnmergeSrc);
1116
1117
1118
1119
1120 for (unsigned I = 0; I != NumDefs; ++I) {
1121 Register Def = MI.getReg(I);
1122 replaceRegOrBuildCopy(Def, NewUnmerge.getReg(SrcDefIdx * NumDefs + I),
1123 MRI, Builder, UpdatedDefs, Observer);
1124 }
1125
1126 markInstAndDefDead(MI, *SrcUnmerge, DeadInsts, SrcDefIdx);
1127 return true;
1128 }
1129
1130 MachineInstr *MergeI = SrcDef;
1131 unsigned ConvertOp = 0;
1132
1133
1134 unsigned SrcOp = SrcDef->getOpcode();
1135 if (isArtifactCast(SrcOp)) {
1136 ConvertOp = SrcOp;
1137 MergeI = getDefIgnoringCopies(SrcDef->getOperand(1).getReg(), MRI);
1138 }
1139
1140 if (!MergeI || !canFoldMergeOpcode(MergeI->getOpcode(),
1141 ConvertOp, OpTy, DestTy)) {
1142
1143
1144 return tryFoldUnmergeCast(MI, *SrcDef, DeadInsts, UpdatedDefs);
1145 }
1146
1147 const unsigned NumMergeRegs = MergeI->getNumOperands() - 1;
1148
1149 if (NumMergeRegs < NumDefs) {
1150 if (NumDefs % NumMergeRegs != 0)
1151 return false;
1152
1153 Builder.setInstr(MI);
1154
1155
1156
1157
1158
1159
1160
1161 const unsigned NewNumDefs = NumDefs / NumMergeRegs;
1162 for (unsigned Idx = 0; Idx < NumMergeRegs; ++Idx) {
1163 SmallVector<Register, 8> DstRegs;
1164 for (unsigned j = 0, DefIdx = Idx * NewNumDefs; j < NewNumDefs;
1165 ++j, ++DefIdx)
1166 DstRegs.push_back(MI.getReg(DefIdx));
1167
1168 if (ConvertOp) {
1169 LLT MergeDstTy = MRI.getType(SrcDef->getOperand(0).getReg());
1170
1171
1172
1173
1174 LLT MergeEltTy = MergeDstTy.divide(NumMergeRegs);
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189 Register TmpReg = MRI.createGenericVirtualRegister(MergeEltTy);
1190 Builder.buildInstr(ConvertOp, {TmpReg},
1191 {MergeI->getOperand(Idx + 1).getReg()});
1192 Builder.buildUnmerge(DstRegs, TmpReg);
1193 } else {
1194 Builder.buildUnmerge(DstRegs, MergeI->getOperand(Idx + 1).getReg());
1195 }
1196 UpdatedDefs.append(DstRegs.begin(), DstRegs.end());
1197 }
1198
1199 } else if (NumMergeRegs > NumDefs) {
1200 if (ConvertOp != 0 || NumMergeRegs % NumDefs != 0)
1201 return false;
1202
1203 Builder.setInstr(MI);
1204
1205
1206
1207
1208
1209
1210
1211 const unsigned NumRegs = NumMergeRegs / NumDefs;
1212 for (unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
1213 SmallVector<Register, 8> Regs;
1214 for (unsigned j = 0, Idx = NumRegs * DefIdx + 1; j < NumRegs;
1215 ++j, ++Idx)
1216 Regs.push_back(MergeI->getOperand(Idx).getReg());
1217
1218 Register DefReg = MI.getReg(DefIdx);
1219 Builder.buildMergeLikeInstr(DefReg, Regs);
1220 UpdatedDefs.push_back(DefReg);
1221 }
1222
1223 } else {
1224 LLT MergeSrcTy = MRI.getType(MergeI->getOperand(1).getReg());
1225
1226 if (!ConvertOp && DestTy != MergeSrcTy) {
1227 if (DestTy.isPointer())
1228 ConvertOp = TargetOpcode::G_INTTOPTR;
1229 else if (MergeSrcTy.isPointer())
1230 ConvertOp = TargetOpcode::G_PTRTOINT;
1231 else
1232 ConvertOp = TargetOpcode::G_BITCAST;
1233 }
1234
1235 if (ConvertOp) {
1236 Builder.setInstr(MI);
1237
1238 for (unsigned Idx = 0; Idx < NumDefs; ++Idx) {
1239 Register DefReg = MI.getOperand(Idx).getReg();
1240 Register MergeSrc = MergeI->getOperand(Idx + 1).getReg();
1241
1242 if (!MRI.use_empty(DefReg)) {
1243 Builder.buildInstr(ConvertOp, {DefReg}, {MergeSrc});
1244 UpdatedDefs.push_back(DefReg);
1245 }
1246 }
1247
1248 markInstAndDefDead(MI, *MergeI, DeadInsts);
1249 return true;
1250 }
1251
1252 assert(DestTy == MergeSrcTy &&
1253 "Bitcast and the other kinds of conversions should "
1254 "have happened earlier");
1255
1256 Builder.setInstr(MI);
1257 for (unsigned Idx = 0; Idx < NumDefs; ++Idx) {
1258 Register DstReg = MI.getOperand(Idx).getReg();
1259 Register SrcReg = MergeI->getOperand(Idx + 1).getReg();
1260 replaceRegOrBuildCopy(DstReg, SrcReg, MRI, Builder, UpdatedDefs,
1261 Observer);
1262 }
1263 }
1264
1265 markInstAndDefDead(MI, *MergeI, DeadInsts);
1266 return true;
1267 }
1268
1269 bool tryCombineExtract(MachineInstr &MI,
1270 SmallVectorImpl<MachineInstr *> &DeadInsts,
1271 SmallVectorImpl<Register> &UpdatedDefs) {
1272 assert(MI.getOpcode() == TargetOpcode::G_EXTRACT);
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
1287 MachineInstr *MergeI = MRI.getVRegDef(SrcReg);
1288 if (!MergeI || !isa<GMergeLikeInstr>(MergeI))
1289 return false;
1290
1291 Register DstReg = MI.getOperand(0).getReg();
1292 LLT DstTy = MRI.getType(DstReg);
1293 LLT SrcTy = MRI.getType(SrcReg);
1294
1295
1296 unsigned ExtractDstSize = DstTy.getSizeInBits();
1297 unsigned Offset = MI.getOperand(2).getImm();
1298 unsigned NumMergeSrcs = MergeI->getNumOperands() - 1;
1299 unsigned MergeSrcSize = SrcTy.getSizeInBits() / NumMergeSrcs;
1300 unsigned MergeSrcIdx = Offset / MergeSrcSize;
1301
1302
1303 unsigned EndMergeSrcIdx = (Offset + ExtractDstSize - 1) / MergeSrcSize;
1304
1305
1306 if (MergeSrcIdx != EndMergeSrcIdx)
1307 return false;
1308
1309
1310 Builder.setInstr(MI);
1311 Builder.buildExtract(DstReg, MergeI->getOperand(MergeSrcIdx + 1).getReg(),
1312 Offset - MergeSrcIdx * MergeSrcSize);
1313 UpdatedDefs.push_back(DstReg);
1314 markInstAndDefDead(MI, *MergeI, DeadInsts);
1315 return true;
1316 }
1317
1318
1319
1320
1321
1322 bool tryCombineInstruction(MachineInstr &MI,
1323 SmallVectorImpl<MachineInstr *> &DeadInsts,
1324 GISelObserverWrapper &WrapperObserver) {
1325 ArtifactValueFinder Finder(MRI, Builder, LI);
1326
1327
1328
1329
1330 if (!DeadInsts.empty())
1331 deleteMarkedDeadInsts(DeadInsts, WrapperObserver);
1332
1333
1334
1335
1336
1337 SmallVector<Register, 4> UpdatedDefs;
1338 bool Changed = false;
1339 switch (MI.getOpcode()) {
1340 default:
1341 return false;
1342 case TargetOpcode::G_ANYEXT:
1343 Changed = tryCombineAnyExt(MI, DeadInsts, UpdatedDefs, WrapperObserver);
1344 break;
1345 case TargetOpcode::G_ZEXT:
1346 Changed = tryCombineZExt(MI, DeadInsts, UpdatedDefs, WrapperObserver);
1347 break;
1348 case TargetOpcode::G_SEXT:
1349 Changed = tryCombineSExt(MI, DeadInsts, UpdatedDefs, WrapperObserver);
1350 break;
1351 case TargetOpcode::G_UNMERGE_VALUES:
1352 Changed = tryCombineUnmergeValues(cast<GUnmerge>(MI), DeadInsts,
1353 UpdatedDefs, WrapperObserver);
1354 break;
1355 case TargetOpcode::G_MERGE_VALUES:
1356 case TargetOpcode::G_BUILD_VECTOR:
1357 case TargetOpcode::G_CONCAT_VECTORS:
1358
1359
1360 for (MachineInstr &U : MRI.use_instructions(MI.getOperand(0).getReg())) {
1361 if (U.getOpcode() == TargetOpcode::G_UNMERGE_VALUES ||
1362 U.getOpcode() == TargetOpcode::G_TRUNC) {
1363 UpdatedDefs.push_back(MI.getOperand(0).getReg());
1364 break;
1365 }
1366 }
1367 Changed = Finder.tryCombineMergeLike(cast<GMergeLikeInstr>(MI), DeadInsts,
1368 UpdatedDefs, WrapperObserver);
1369 break;
1370 case TargetOpcode::G_EXTRACT:
1371 Changed = tryCombineExtract(MI, DeadInsts, UpdatedDefs);
1372 break;
1373 case TargetOpcode::G_TRUNC:
1374 Changed = tryCombineTrunc(MI, DeadInsts, UpdatedDefs, WrapperObserver);
1375 if (!Changed) {
1376
1377
1378
1379
1380 UpdatedDefs.push_back(MI.getOperand(0).getReg());
1381 }
1382 break;
1383 }
1384
1385
1386
1387
1388 while (!UpdatedDefs.empty()) {
1389 Register NewDef = UpdatedDefs.pop_back_val();
1390 assert(NewDef.isVirtual() && "Unexpected redefinition of a physreg");
1391 for (MachineInstr &Use : MRI.use_instructions(NewDef)) {
1392 switch (Use.getOpcode()) {
1393
1394 case TargetOpcode::G_ANYEXT:
1395 case TargetOpcode::G_ZEXT:
1396 case TargetOpcode::G_SEXT:
1397 case TargetOpcode::G_UNMERGE_VALUES:
1398 case TargetOpcode::G_EXTRACT:
1399 case TargetOpcode::G_TRUNC:
1400 case TargetOpcode::G_BUILD_VECTOR:
1401
1402 WrapperObserver.changedInstr(Use);
1403 break;
1404 case TargetOpcode::G_ASSERT_SEXT:
1405 case TargetOpcode::G_ASSERT_ZEXT:
1406 case TargetOpcode::G_ASSERT_ALIGN:
1407 case TargetOpcode::COPY: {
1408 Register Copy = Use.getOperand(0).getReg();
1409 if (Copy.isVirtual())
1410 UpdatedDefs.push_back(Copy);
1411 break;
1412 }
1413 default:
1414
1415
1416
1417 break;
1418 }
1419 }
1420 }
1421 return Changed;
1422 }
1423
1424 private:
1425 static Register getArtifactSrcReg(const MachineInstr &MI) {
1426 switch (MI.getOpcode()) {
1427 case TargetOpcode::COPY:
1428 case TargetOpcode::G_TRUNC:
1429 case TargetOpcode::G_ZEXT:
1430 case TargetOpcode::G_ANYEXT:
1431 case TargetOpcode::G_SEXT:
1432 case TargetOpcode::G_EXTRACT:
1433 case TargetOpcode::G_ASSERT_SEXT:
1434 case TargetOpcode::G_ASSERT_ZEXT:
1435 case TargetOpcode::G_ASSERT_ALIGN:
1436 return MI.getOperand(1).getReg();
1437 case TargetOpcode::G_UNMERGE_VALUES:
1438 return MI.getOperand(MI.getNumOperands() - 1).getReg();
1439 default:
1440 llvm_unreachable("Not a legalization artifact happen");
1441 }
1442 }
1443
1444
1445
1446
1447
1448
1449 void markDefDead(MachineInstr &MI, MachineInstr &DefMI,
1450 SmallVectorImpl<MachineInstr *> &DeadInsts,
1451 unsigned DefIdx = 0) {
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461 MachineInstr *PrevMI = &MI;
1462 while (PrevMI != &DefMI) {
1463 Register PrevRegSrc = getArtifactSrcReg(*PrevMI);
1464
1465 MachineInstr *TmpDef = MRI.getVRegDef(PrevRegSrc);
1466 if (MRI.hasOneUse(PrevRegSrc)) {
1467 if (TmpDef != &DefMI) {
1468 assert((TmpDef->getOpcode() == TargetOpcode::COPY ||
1469 isArtifactCast(TmpDef->getOpcode()) ||
1470 isPreISelGenericOptimizationHint(TmpDef->getOpcode())) &&
1471 "Expecting copy or artifact cast here");
1472
1473 DeadInsts.push_back(TmpDef);
1474 }
1475 } else
1476 break;
1477 PrevMI = TmpDef;
1478 }
1479
1480 if (PrevMI == &DefMI) {
1481 unsigned I = 0;
1482 bool IsDead = true;
1483 for (MachineOperand &Def : DefMI.defs()) {
1484 if (I != DefIdx) {
1485 if (!MRI.use_empty(Def.getReg())) {
1486 IsDead = false;
1487 break;
1488 }
1489 } else {
1490 if (!MRI.hasOneUse(DefMI.getOperand(DefIdx).getReg()))
1491 break;
1492 }
1493
1494 ++I;
1495 }
1496
1497 if (IsDead)
1498 DeadInsts.push_back(&DefMI);
1499 }
1500 }
1501
1502
1503
1504
1505
1506
1507 void markInstAndDefDead(MachineInstr &MI, MachineInstr &DefMI,
1508 SmallVectorImpl<MachineInstr *> &DeadInsts,
1509 unsigned DefIdx = 0) {
1510 DeadInsts.push_back(&MI);
1511 markDefDead(MI, DefMI, DeadInsts, DefIdx);
1512 }
1513
1514
1515
1516
1517
1518
1519
1520 void deleteMarkedDeadInsts(SmallVectorImpl<MachineInstr *> &DeadInsts,
1521 GISelObserverWrapper &WrapperObserver) {
1522 for (auto *DeadMI : DeadInsts) {
1523 LLVM_DEBUG(dbgs() << *DeadMI << "Is dead, eagerly deleting\n");
1524 WrapperObserver.erasingInstr(*DeadMI);
1525 DeadMI->eraseFromParent();
1526 }
1527 DeadInsts.clear();
1528 }
1529
1530
1531
1532 bool isInstUnsupported(const LegalityQuery &Query) const {
1533 using namespace LegalizeActions;
1534 auto Step = LI.getAction(Query);
1535 return Step.Action == Unsupported || Step.Action == NotFound;
1536 }
1537
1538 bool isInstLegal(const LegalityQuery &Query) const {
1539 return LI.getAction(Query).Action == LegalizeActions::Legal;
1540 }
1541
1542 bool isConstantUnsupported(LLT Ty) const {
1543 if (!Ty.isVector())
1544 return isInstUnsupported({TargetOpcode::G_CONSTANT, {Ty}});
1545
1546 LLT EltTy = Ty.getElementType();
1547 return isInstUnsupported({TargetOpcode::G_CONSTANT, {EltTy}}) ||
1548 isInstUnsupported({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}});
1549 }
1550
1551
1552
1553 Register lookThroughCopyInstrs(Register Reg) {
1554 Register TmpReg = getSrcRegIgnoringCopies(Reg, MRI);
1555 return TmpReg.isValid() ? TmpReg : Reg;
1556 }
1557 };
1558
1559 }
1560
1561 #endif