14#ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZATIONARTIFACTCOMBINER_H
15#define LLVM_CODEGEN_GLOBALISEL_LEGALIZATIONARTIFACTCOMBINER_H
32#define DEBUG_TYPE "legalizer"
41 static bool isArtifactCast(
unsigned Opc) {
43 case TargetOpcode::G_TRUNC:
44 case TargetOpcode::G_SEXT:
45 case TargetOpcode::G_ZEXT:
46 case TargetOpcode::G_ANYEXT:
57 : Builder(
B),
MRI(
MRI), LI(LI), KB(KB) {}
64 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT);
68 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
72 if (mi_match(SrcReg,
MRI, m_GTrunc(m_Reg(TruncSrc)))) {
74 if (
MRI.getType(DstReg) ==
MRI.getType(TruncSrc))
80 markInstAndDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
87 if (mi_match(SrcReg,
MRI,
88 m_all_of(m_MInstr(ExtMI), m_any_of(m_GAnyExt(m_Reg(ExtSrc)),
89 m_GSExt(m_Reg(ExtSrc)),
90 m_GZExt(m_Reg(ExtSrc)))))) {
93 markInstAndDefDead(
MI, *ExtMI, DeadInsts);
98 auto *SrcMI =
MRI.getVRegDef(SrcReg);
99 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
100 const LLT DstTy =
MRI.getType(DstReg);
101 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
102 auto &CstVal = SrcMI->getOperand(1);
104 MI.getDebugLoc().get(), SrcMI->getDebugLoc().get());
109 DstReg, CstVal.getCImm()->getValue().sext(DstTy.
getSizeInBits()));
111 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
123 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT);
127 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
133 if (mi_match(SrcReg,
MRI, m_GTrunc(m_Reg(TruncSrc))) ||
134 mi_match(SrcReg,
MRI, m_GSExt(m_Reg(SextSrc)))) {
135 LLT DstTy =
MRI.getType(DstReg);
136 if (isInstUnsupported({TargetOpcode::G_AND, {DstTy}}) ||
137 isConstantUnsupported(DstTy))
140 LLT SrcTy =
MRI.getType(SrcReg);
142 if (SextSrc && (DstTy !=
MRI.getType(SextSrc)))
144 if (TruncSrc && (DstTy !=
MRI.getType(TruncSrc)))
147 Register AndSrc = SextSrc ? SextSrc : TruncSrc;
154 if (KB && (KB->
getKnownZeroes(AndSrc) | ExtMaskVal).isAllOnes()) {
159 Builder.
buildAnd(DstReg, AndSrc, Mask);
161 markInstAndDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
167 if (mi_match(SrcReg,
MRI, m_GZExt(m_Reg(ZextSrc)))) {
170 MI.getOperand(1).setReg(ZextSrc);
173 markDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
178 auto *SrcMI =
MRI.getVRegDef(SrcReg);
179 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
180 const LLT DstTy =
MRI.getType(DstReg);
181 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
182 auto &CstVal = SrcMI->getOperand(1);
184 DstReg, CstVal.getCImm()->getValue().zext(DstTy.
getSizeInBits()));
186 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
197 assert(
MI.getOpcode() == TargetOpcode::G_SEXT);
201 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
205 if (mi_match(SrcReg,
MRI, m_GTrunc(m_Reg(TruncSrc)))) {
206 LLT DstTy =
MRI.getType(DstReg);
207 if (isInstUnsupported({TargetOpcode::G_SEXT_INREG, {DstTy}}))
210 LLT SrcTy =
MRI.getType(SrcReg);
211 uint64_t SizeInBits = SrcTy.getScalarSizeInBits();
212 if (DstTy !=
MRI.getType(TruncSrc))
215 markInstAndDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
223 if (mi_match(SrcReg,
MRI,
224 m_all_of(m_MInstr(ExtMI), m_any_of(m_GZExt(m_Reg(ExtSrc)),
225 m_GSExt(m_Reg(ExtSrc)))))) {
229 markInstAndDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
234 auto *SrcMI =
MRI.getVRegDef(SrcReg);
235 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
236 const LLT DstTy =
MRI.getType(DstReg);
237 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
238 auto &CstVal = SrcMI->getOperand(1);
240 DstReg, CstVal.getCImm()->getValue().sext(DstTy.
getSizeInBits()));
242 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
255 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC);
259 const LLT DstTy =
MRI.getType(DstReg);
260 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
263 auto *SrcMI =
MRI.getVRegDef(SrcReg);
264 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
265 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
266 auto &CstVal = SrcMI->getOperand(1);
268 DstReg, CstVal.getCImm()->getValue().trunc(DstTy.
getSizeInBits()));
270 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
277 if (
auto *SrcMerge = dyn_cast<GMerge>(SrcMI)) {
278 const Register MergeSrcReg = SrcMerge->getSourceReg(0);
279 const LLT MergeSrcTy =
MRI.getType(MergeSrcReg);
287 if (DstSize < MergeSrcSize) {
290 if (isInstUnsupported({TargetOpcode::G_TRUNC, {DstTy, MergeSrcTy}}))
293 LLVM_DEBUG(
dbgs() <<
"Combining G_TRUNC(G_MERGE_VALUES) to G_TRUNC: "
298 }
else if (DstSize == MergeSrcSize) {
301 dbgs() <<
"Replacing G_TRUNC(G_MERGE_VALUES) with merge input: "
305 }
else if (DstSize % MergeSrcSize == 0) {
308 if (isInstUnsupported(
309 {TargetOpcode::G_MERGE_VALUES, {DstTy, MergeSrcTy}}))
313 dbgs() <<
"Combining G_TRUNC(G_MERGE_VALUES) to G_MERGE_VALUES: "
316 const unsigned NumSrcs = DstSize / MergeSrcSize;
317 assert(NumSrcs < SrcMI->getNumOperands() - 1 &&
318 "trunc(merge) should require less inputs than merge");
320 for (
unsigned i = 0; i < NumSrcs; ++i)
321 SrcRegs[i] = SrcMerge->getSourceReg(i);
330 markInstAndDefDead(
MI, *SrcMerge, DeadInsts);
336 if (mi_match(SrcReg,
MRI, m_GTrunc(m_Reg(TruncSrc)))) {
344 markInstAndDefDead(
MI, *
MRI.getVRegDef(TruncSrc), DeadInsts);
352 LLT FoundRegTy =
MRI.getType(FoundReg);
353 if (DstTy == FoundRegTy) {
354 LLVM_DEBUG(
dbgs() <<
".. Combine G_TRUNC(G_[S,Z,ANY]EXT/G_TRUNC...): "
360 markInstAndDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
372 unsigned Opcode =
MI.getOpcode();
373 assert(Opcode == TargetOpcode::G_ANYEXT || Opcode == TargetOpcode::G_ZEXT ||
374 Opcode == TargetOpcode::G_SEXT);
377 MI.getOperand(1).getReg(),
MRI)) {
380 LLT DstTy =
MRI.getType(DstReg);
382 if (Opcode == TargetOpcode::G_ANYEXT) {
384 if (!isInstLegal({TargetOpcode::G_IMPLICIT_DEF, {DstTy}}))
387 Builder.
buildInstr(TargetOpcode::G_IMPLICIT_DEF, {DstReg}, {});
392 if (isConstantUnsupported(DstTy))
399 markInstAndDefDead(
MI, *
DefMI, DeadInsts);
409 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
411 const unsigned CastOpc = CastMI.
getOpcode();
413 if (!isArtifactCast(CastOpc))
416 const unsigned NumDefs =
MI.getNumOperands() - 1;
419 const LLT CastSrcTy =
MRI.getType(CastSrcReg);
420 const LLT DestTy =
MRI.getType(
MI.getOperand(0).getReg());
421 const LLT SrcTy =
MRI.getType(
MI.getOperand(NumDefs).getReg());
426 if (CastOpc == TargetOpcode::G_TRUNC) {
437 unsigned UnmergeNumElts =
444 if (isInstUnsupported(
445 {TargetOpcode::G_UNMERGE_VALUES, {UnmergeTy, CastSrcTy}}) ||
446 LI.
getAction({TargetOpcode::G_TRUNC, {SrcWideTy, UnmergeTy}})
451 auto NewUnmerge = Builder.
buildUnmerge(UnmergeTy, CastSrcReg);
453 for (
unsigned I = 0;
I != NumDefs; ++
I) {
459 markInstAndDefDead(
MI, CastMI, DeadInsts);
471 if (CastSrcSize % DestSize != 0)
475 if (isInstUnsupported(
476 {TargetOpcode::G_UNMERGE_VALUES, {DestTy, CastSrcTy}}))
481 const unsigned NewNumDefs = CastSrcSize / DestSize;
483 for (
unsigned Idx = 0;
Idx < NewNumDefs; ++
Idx) {
485 DstRegs[
Idx] =
MI.getOperand(
Idx).getReg();
487 DstRegs[
Idx] =
MRI.createGenericVirtualRegister(DestTy);
494 markInstAndDefDead(
MI, CastMI, DeadInsts);
509 case TargetOpcode::G_BUILD_VECTOR:
510 case TargetOpcode::G_MERGE_VALUES:
537 case TargetOpcode::G_CONCAT_VECTORS: {
548 if (ConvertOp == TargetOpcode::G_TRUNC)
569 for (
auto &
UseMI :
MRI.use_instructions(DstReg)) {
574 MRI.replaceRegWith(DstReg, SrcReg);
577 for (
auto *
UseMI : UseMIs)
585 if (Def.getReg() == SearchDef)
616 unsigned SrcSize =
MRI.getType(Src1Reg).getSizeInBits();
619 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
621 unsigned InRegOffset = StartBit % SrcSize;
625 if (InRegOffset +
Size > SrcSize)
629 if (InRegOffset == 0 &&
Size == SrcSize) {
630 CurrentBest = SrcReg;
631 return findValueFromDefImpl(SrcReg, 0,
Size);
634 return findValueFromDefImpl(SrcReg, InRegOffset,
Size);
648 unsigned SrcSize =
MRI.getType(Src1Reg).getSizeInBits();
651 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
653 unsigned InRegOffset = StartBit % SrcSize;
655 if (InRegOffset != 0)
662 if (
Size > SrcSize) {
663 if (
Size % SrcSize > 0)
666 unsigned NumSrcsUsed =
Size / SrcSize;
671 LLT SrcTy =
MRI.getType(Src1Reg);
672 LLT NewBVTy = LLT::fixed_vector(NumSrcsUsed, SrcTy);
676 LI.
getAction({TargetOpcode::G_BUILD_VECTOR, {NewBVTy, SrcTy}});
677 if (ActionStep.
Action != LegalizeActions::Legal)
681 for (
unsigned SrcIdx = StartSrcIdx; SrcIdx < StartSrcIdx + NumSrcsUsed;
688 return BV.
getReg(StartSrcIdx);
698 assert(
MI.getOpcode() == TargetOpcode::G_INSERT);
701 Register ContainerSrcReg =
MI.getOperand(1).getReg();
702 Register InsertedReg =
MI.getOperand(2).getReg();
703 LLT InsertedRegTy =
MRI.getType(InsertedReg);
704 unsigned InsertOffset =
MI.getOperand(3).getImm();
742 unsigned InsertedEndBit = InsertOffset + InsertedRegTy.
getSizeInBits();
743 unsigned EndBit = StartBit +
Size;
744 unsigned NewStartBit;
746 if (EndBit <= InsertOffset || InsertedEndBit <= StartBit) {
747 SrcRegToUse = ContainerSrcReg;
748 NewStartBit = StartBit;
749 return findValueFromDefImpl(SrcRegToUse, NewStartBit,
Size);
751 if (InsertOffset <= StartBit && EndBit <= InsertedEndBit) {
752 SrcRegToUse = InsertedReg;
753 NewStartBit = StartBit - InsertOffset;
754 if (NewStartBit == 0 &&
755 Size ==
MRI.getType(SrcRegToUse).getSizeInBits())
756 CurrentBest = SrcRegToUse;
757 return findValueFromDefImpl(SrcRegToUse, NewStartBit,
Size);
771 assert(
MI.getOpcode() == TargetOpcode::G_SEXT ||
772 MI.getOpcode() == TargetOpcode::G_ZEXT ||
773 MI.getOpcode() == TargetOpcode::G_ANYEXT);
777 LLT SrcType =
MRI.getType(SrcReg);
784 if (StartBit +
Size > SrcSize)
788 CurrentBest = SrcReg;
789 return findValueFromDefImpl(SrcReg, StartBit,
Size);
799 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC);
803 LLT SrcType =
MRI.getType(SrcReg);
809 return findValueFromDefImpl(SrcReg, StartBit,
Size);
817 std::optional<DefinitionAndSourceRegister> DefSrcReg =
820 DefReg = DefSrcReg->Reg;
824 switch (Def->getOpcode()) {
825 case TargetOpcode::G_CONCAT_VECTORS:
826 return findValueFromConcat(cast<GConcatVectors>(*Def), StartBit,
Size);
827 case TargetOpcode::G_UNMERGE_VALUES: {
828 unsigned DefStartBit = 0;
829 unsigned DefSize =
MRI.getType(DefReg).getSizeInBits();
830 for (
const auto &MO : Def->defs()) {
831 if (MO.getReg() == DefReg)
833 DefStartBit += DefSize;
835 Register SrcReg = Def->getOperand(Def->getNumOperands() - 1).getReg();
837 findValueFromDefImpl(SrcReg, StartBit + DefStartBit,
Size);
843 if (StartBit == 0 &&
Size == DefSize)
847 case TargetOpcode::G_BUILD_VECTOR:
848 return findValueFromBuildVector(cast<GBuildVector>(*Def), StartBit,
850 case TargetOpcode::G_INSERT:
851 return findValueFromInsert(*Def, StartBit,
Size);
852 case TargetOpcode::G_TRUNC:
853 return findValueFromTrunc(*Def, StartBit,
Size);
854 case TargetOpcode::G_SEXT:
855 case TargetOpcode::G_ZEXT:
856 case TargetOpcode::G_ANYEXT:
857 return findValueFromExt(*Def, StartBit,
Size);
866 :
MRI(Mri), MIB(Builder), LI(
Info) {}
875 Register FoundReg = findValueFromDefImpl(DefReg, StartBit,
Size);
876 return FoundReg != DefReg ? FoundReg :
Register();
884 unsigned NumDefs =
MI.getNumDefs();
885 LLT DestTy =
MRI.getType(
MI.getReg(0));
888 for (
unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
890 if (
MRI.use_nodbg_empty(DefReg)) {
891 DeadDefs[DefIdx] =
true;
897 if (
MRI.getType(FoundVal) != DestTy)
900 replaceRegOrBuildCopy(DefReg, FoundVal,
MRI, MIB, UpdatedDefs,
904 MI.getOperand(DefIdx).setReg(DefReg);
906 DeadDefs[DefIdx] =
true;
908 return DeadDefs.
all();
912 unsigned &DefOperandIdx) {
914 if (
auto *Unmerge = dyn_cast<GUnmerge>(
MRI.getVRegDef(Def))) {
916 Unmerge->findRegisterDefOperandIdx(Def,
nullptr);
927 GUnmerge *Unmerge,
unsigned UnmergeIdxStart,
928 unsigned NumElts,
unsigned EltSize,
930 assert(MergeStartIdx + NumElts <=
MI.getNumSources());
931 for (
unsigned i = MergeStartIdx; i < MergeStartIdx + NumElts; ++i) {
932 unsigned EltUnmergeIdx;
933 GUnmerge *EltUnmerge = findUnmergeThatDefinesReg(
934 MI.getSourceReg(i), EltSize, EltUnmergeIdx);
936 if (EltUnmerge == Unmerge) {
938 if (i - MergeStartIdx != EltUnmergeIdx - UnmergeIdxStart)
940 }
else if (!AllowUndef ||
941 MRI.getVRegDef(
MI.getSourceReg(i))->getOpcode() !=
942 TargetOpcode::G_IMPLICIT_DEF)
953 LLT EltTy =
MRI.getType(Elt0);
956 unsigned Elt0UnmergeIdx;
958 auto *Unmerge = findUnmergeThatDefinesReg(Elt0, EltSize, Elt0UnmergeIdx);
962 unsigned NumMIElts =
MI.getNumSources();
964 LLT DstTy =
MRI.getType(Dst);
965 Register UnmergeSrc = Unmerge->getSourceReg();
966 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
975 if ((DstTy == UnmergeSrcTy) && (Elt0UnmergeIdx == 0)) {
976 if (!isSequenceFromUnmerge(
MI, 0, Unmerge, 0, NumMIElts, EltSize,
980 replaceRegOrBuildCopy(Dst, UnmergeSrc,
MRI, MIB, UpdatedDefs, Observer);
996 (Elt0UnmergeIdx % NumMIElts == 0) &&
997 getCoverTy(UnmergeSrcTy, DstTy) == UnmergeSrcTy) {
998 if (!isSequenceFromUnmerge(
MI, 0, Unmerge, Elt0UnmergeIdx, NumMIElts,
1002 auto NewUnmerge = MIB.
buildUnmerge(DstTy, Unmerge->getSourceReg());
1003 unsigned DstIdx = (Elt0UnmergeIdx * EltSize) / DstTy.
getSizeInBits();
1004 replaceRegOrBuildCopy(Dst, NewUnmerge.getReg(DstIdx),
MRI, MIB,
1005 UpdatedDefs, Observer);
1023 unsigned NumElts = Unmerge->getNumDefs();
1024 for (
unsigned i = 0; i <
MI.getNumSources(); i += NumElts) {
1025 unsigned EltUnmergeIdx;
1026 auto *UnmergeI = findUnmergeThatDefinesReg(
MI.getSourceReg(i),
1027 EltSize, EltUnmergeIdx);
1029 if ((!UnmergeI) || (UnmergeI->getNumDefs() != NumElts) ||
1030 (EltUnmergeIdx != 0))
1032 if (!isSequenceFromUnmerge(
MI, i, UnmergeI, 0, NumElts, EltSize,
1035 ConcatSources.
push_back(UnmergeI->getSourceReg());
1052 unsigned NumDefs =
MI.getNumDefs();
1058 LLT OpTy =
MRI.getType(SrcReg);
1059 LLT DestTy =
MRI.getType(
MI.getReg(0));
1060 unsigned SrcDefIdx = getDefIndex(*SrcDef, SrcReg);
1062 Builder.setInstrAndDebugLoc(
MI);
1066 markInstAndDefDead(
MI, *SrcDef, DeadInsts, SrcDefIdx);
1070 if (
auto *SrcUnmerge = dyn_cast<GUnmerge>(SrcDef)) {
1076 Register SrcUnmergeSrc = SrcUnmerge->getSourceReg();
1077 LLT SrcUnmergeSrcTy =
MRI.getType(SrcUnmergeSrc);
1083 {TargetOpcode::G_UNMERGE_VALUES, {OpTy, SrcUnmergeSrcTy}});
1084 switch (ActionStep.
Action) {
1097 auto NewUnmerge = Builder.buildUnmerge(DestTy, SrcUnmergeSrc);
1102 for (
unsigned I = 0;
I != NumDefs; ++
I) {
1104 replaceRegOrBuildCopy(Def, NewUnmerge.getReg(SrcDefIdx * NumDefs +
I),
1105 MRI, Builder, UpdatedDefs, Observer);
1108 markInstAndDefDead(
MI, *SrcUnmerge, DeadInsts, SrcDefIdx);
1113 unsigned ConvertOp = 0;
1117 if (isArtifactCast(
SrcOp)) {
1122 if (!MergeI || !canFoldMergeOpcode(MergeI->
getOpcode(),
1123 ConvertOp, OpTy, DestTy)) {
1126 return tryFoldUnmergeCast(
MI, *SrcDef, DeadInsts, UpdatedDefs);
1131 if (NumMergeRegs < NumDefs) {
1132 if (NumDefs % NumMergeRegs != 0)
1135 Builder.setInstr(
MI);
1143 const unsigned NewNumDefs = NumDefs / NumMergeRegs;
1144 for (
unsigned Idx = 0;
Idx < NumMergeRegs; ++
Idx) {
1146 for (
unsigned j = 0, DefIdx =
Idx * NewNumDefs; j < NewNumDefs;
1156 LLT MergeEltTy = MergeDstTy.
divide(NumMergeRegs);
1171 Register TmpReg =
MRI.createGenericVirtualRegister(MergeEltTy);
1172 Builder.buildInstr(ConvertOp, {TmpReg},
1174 Builder.buildUnmerge(DstRegs, TmpReg);
1181 }
else if (NumMergeRegs > NumDefs) {
1182 if (ConvertOp != 0 || NumMergeRegs % NumDefs != 0)
1185 Builder.setInstr(
MI);
1193 const unsigned NumRegs = NumMergeRegs / NumDefs;
1194 for (
unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
1196 for (
unsigned j = 0,
Idx = NumRegs * DefIdx + 1; j < NumRegs;
1201 Builder.buildMergeLikeInstr(DefReg, Regs);
1208 if (!ConvertOp && DestTy != MergeSrcTy)
1209 ConvertOp = TargetOpcode::G_BITCAST;
1212 Builder.setInstr(
MI);
1214 for (
unsigned Idx = 0;
Idx < NumDefs; ++
Idx) {
1218 if (!
MRI.use_empty(DefReg)) {
1219 Builder.buildInstr(ConvertOp, {DefReg}, {MergeSrc});
1224 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1228 assert(DestTy == MergeSrcTy &&
1229 "Bitcast and the other kinds of conversions should "
1230 "have happened earlier");
1232 Builder.setInstr(
MI);
1233 for (
unsigned Idx = 0;
Idx < NumDefs; ++
Idx) {
1236 replaceRegOrBuildCopy(DstReg, SrcReg,
MRI, Builder, UpdatedDefs,
1241 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1248 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT);
1262 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
1264 if (!MergeI || !isa<GMergeLikeInstr>(MergeI))
1268 LLT DstTy =
MRI.getType(DstReg);
1269 LLT SrcTy =
MRI.getType(SrcReg);
1273 unsigned Offset =
MI.getOperand(2).getImm();
1275 unsigned MergeSrcSize = SrcTy.
getSizeInBits() / NumMergeSrcs;
1276 unsigned MergeSrcIdx =
Offset / MergeSrcSize;
1279 unsigned EndMergeSrcIdx = (
Offset + ExtractDstSize - 1) / MergeSrcSize;
1282 if (MergeSrcIdx != EndMergeSrcIdx)
1286 Builder.setInstr(
MI);
1288 Offset - MergeSrcIdx * MergeSrcSize);
1290 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1306 if (!DeadInsts.
empty())
1307 deleteMarkedDeadInsts(DeadInsts, WrapperObserver);
1314 bool Changed =
false;
1315 switch (
MI.getOpcode()) {
1318 case TargetOpcode::G_ANYEXT:
1319 Changed = tryCombineAnyExt(
MI, DeadInsts, UpdatedDefs, WrapperObserver);
1321 case TargetOpcode::G_ZEXT:
1322 Changed = tryCombineZExt(
MI, DeadInsts, UpdatedDefs, WrapperObserver);
1324 case TargetOpcode::G_SEXT:
1325 Changed = tryCombineSExt(
MI, DeadInsts, UpdatedDefs);
1327 case TargetOpcode::G_UNMERGE_VALUES:
1328 Changed = tryCombineUnmergeValues(cast<GUnmerge>(
MI), DeadInsts,
1329 UpdatedDefs, WrapperObserver);
1331 case TargetOpcode::G_MERGE_VALUES:
1332 case TargetOpcode::G_BUILD_VECTOR:
1333 case TargetOpcode::G_CONCAT_VECTORS:
1337 if (U.getOpcode() == TargetOpcode::G_UNMERGE_VALUES ||
1338 U.getOpcode() == TargetOpcode::G_TRUNC) {
1344 UpdatedDefs, WrapperObserver);
1346 case TargetOpcode::G_EXTRACT:
1347 Changed = tryCombineExtract(
MI, DeadInsts, UpdatedDefs);
1349 case TargetOpcode::G_TRUNC:
1350 Changed = tryCombineTrunc(
MI, DeadInsts, UpdatedDefs, WrapperObserver);
1364 while (!UpdatedDefs.
empty()) {
1368 switch (
Use.getOpcode()) {
1370 case TargetOpcode::G_ANYEXT:
1371 case TargetOpcode::G_ZEXT:
1372 case TargetOpcode::G_SEXT:
1373 case TargetOpcode::G_UNMERGE_VALUES:
1374 case TargetOpcode::G_EXTRACT:
1375 case TargetOpcode::G_TRUNC:
1376 case TargetOpcode::G_BUILD_VECTOR:
1380 case TargetOpcode::G_ASSERT_SEXT:
1381 case TargetOpcode::G_ASSERT_ZEXT:
1382 case TargetOpcode::G_ASSERT_ALIGN:
1383 case TargetOpcode::COPY: {
1385 if (Copy.isVirtual())
1402 switch (
MI.getOpcode()) {
1403 case TargetOpcode::COPY:
1404 case TargetOpcode::G_TRUNC:
1405 case TargetOpcode::G_ZEXT:
1406 case TargetOpcode::G_ANYEXT:
1407 case TargetOpcode::G_SEXT:
1408 case TargetOpcode::G_EXTRACT:
1409 case TargetOpcode::G_ASSERT_SEXT:
1410 case TargetOpcode::G_ASSERT_ZEXT:
1411 case TargetOpcode::G_ASSERT_ALIGN:
1412 return MI.getOperand(1).getReg();
1413 case TargetOpcode::G_UNMERGE_VALUES:
1414 return MI.getOperand(
MI.getNumOperands() - 1).getReg();
1427 unsigned DefIdx = 0) {
1438 while (PrevMI != &
DefMI) {
1439 Register PrevRegSrc = getArtifactSrcReg(*PrevMI);
1442 if (
MRI.hasOneUse(PrevRegSrc)) {
1443 if (TmpDef != &
DefMI) {
1447 "Expecting copy or artifact cast here");
1456 if (PrevMI == &
DefMI) {
1461 if (!
MRI.use_empty(
Def.getReg())) {
1485 unsigned DefIdx = 0) {
1487 markDefDead(
MI,
DefMI, DeadInsts, DefIdx);
1498 for (
auto *DeadMI : DeadInsts) {
1501 DeadMI->eraseFromParent();
1509 using namespace LegalizeActions;
1510 auto Step = LI.getAction(Query);
1518 bool isConstantUnsupported(
LLT Ty)
const {
1520 return isInstUnsupported({TargetOpcode::G_CONSTANT, {Ty}});
1523 return isInstUnsupported({TargetOpcode::G_CONSTANT, {EltTy}}) ||
1524 isInstUnsupported({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}});
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Analysis containing CSE Info
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This contains common code to allow clients to notify changes to machine instr.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
Interface for Targets to specify which operations they can successfully select and how the others sho...
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Promote Memory to Register
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements the SmallBitVector class.
static constexpr int Concat[]
Class for arbitrary precision integers.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
APInt zext(unsigned width) const
Zero extend to a new width.
static DILocation * getMergedLocation(DILocation *LocA, DILocation *LocB)
When two instructions are combined into a single instruction we also need to combine the original loc...
static constexpr ElementCount getFixed(ScalarTy MinVal)
Represents a G_BUILD_VECTOR.
Represents a G_CONCAT_VECTORS.
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
APInt getKnownZeroes(Register R)
Simple wrapper observer that takes several observers, and calls each one for each event.
void changedInstr(MachineInstr &MI) override
This instruction was mutated in some way.
void changingInstr(MachineInstr &MI) override
This instruction is about to be mutated in some way.
void erasingInstr(MachineInstr &MI) override
An instruction is about to be erased.
Represents G_BUILD_VECTOR, G_CONCAT_VECTORS or G_MERGE_VALUES.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents a G_UNMERGE_VALUES.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
constexpr LLT changeElementCount(ElementCount EC) const
Return a vector or scalar with the same element type and the new element count.
constexpr LLT getScalarType() const
constexpr LLT divide(int Factor) const
Return a type that is Factor times smaller.
This class provides utilities for finding source registers of specific bit ranges in an artifact.
bool tryCombineUnmergeDefs(GUnmerge &MI, GISelChangeObserver &Observer, SmallVectorImpl< Register > &UpdatedDefs)
Try to combine the defs of an unmerge MI by attempting to find values that provides the bits for each...
bool isSequenceFromUnmerge(GMergeLikeInstr &MI, unsigned MergeStartIdx, GUnmerge *Unmerge, unsigned UnmergeIdxStart, unsigned NumElts, unsigned EltSize, bool AllowUndef)
Register findValueFromDef(Register DefReg, unsigned StartBit, unsigned Size)
Try to find a source of the value defined in the def DefReg, starting at position StartBit with size ...
GUnmerge * findUnmergeThatDefinesReg(Register Reg, unsigned Size, unsigned &DefOperandIdx)
bool tryCombineMergeLike(GMergeLikeInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs, GISelChangeObserver &Observer)
ArtifactValueFinder(MachineRegisterInfo &Mri, MachineIRBuilder &Builder, const LegalizerInfo &Info)
LegalizationArtifactCombiner(MachineIRBuilder &B, MachineRegisterInfo &MRI, const LegalizerInfo &LI, GISelKnownBits *KB=nullptr)
bool tryFoldUnmergeCast(MachineInstr &MI, MachineInstr &CastMI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs)
bool tryCombineZExt(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs, GISelObserverWrapper &Observer)
bool tryCombineInstruction(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, GISelObserverWrapper &WrapperObserver)
Try to combine away MI.
bool tryCombineTrunc(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs, GISelObserverWrapper &Observer)
static bool canFoldMergeOpcode(unsigned MergeOp, unsigned ConvertOp, LLT OpTy, LLT DestTy)
bool tryCombineSExt(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs)
static unsigned getDefIndex(const MachineInstr &MI, Register SearchDef)
Return the operand index in MI that defines Def.
static void replaceRegOrBuildCopy(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI, MachineIRBuilder &Builder, SmallVectorImpl< Register > &UpdatedDefs, GISelChangeObserver &Observer)
Try to replace DstReg with SrcReg or build a COPY instruction depending on the register constraints.
bool tryCombineUnmergeValues(GUnmerge &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs, GISelChangeObserver &Observer)
bool tryCombineExtract(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs)
bool tryFoldImplicitDef(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs)
Try to fold G_[ASZ]EXT (G_IMPLICIT_DEF).
bool tryCombineAnyExt(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs, GISelObserverWrapper &Observer)
LegalizeActionStep getAction(const LegalityQuery &Query) const
Determine what action should be taken to legalize the described instruction.
Helper class to build MachineInstr.
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildAnyExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Res = COPY Op depending on the differing sizes of Res and Op.
MachineInstrBuilder buildSExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_SEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildMergeLikeInstr(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ... or Res = G_BUILD_VECTOR Op0, ... or Res = G_CONCAT_VEC...
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
MachineInstrBuilder buildMergeValues(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ...
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
void setDebugLoc(const DebugLoc &DL)
Set the debug location to DL for all the next build instructions.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
MachineInstrBuilder buildSExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and insert Res = G_SEXT_INREG Op, ImmOp.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
bool all() const
Returns true if all bits are set.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A Use represents the edge between a Value definition and its users.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Unsupported
This operation is completely unsupported on the target.
@ NotFound
Sentinel value for when no action was found in the specified table.
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ Unsupported
This operation is completely unsupported on the target.
@ Lower
The operation itself must be expressed in terms of simpler actions on this target.
@ NarrowScalar
The operation should be synthesized from multiple instructions acting on a narrower scalar base-type.
@ MoreElements
The (vector) operation should be implemented by widening the input vector and ignoring the lanes adde...
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
bool isPreISelGenericOptimizationHint(unsigned Opcode)
bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_READNONE LLT getCoverTy(LLT OrigTy, LLT TargetTy)
Return smallest type that covers both OrigTy and TargetTy and is multiple of TargetTy.
std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
LegalizeAction Action
The action to take or the final answer.
unsigned TypeIdx
If describing an action, the type index to change. Otherwise zero.