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);
198 assert(
MI.getOpcode() == TargetOpcode::G_SEXT);
202 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
206 if (mi_match(SrcReg,
MRI, m_GTrunc(m_Reg(TruncSrc)))) {
207 LLT DstTy =
MRI.getType(DstReg);
208 if (isInstUnsupported({TargetOpcode::G_SEXT_INREG, {DstTy}}))
211 LLT SrcTy =
MRI.getType(SrcReg);
213 if (DstTy !=
MRI.getType(TruncSrc))
223 markInstAndDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
231 if (mi_match(SrcReg,
MRI,
232 m_all_of(m_MInstr(ExtMI), m_any_of(m_GZExt(m_Reg(ExtSrc)),
233 m_GSExt(m_Reg(ExtSrc)))))) {
237 markInstAndDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
242 auto *SrcMI =
MRI.getVRegDef(SrcReg);
243 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
244 const LLT DstTy =
MRI.getType(DstReg);
245 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
246 auto &CstVal = SrcMI->getOperand(1);
248 DstReg, CstVal.getCImm()->getValue().sext(DstTy.
getSizeInBits()));
250 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
263 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC);
267 const LLT DstTy =
MRI.getType(DstReg);
268 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
271 auto *SrcMI =
MRI.getVRegDef(SrcReg);
272 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
273 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
274 auto &CstVal = SrcMI->getOperand(1);
276 DstReg, CstVal.getCImm()->getValue().trunc(DstTy.
getSizeInBits()));
278 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
285 if (
auto *SrcMerge = dyn_cast<GMerge>(SrcMI)) {
286 const Register MergeSrcReg = SrcMerge->getSourceReg(0);
287 const LLT MergeSrcTy =
MRI.getType(MergeSrcReg);
295 if (DstSize < MergeSrcSize) {
298 if (isInstUnsupported({TargetOpcode::G_TRUNC, {DstTy, MergeSrcTy}}))
301 LLVM_DEBUG(
dbgs() <<
"Combining G_TRUNC(G_MERGE_VALUES) to G_TRUNC: "
306 }
else if (DstSize == MergeSrcSize) {
309 dbgs() <<
"Replacing G_TRUNC(G_MERGE_VALUES) with merge input: "
313 }
else if (DstSize % MergeSrcSize == 0) {
316 if (isInstUnsupported(
317 {TargetOpcode::G_MERGE_VALUES, {DstTy, MergeSrcTy}}))
321 dbgs() <<
"Combining G_TRUNC(G_MERGE_VALUES) to G_MERGE_VALUES: "
324 const unsigned NumSrcs = DstSize / MergeSrcSize;
325 assert(NumSrcs < SrcMI->getNumOperands() - 1 &&
326 "trunc(merge) should require less inputs than merge");
328 for (
unsigned i = 0; i < NumSrcs; ++i)
329 SrcRegs[i] = SrcMerge->getSourceReg(i);
338 markInstAndDefDead(
MI, *SrcMerge, DeadInsts);
344 if (mi_match(SrcReg,
MRI, m_GTrunc(m_Reg(TruncSrc)))) {
352 markInstAndDefDead(
MI, *
MRI.getVRegDef(TruncSrc), DeadInsts);
360 LLT FoundRegTy =
MRI.getType(FoundReg);
361 if (DstTy == FoundRegTy) {
362 LLVM_DEBUG(
dbgs() <<
".. Combine G_TRUNC(G_[S,Z,ANY]EXT/G_TRUNC...): "
368 markInstAndDefDead(
MI, *
MRI.getVRegDef(SrcReg), DeadInsts);
381 unsigned Opcode =
MI.getOpcode();
382 assert(Opcode == TargetOpcode::G_ANYEXT || Opcode == TargetOpcode::G_ZEXT ||
383 Opcode == TargetOpcode::G_SEXT);
386 MI.getOperand(1).getReg(),
MRI)) {
389 LLT DstTy =
MRI.getType(DstReg);
391 if (Opcode == TargetOpcode::G_ANYEXT) {
393 if (!isInstLegal({TargetOpcode::G_IMPLICIT_DEF, {DstTy}}))
403 if (isConstantUnsupported(DstTy))
412 markInstAndDefDead(
MI, *
DefMI, DeadInsts);
422 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
424 const unsigned CastOpc = CastMI.
getOpcode();
426 if (!isArtifactCast(CastOpc))
429 const unsigned NumDefs =
MI.getNumOperands() - 1;
432 const LLT CastSrcTy =
MRI.getType(CastSrcReg);
433 const LLT DestTy =
MRI.getType(
MI.getOperand(0).getReg());
434 const LLT SrcTy =
MRI.getType(
MI.getOperand(NumDefs).getReg());
439 if (CastOpc == TargetOpcode::G_TRUNC) {
450 unsigned UnmergeNumElts =
457 if (isInstUnsupported(
458 {TargetOpcode::G_UNMERGE_VALUES, {UnmergeTy, CastSrcTy}}) ||
459 LI.
getAction({TargetOpcode::G_TRUNC, {SrcWideTy, UnmergeTy}})
464 auto NewUnmerge = Builder.
buildUnmerge(UnmergeTy, CastSrcReg);
466 for (
unsigned I = 0;
I != NumDefs; ++
I) {
472 markInstAndDefDead(
MI, CastMI, DeadInsts);
484 if (CastSrcSize % DestSize != 0)
488 if (isInstUnsupported(
489 {TargetOpcode::G_UNMERGE_VALUES, {DestTy, CastSrcTy}}))
494 const unsigned NewNumDefs = CastSrcSize / DestSize;
496 for (
unsigned Idx = 0;
Idx < NewNumDefs; ++
Idx) {
498 DstRegs[
Idx] =
MI.getOperand(
Idx).getReg();
500 DstRegs[
Idx] =
MRI.createGenericVirtualRegister(DestTy);
507 markInstAndDefDead(
MI, CastMI, DeadInsts);
522 case TargetOpcode::G_BUILD_VECTOR:
523 case TargetOpcode::G_MERGE_VALUES:
550 case TargetOpcode::G_CONCAT_VECTORS: {
561 if (ConvertOp == TargetOpcode::G_TRUNC)
582 for (
auto &
UseMI :
MRI.use_instructions(DstReg)) {
587 MRI.replaceRegWith(DstReg, SrcReg);
590 for (
auto *
UseMI : UseMIs)
598 if (Def.getReg() == SearchDef)
629 unsigned SrcSize =
MRI.getType(Src1Reg).getSizeInBits();
632 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
634 unsigned InRegOffset = StartBit % SrcSize;
638 if (InRegOffset +
Size > SrcSize)
642 if (InRegOffset == 0 &&
Size == SrcSize) {
643 CurrentBest = SrcReg;
644 return findValueFromDefImpl(SrcReg, 0,
Size);
647 return findValueFromDefImpl(SrcReg, InRegOffset,
Size);
661 unsigned SrcSize =
MRI.getType(Src1Reg).getSizeInBits();
664 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
666 unsigned InRegOffset = StartBit % SrcSize;
668 if (InRegOffset != 0)
675 if (
Size > SrcSize) {
676 if (
Size % SrcSize > 0)
679 unsigned NumSrcsUsed =
Size / SrcSize;
684 LLT SrcTy =
MRI.getType(Src1Reg);
685 LLT NewBVTy = LLT::fixed_vector(NumSrcsUsed, SrcTy);
689 LI.
getAction({TargetOpcode::G_BUILD_VECTOR, {NewBVTy, SrcTy}});
690 if (ActionStep.
Action != LegalizeActions::Legal)
694 for (
unsigned SrcIdx = StartSrcIdx; SrcIdx < StartSrcIdx + NumSrcsUsed;
701 return BV.
getReg(StartSrcIdx);
711 assert(
MI.getOpcode() == TargetOpcode::G_INSERT);
714 Register ContainerSrcReg =
MI.getOperand(1).getReg();
715 Register InsertedReg =
MI.getOperand(2).getReg();
716 LLT InsertedRegTy =
MRI.getType(InsertedReg);
717 unsigned InsertOffset =
MI.getOperand(3).getImm();
755 unsigned InsertedEndBit = InsertOffset + InsertedRegTy.
getSizeInBits();
756 unsigned EndBit = StartBit +
Size;
757 unsigned NewStartBit;
759 if (EndBit <= InsertOffset || InsertedEndBit <= StartBit) {
760 SrcRegToUse = ContainerSrcReg;
761 NewStartBit = StartBit;
762 return findValueFromDefImpl(SrcRegToUse, NewStartBit,
Size);
764 if (InsertOffset <= StartBit && EndBit <= InsertedEndBit) {
765 SrcRegToUse = InsertedReg;
766 NewStartBit = StartBit - InsertOffset;
767 if (NewStartBit == 0 &&
768 Size ==
MRI.getType(SrcRegToUse).getSizeInBits())
769 CurrentBest = SrcRegToUse;
770 return findValueFromDefImpl(SrcRegToUse, NewStartBit,
Size);
784 assert(
MI.getOpcode() == TargetOpcode::G_SEXT ||
785 MI.getOpcode() == TargetOpcode::G_ZEXT ||
786 MI.getOpcode() == TargetOpcode::G_ANYEXT);
790 LLT SrcType =
MRI.getType(SrcReg);
797 if (StartBit +
Size > SrcSize)
801 CurrentBest = SrcReg;
802 return findValueFromDefImpl(SrcReg, StartBit,
Size);
812 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC);
816 LLT SrcType =
MRI.getType(SrcReg);
822 return findValueFromDefImpl(SrcReg, StartBit,
Size);
830 std::optional<DefinitionAndSourceRegister> DefSrcReg =
833 DefReg = DefSrcReg->Reg;
837 switch (Def->getOpcode()) {
838 case TargetOpcode::G_CONCAT_VECTORS:
839 return findValueFromConcat(cast<GConcatVectors>(*Def), StartBit,
Size);
840 case TargetOpcode::G_UNMERGE_VALUES: {
841 unsigned DefStartBit = 0;
842 unsigned DefSize =
MRI.getType(DefReg).getSizeInBits();
843 for (
const auto &MO : Def->defs()) {
844 if (MO.getReg() == DefReg)
846 DefStartBit += DefSize;
848 Register SrcReg = Def->getOperand(Def->getNumOperands() - 1).getReg();
850 findValueFromDefImpl(SrcReg, StartBit + DefStartBit,
Size);
856 if (StartBit == 0 &&
Size == DefSize)
860 case TargetOpcode::G_BUILD_VECTOR:
861 return findValueFromBuildVector(cast<GBuildVector>(*Def), StartBit,
863 case TargetOpcode::G_INSERT:
864 return findValueFromInsert(*Def, StartBit,
Size);
865 case TargetOpcode::G_TRUNC:
866 return findValueFromTrunc(*Def, StartBit,
Size);
867 case TargetOpcode::G_SEXT:
868 case TargetOpcode::G_ZEXT:
869 case TargetOpcode::G_ANYEXT:
870 return findValueFromExt(*Def, StartBit,
Size);
879 :
MRI(Mri), MIB(Builder), LI(
Info) {}
888 Register FoundReg = findValueFromDefImpl(DefReg, StartBit,
Size);
889 return FoundReg != DefReg ? FoundReg :
Register();
897 unsigned NumDefs =
MI.getNumDefs();
898 LLT DestTy =
MRI.getType(
MI.getReg(0));
901 for (
unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
903 if (
MRI.use_nodbg_empty(DefReg)) {
904 DeadDefs[DefIdx] =
true;
910 if (
MRI.getType(FoundVal) != DestTy)
913 replaceRegOrBuildCopy(DefReg, FoundVal,
MRI, MIB, UpdatedDefs,
917 MI.getOperand(DefIdx).setReg(DefReg);
919 DeadDefs[DefIdx] =
true;
921 return DeadDefs.
all();
925 unsigned &DefOperandIdx) {
927 if (
auto *Unmerge = dyn_cast<GUnmerge>(
MRI.getVRegDef(Def))) {
929 Unmerge->findRegisterDefOperandIdx(Def,
nullptr);
940 GUnmerge *Unmerge,
unsigned UnmergeIdxStart,
941 unsigned NumElts,
unsigned EltSize,
943 assert(MergeStartIdx + NumElts <=
MI.getNumSources());
944 for (
unsigned i = MergeStartIdx; i < MergeStartIdx + NumElts; ++i) {
945 unsigned EltUnmergeIdx;
946 GUnmerge *EltUnmerge = findUnmergeThatDefinesReg(
947 MI.getSourceReg(i), EltSize, EltUnmergeIdx);
949 if (EltUnmerge == Unmerge) {
951 if (i - MergeStartIdx != EltUnmergeIdx - UnmergeIdxStart)
953 }
else if (!AllowUndef ||
954 MRI.getVRegDef(
MI.getSourceReg(i))->getOpcode() !=
955 TargetOpcode::G_IMPLICIT_DEF)
966 LLT EltTy =
MRI.getType(Elt0);
969 unsigned Elt0UnmergeIdx;
971 auto *Unmerge = findUnmergeThatDefinesReg(Elt0, EltSize, Elt0UnmergeIdx);
975 unsigned NumMIElts =
MI.getNumSources();
977 LLT DstTy =
MRI.getType(Dst);
978 Register UnmergeSrc = Unmerge->getSourceReg();
979 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
988 if ((DstTy == UnmergeSrcTy) && (Elt0UnmergeIdx == 0)) {
989 if (!isSequenceFromUnmerge(
MI, 0, Unmerge, 0, NumMIElts, EltSize,
993 replaceRegOrBuildCopy(Dst, UnmergeSrc,
MRI, MIB, UpdatedDefs, Observer);
1009 (Elt0UnmergeIdx % NumMIElts == 0) &&
1010 getCoverTy(UnmergeSrcTy, DstTy) == UnmergeSrcTy) {
1011 if (!isSequenceFromUnmerge(
MI, 0, Unmerge, Elt0UnmergeIdx, NumMIElts,
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);
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);
1042 if ((!UnmergeI) || (UnmergeI->getNumDefs() != NumElts) ||
1043 (EltUnmergeIdx != 0))
1045 if (!isSequenceFromUnmerge(
MI, i, UnmergeI, 0, NumElts, EltSize,
1048 ConcatSources.
push_back(UnmergeI->getSourceReg());
1065 unsigned NumDefs =
MI.getNumDefs();
1071 LLT OpTy =
MRI.getType(SrcReg);
1072 LLT DestTy =
MRI.getType(
MI.getReg(0));
1073 unsigned SrcDefIdx = getDefIndex(*SrcDef, SrcReg);
1075 Builder.setInstrAndDebugLoc(
MI);
1079 markInstAndDefDead(
MI, *SrcDef, DeadInsts, SrcDefIdx);
1083 if (
auto *SrcUnmerge = dyn_cast<GUnmerge>(SrcDef)) {
1089 Register SrcUnmergeSrc = SrcUnmerge->getSourceReg();
1090 LLT SrcUnmergeSrcTy =
MRI.getType(SrcUnmergeSrc);
1096 {TargetOpcode::G_UNMERGE_VALUES, {OpTy, SrcUnmergeSrcTy}});
1097 switch (ActionStep.
Action) {
1099 if (!OpTy.
isVector() || !LI.isLegal({TargetOpcode::G_UNMERGE_VALUES,
1100 {DestTy, SrcUnmergeSrcTy}}))
1115 auto NewUnmerge = Builder.buildUnmerge(DestTy, SrcUnmergeSrc);
1120 for (
unsigned I = 0;
I != NumDefs; ++
I) {
1122 replaceRegOrBuildCopy(Def, NewUnmerge.getReg(SrcDefIdx * NumDefs +
I),
1123 MRI, Builder, UpdatedDefs, Observer);
1126 markInstAndDefDead(
MI, *SrcUnmerge, DeadInsts, SrcDefIdx);
1131 unsigned ConvertOp = 0;
1134 unsigned SrcOp = SrcDef->getOpcode();
1135 if (isArtifactCast(
SrcOp)) {
1140 if (!MergeI || !canFoldMergeOpcode(MergeI->
getOpcode(),
1141 ConvertOp, OpTy, DestTy)) {
1144 return tryFoldUnmergeCast(
MI, *SrcDef, DeadInsts, UpdatedDefs);
1149 if (NumMergeRegs < NumDefs) {
1150 if (NumDefs % NumMergeRegs != 0)
1153 Builder.setInstr(
MI);
1161 const unsigned NewNumDefs = NumDefs / NumMergeRegs;
1162 for (
unsigned Idx = 0;
Idx < NumMergeRegs; ++
Idx) {
1164 for (
unsigned j = 0, DefIdx =
Idx * NewNumDefs;
j < NewNumDefs;
1169 LLT MergeDstTy =
MRI.getType(SrcDef->getOperand(0).getReg());
1174 LLT MergeEltTy = MergeDstTy.
divide(NumMergeRegs);
1189 Register TmpReg =
MRI.createGenericVirtualRegister(MergeEltTy);
1190 Builder.buildInstr(ConvertOp, {TmpReg},
1192 Builder.buildUnmerge(DstRegs, TmpReg);
1196 UpdatedDefs.append(DstRegs.
begin(), DstRegs.
end());
1199 }
else if (NumMergeRegs > NumDefs) {
1200 if (ConvertOp != 0 || NumMergeRegs % NumDefs != 0)
1203 Builder.setInstr(
MI);
1211 const unsigned NumRegs = NumMergeRegs / NumDefs;
1212 for (
unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
1214 for (
unsigned j = 0,
Idx = NumRegs * DefIdx + 1;
j < NumRegs;
1219 Builder.buildMergeLikeInstr(DefReg, Regs);
1220 UpdatedDefs.push_back(DefReg);
1226 if (!ConvertOp && DestTy != MergeSrcTy) {
1227 if (DestTy.isPointer())
1228 ConvertOp = TargetOpcode::G_INTTOPTR;
1230 ConvertOp = TargetOpcode::G_PTRTOINT;
1232 ConvertOp = TargetOpcode::G_BITCAST;
1236 Builder.setInstr(
MI);
1238 for (
unsigned Idx = 0;
Idx < NumDefs; ++
Idx) {
1242 if (!
MRI.use_empty(DefReg)) {
1243 Builder.buildInstr(ConvertOp, {DefReg}, {MergeSrc});
1244 UpdatedDefs.push_back(DefReg);
1248 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1252 assert(DestTy == MergeSrcTy &&
1253 "Bitcast and the other kinds of conversions should "
1254 "have happened earlier");
1256 Builder.setInstr(
MI);
1257 for (
unsigned Idx = 0;
Idx < NumDefs; ++
Idx) {
1260 replaceRegOrBuildCopy(DstReg, SrcReg,
MRI, Builder, UpdatedDefs,
1265 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1272 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT);
1286 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
1288 if (!MergeI || !isa<GMergeLikeInstr>(MergeI))
1292 LLT DstTy =
MRI.getType(DstReg);
1293 LLT SrcTy =
MRI.getType(SrcReg);
1297 unsigned Offset =
MI.getOperand(2).getImm();
1299 unsigned MergeSrcSize = SrcTy.
getSizeInBits() / NumMergeSrcs;
1300 unsigned MergeSrcIdx =
Offset / MergeSrcSize;
1303 unsigned EndMergeSrcIdx = (
Offset + ExtractDstSize - 1) / MergeSrcSize;
1306 if (MergeSrcIdx != EndMergeSrcIdx)
1310 Builder.setInstr(
MI);
1312 Offset - MergeSrcIdx * MergeSrcSize);
1314 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1330 if (!DeadInsts.
empty())
1331 deleteMarkedDeadInsts(DeadInsts, WrapperObserver);
1338 bool Changed =
false;
1339 switch (
MI.getOpcode()) {
1342 case TargetOpcode::G_ANYEXT:
1343 Changed = tryCombineAnyExt(
MI, DeadInsts, UpdatedDefs, WrapperObserver);
1345 case TargetOpcode::G_ZEXT:
1346 Changed = tryCombineZExt(
MI, DeadInsts, UpdatedDefs, WrapperObserver);
1348 case TargetOpcode::G_SEXT:
1349 Changed = tryCombineSExt(
MI, DeadInsts, UpdatedDefs, WrapperObserver);
1351 case TargetOpcode::G_UNMERGE_VALUES:
1352 Changed = tryCombineUnmergeValues(cast<GUnmerge>(
MI), DeadInsts,
1353 UpdatedDefs, WrapperObserver);
1355 case TargetOpcode::G_MERGE_VALUES:
1356 case TargetOpcode::G_BUILD_VECTOR:
1357 case TargetOpcode::G_CONCAT_VECTORS:
1361 if (U.getOpcode() == TargetOpcode::G_UNMERGE_VALUES ||
1362 U.getOpcode() == TargetOpcode::G_TRUNC) {
1368 UpdatedDefs, WrapperObserver);
1370 case TargetOpcode::G_EXTRACT:
1371 Changed = tryCombineExtract(
MI, DeadInsts, UpdatedDefs);
1373 case TargetOpcode::G_TRUNC:
1374 Changed = tryCombineTrunc(
MI, DeadInsts, UpdatedDefs, WrapperObserver);
1388 while (!UpdatedDefs.
empty()) {
1392 switch (
Use.getOpcode()) {
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:
1404 case TargetOpcode::G_ASSERT_SEXT:
1405 case TargetOpcode::G_ASSERT_ZEXT:
1406 case TargetOpcode::G_ASSERT_ALIGN:
1407 case TargetOpcode::COPY: {
1409 if (Copy.isVirtual())
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();
1451 unsigned DefIdx = 0) {
1462 while (PrevMI != &
DefMI) {
1463 Register PrevRegSrc = getArtifactSrcReg(*PrevMI);
1466 if (
MRI.hasOneUse(PrevRegSrc)) {
1467 if (TmpDef != &
DefMI) {
1471 "Expecting copy or artifact cast here");
1480 if (PrevMI == &
DefMI) {
1485 if (!
MRI.use_empty(
Def.getReg())) {
1490 if (!
MRI.hasOneUse(
DefMI.getOperand(DefIdx).getReg()))
1509 unsigned DefIdx = 0) {
1511 markDefDead(
MI,
DefMI, DeadInsts, DefIdx);
1522 for (
auto *DeadMI : DeadInsts) {
1525 DeadMI->eraseFromParent();
1533 using namespace LegalizeActions;
1534 auto Step = LI.getAction(Query);
1539 return LI.getAction(Query).Action == LegalizeActions::Legal;
1542 bool isConstantUnsupported(
LLT Ty)
const {
1544 return isInstUnsupported({TargetOpcode::G_CONSTANT, {Ty}});
1547 return isInstUnsupported({TargetOpcode::G_CONSTANT, {EltTy}}) ||
1548 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.
unsigned computeNumSignBits(Register R, const APInt &DemandedElts, unsigned Depth=0)
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 bool isPointer() const
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 tryFoldImplicitDef(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs, GISelObserverWrapper &Observer)
Try to fold G_[ASZ]EXT (G_IMPLICIT_DEF).
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)
bool tryCombineSExt(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, SmallVectorImpl< Register > &UpdatedDefs, GISelObserverWrapper &Observer)
static bool canFoldMergeOpcode(unsigned MergeOp, unsigned ConvertOp, LLT OpTy, LLT DestTy)
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 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 buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
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.