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), VT(VT) {}
64 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT);
66 Builder.setInstrAndDebugLoc(
MI);
68 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
74 if (MRI.getType(DstReg) == MRI.getType(TruncSrc))
78 Builder.buildAnyExtOrTrunc(DstReg, TruncSrc);
80 markInstAndDefDead(
MI, *MRI.getVRegDef(SrcReg), DeadInsts);
91 Builder.buildInstr(ExtMI->
getOpcode(), {DstReg}, {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);
103 auto MergedLocation =
107 Builder.setDebugLoc(MergedLocation);
108 Builder.buildConstant(
109 DstReg, CstVal.getCImm()->getValue().sext(DstTy.
getSizeInBits()));
111 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
123 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT);
125 Builder.setInstrAndDebugLoc(
MI);
127 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
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)))
143 SextSrc = Builder.buildSExtOrTrunc(DstTy, SextSrc).getReg(0);
144 if (TruncSrc && (DstTy != MRI.getType(TruncSrc)))
145 TruncSrc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrc).getReg(0);
147 Register AndSrc = SextSrc ? SextSrc : TruncSrc;
154 if (VT && (VT->getKnownZeroes(AndSrc) | ExtMaskVal).isAllOnes()) {
158 auto Mask = Builder.buildConstant(DstTy, ExtMaskVal);
159 Builder.buildAnd(DstReg, AndSrc, Mask);
161 markInstAndDefDead(
MI, *MRI.getVRegDef(SrcReg), DeadInsts);
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);
183 Builder.buildConstant(
184 DstReg, CstVal.getCImm()->getValue().zext(DstTy.
getSizeInBits()));
186 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
198 assert(
MI.getOpcode() == TargetOpcode::G_SEXT);
200 Builder.setInstrAndDebugLoc(
MI);
202 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
207 LLT DstTy = MRI.getType(DstReg);
208 LLT SrcTy = MRI.getType(SrcReg);
209 uint64_t SizeInBits = SrcTy.getScalarSizeInBits();
210 if (isInstUnsupported({TargetOpcode::G_SEXT_INREG,
213 {
static_cast<int64_t
>(SizeInBits)}}))
216 if (DstTy != MRI.getType(TruncSrc))
217 TruncSrc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrc).getReg(0);
220 if (VT && VT->computeNumSignBits(TruncSrc) >
225 Builder.buildSExtInReg(DstReg, TruncSrc, SizeInBits);
226 markInstAndDefDead(
MI, *MRI.getVRegDef(SrcReg), DeadInsts);
238 Builder.buildInstr(ExtMI->
getOpcode(), {DstReg}, {ExtSrc});
240 markInstAndDefDead(
MI, *MRI.getVRegDef(SrcReg), DeadInsts);
245 auto *SrcMI = MRI.getVRegDef(SrcReg);
246 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
247 const LLT DstTy = MRI.getType(DstReg);
248 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
249 auto &CstVal = SrcMI->getOperand(1);
250 Builder.buildConstant(
251 DstReg, CstVal.getCImm()->getValue().sext(DstTy.
getSizeInBits()));
253 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
266 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC);
268 Builder.setInstr(
MI);
270 const LLT DstTy = MRI.getType(DstReg);
271 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
274 auto *SrcMI = MRI.getVRegDef(SrcReg);
275 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
276 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
277 auto &CstVal = SrcMI->getOperand(1);
278 Builder.buildConstant(
279 DstReg, CstVal.getCImm()->getValue().trunc(DstTy.
getSizeInBits()));
281 markInstAndDefDead(
MI, *SrcMI, DeadInsts);
289 const Register MergeSrcReg = SrcMerge->getSourceReg(0);
290 const LLT MergeSrcTy = MRI.getType(MergeSrcReg);
305 if (MergeSrcTy != WorkTy)
306 return Builder.buildBitcast(WorkTy, R).getReg(0);
310 if (DstSize < MergeSrcSize) {
313 if (isInstUnsupported({TargetOpcode::G_TRUNC, {DstTy, WorkTy}}))
316 LLVM_DEBUG(
dbgs() <<
"Combining G_TRUNC(G_MERGE_VALUES) to G_TRUNC: "
319 Builder.buildTrunc(DstReg, AsInt(MergeSrcReg));
321 }
else if (DstSize == MergeSrcSize) {
324 dbgs() <<
"Replacing G_TRUNC(G_MERGE_VALUES) with merge input: "
327 UpdatedDefs, Observer);
328 }
else if (DstSize % MergeSrcSize == 0) {
331 if (isInstUnsupported({TargetOpcode::G_MERGE_VALUES, {DstTy, WorkTy}}))
335 dbgs() <<
"Combining G_TRUNC(G_MERGE_VALUES) to G_MERGE_VALUES: "
338 const unsigned NumSrcs = DstSize / MergeSrcSize;
339 assert(NumSrcs < SrcMI->getNumOperands() - 1 &&
340 "trunc(merge) should require less inputs than merge");
342 for (
unsigned i = 0; i < NumSrcs; ++i)
343 SrcRegs[i] = AsInt(SrcMerge->getSourceReg(i));
345 Builder.buildMergeValues(DstReg, SrcRegs);
352 markInstAndDefDead(
MI, *SrcMerge, DeadInsts);
364 Builder.buildTrunc(DstReg, TruncSrc);
366 markInstAndDefDead(
MI, *MRI.getVRegDef(TruncSrc), DeadInsts);
374 LLT FoundRegTy = MRI.getType(FoundReg);
375 if (DstTy == FoundRegTy) {
376 LLVM_DEBUG(
dbgs() <<
".. Combine G_TRUNC(G_[S,Z,ANY]EXT/G_TRUNC...): "
382 markInstAndDefDead(
MI, *MRI.getVRegDef(SrcReg), DeadInsts);
395 unsigned Opcode =
MI.getOpcode();
396 assert(Opcode == TargetOpcode::G_ANYEXT || Opcode == TargetOpcode::G_ZEXT ||
397 Opcode == TargetOpcode::G_SEXT);
400 MI.getOperand(1).getReg(), MRI)) {
401 Builder.setInstr(
MI);
403 LLT DstTy = MRI.getType(DstReg);
405 if (Opcode == TargetOpcode::G_ANYEXT) {
407 if (!isInstLegal({TargetOpcode::G_IMPLICIT_DEF, {DstTy}}))
410 auto Impl = Builder.buildUndef(DstTy);
417 if (isConstantUnsupported(DstTy))
420 auto Cnst = Builder.buildConstant(DstTy, 0);
426 markInstAndDefDead(
MI, *
DefMI, DeadInsts);
436 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
438 const unsigned CastOpc = CastMI.
getOpcode();
440 if (!isArtifactCast(CastOpc))
443 const unsigned NumDefs =
MI.getNumOperands() - 1;
446 const LLT CastSrcTy = MRI.getType(CastSrcReg);
447 const LLT DestTy = MRI.getType(
MI.getOperand(0).getReg());
448 const LLT SrcTy = MRI.getType(
MI.getOperand(NumDefs).getReg());
453 if (CastOpc == TargetOpcode::G_TRUNC) {
454 if (SrcTy.isVector() && SrcTy.getScalarType() == DestTy.
getScalarType()) {
464 unsigned UnmergeNumElts =
471 if (isInstUnsupported(
472 {TargetOpcode::G_UNMERGE_VALUES, {UnmergeTy, CastSrcTy}}) ||
473 LI.getAction({TargetOpcode::G_TRUNC, {SrcWideTy, UnmergeTy}})
477 Builder.setInstr(
MI);
478 auto NewUnmerge = Builder.buildUnmerge(UnmergeTy, CastSrcReg);
480 for (
unsigned I = 0;
I != NumDefs; ++
I) {
483 Builder.buildTrunc(DefReg, NewUnmerge.getReg(
I));
486 markInstAndDefDead(
MI, CastMI, DeadInsts);
498 if (CastSrcSize % DestSize != 0)
502 if (isInstUnsupported(
503 {TargetOpcode::G_UNMERGE_VALUES, {DestTy, CastSrcTy}}))
508 const unsigned NewNumDefs = CastSrcSize / DestSize;
510 for (
unsigned Idx = 0; Idx < NewNumDefs; ++Idx) {
512 DstRegs[Idx] =
MI.getOperand(Idx).getReg();
514 DstRegs[Idx] = MRI.createGenericVirtualRegister(DestTy);
518 Builder.setInstr(
MI);
519 Builder.buildUnmerge(DstRegs, CastSrcReg);
521 markInstAndDefDead(
MI, CastMI, DeadInsts);
536 case TargetOpcode::G_BUILD_VECTOR:
537 case TargetOpcode::G_MERGE_VALUES:
563 DestTy ==
OpTy.getElementType();
564 case TargetOpcode::G_CONCAT_VECTORS: {
570 const unsigned OpEltSize =
OpTy.getElementType().getSizeInBits();
575 if (ConvertOp == TargetOpcode::G_TRUNC)
590 Builder.buildCopy(DstReg, SrcReg);
596 for (
auto &
UseMI : MRI.use_instructions(DstReg)) {
601 MRI.replaceRegWith(DstReg, SrcReg);
604 for (
auto *
UseMI : UseMIs)
612 if (Def.getReg() == SearchDef)
643 unsigned SrcSize = MRI.getType(Src1Reg).getSizeInBits();
646 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
648 unsigned InRegOffset = StartBit % SrcSize;
652 if (InRegOffset +
Size > SrcSize)
656 if (InRegOffset == 0 &&
Size == SrcSize) {
657 CurrentBest = SrcReg;
658 return findValueFromDefImpl(SrcReg, 0,
Size, MRI.getType(SrcReg));
661 return findValueFromDefImpl(SrcReg, InRegOffset,
Size,
662 MRI.getType(SrcReg));
676 unsigned SrcSize = MRI.getType(Src1Reg).getSizeInBits();
679 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
681 unsigned InRegOffset = StartBit % SrcSize;
683 if (InRegOffset != 0)
690 if (
Size > SrcSize) {
691 if (
Size % SrcSize > 0)
694 unsigned NumSrcsUsed =
Size / SrcSize;
699 LLT SrcTy = MRI.getType(Src1Reg);
704 LI.getAction({TargetOpcode::G_BUILD_VECTOR, {NewBVTy, SrcTy}});
709 for (
unsigned SrcIdx = StartSrcIdx; SrcIdx < StartSrcIdx + NumSrcsUsed;
712 MIB.setInstrAndDebugLoc(BV);
713 return MIB.buildBuildVector(NewBVTy, NewSrcs).getReg(0);
716 return BV.
getReg(StartSrcIdx);
726 assert(
MI.getOpcode() == TargetOpcode::G_INSERT);
729 Register ContainerSrcReg =
MI.getOperand(1).getReg();
730 Register InsertedReg =
MI.getOperand(2).getReg();
731 LLT InsertedRegTy = MRI.getType(InsertedReg);
732 unsigned InsertOffset =
MI.getOperand(3).getImm();
770 unsigned InsertedEndBit = InsertOffset + InsertedRegTy.
getSizeInBits();
771 unsigned EndBit = StartBit +
Size;
772 unsigned NewStartBit;
774 if (EndBit <= InsertOffset || InsertedEndBit <= StartBit) {
775 SrcRegToUse = ContainerSrcReg;
776 NewStartBit = StartBit;
777 return findValueFromDefImpl(SrcRegToUse, NewStartBit,
Size,
778 MRI.getType(SrcRegToUse));
780 if (InsertOffset <= StartBit && EndBit <= InsertedEndBit) {
781 SrcRegToUse = InsertedReg;
782 NewStartBit = StartBit - InsertOffset;
783 if (NewStartBit == 0 &&
784 Size == MRI.getType(SrcRegToUse).getSizeInBits())
785 CurrentBest = SrcRegToUse;
786 return findValueFromDefImpl(SrcRegToUse, NewStartBit,
Size,
787 MRI.getType(SrcRegToUse));
801 assert(
MI.getOpcode() == TargetOpcode::G_SEXT ||
802 MI.getOpcode() == TargetOpcode::G_ZEXT ||
803 MI.getOpcode() == TargetOpcode::G_ANYEXT);
807 LLT SrcType = MRI.getType(SrcReg);
811 if (!SrcType.isScalar())
814 if (StartBit +
Size > SrcSize)
817 if (StartBit == 0 && SrcType.getSizeInBits() ==
Size)
818 CurrentBest = SrcReg;
819 return findValueFromDefImpl(SrcReg, StartBit,
Size, SrcType);
829 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC);
833 LLT SrcType = MRI.getType(SrcReg);
836 if (!SrcType.isScalar())
839 return findValueFromDefImpl(SrcReg, StartBit,
Size, SrcType);
847 std::optional<DefinitionAndSourceRegister> DefSrcReg =
850 DefReg = DefSrcReg->Reg;
854 switch (Def->getOpcode()) {
855 case TargetOpcode::G_CONCAT_VECTORS:
857 case TargetOpcode::G_UNMERGE_VALUES: {
858 unsigned DefStartBit = 0;
859 unsigned DefSize = MRI.getType(DefReg).getSizeInBits();
860 for (
const auto &MO : Def->defs()) {
861 if (MO.getReg() == DefReg)
863 DefStartBit += DefSize;
865 Register SrcReg = Def->getOperand(Def->getNumOperands() - 1).getReg();
867 findValueFromDefImpl(SrcReg, StartBit + DefStartBit,
Size, DstTy);
873 if (StartBit == 0 &&
Size == DefSize)
877 case TargetOpcode::G_BUILD_VECTOR:
880 case TargetOpcode::G_INSERT:
881 return findValueFromInsert(*Def, StartBit,
Size);
882 case TargetOpcode::G_TRUNC:
883 return findValueFromTrunc(*Def, StartBit,
Size);
884 case TargetOpcode::G_SEXT:
885 case TargetOpcode::G_ZEXT:
886 case TargetOpcode::G_ANYEXT:
887 return findValueFromExt(*Def, StartBit,
Size);
888 case TargetOpcode::G_IMPLICIT_DEF: {
889 if (MRI.getType(DefReg) == DstTy)
891 MIB.setInstrAndDebugLoc(*Def);
892 return MIB.buildUndef(DstTy).getReg(0);
902 : MRI(Mri), MIB(Builder), LI(Info) {}
911 Register FoundReg = findValueFromDefImpl(DefReg, StartBit,
Size, DstTy);
912 return FoundReg != DefReg ? FoundReg :
Register();
920 unsigned NumDefs =
MI.getNumDefs();
921 LLT DestTy = MRI.getType(
MI.getReg(0));
924 for (
unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
926 if (MRI.use_nodbg_empty(DefReg)) {
927 DeadDefs[DefIdx] =
true;
934 if (MRI.getType(FoundVal) != DestTy)
941 MI.getOperand(DefIdx).setReg(DefReg);
943 DeadDefs[DefIdx] =
true;
945 return DeadDefs.
all();
949 unsigned &DefOperandIdx) {
953 Unmerge->findRegisterDefOperandIdx(Def,
nullptr);
964 GUnmerge *Unmerge,
unsigned UnmergeIdxStart,
965 unsigned NumElts,
unsigned EltSize,
967 assert(MergeStartIdx + NumElts <=
MI.getNumSources());
968 for (
unsigned i = MergeStartIdx; i < MergeStartIdx + NumElts; ++i) {
969 unsigned EltUnmergeIdx;
971 MI.getSourceReg(i), EltSize, EltUnmergeIdx);
973 if (EltUnmerge == Unmerge) {
975 if (i - MergeStartIdx != EltUnmergeIdx - UnmergeIdxStart)
977 }
else if (!AllowUndef ||
978 MRI.getVRegDef(
MI.getSourceReg(i))->getOpcode() !=
979 TargetOpcode::G_IMPLICIT_DEF)
990 LLT EltTy = MRI.getType(Elt0);
993 unsigned Elt0UnmergeIdx;
999 unsigned NumMIElts =
MI.getNumSources();
1001 LLT DstTy = MRI.getType(Dst);
1002 Register UnmergeSrc = Unmerge->getSourceReg();
1003 LLT UnmergeSrcTy = MRI.getType(UnmergeSrc);
1012 if ((DstTy == UnmergeSrcTy) && (Elt0UnmergeIdx == 0)) {
1036 (Elt0UnmergeIdx % NumMIElts == 0) &&
1037 getCoverTy(UnmergeSrcTy, DstTy) == UnmergeSrcTy) {
1041 MIB.setInstrAndDebugLoc(
MI);
1042 auto NewUnmerge = MIB.buildUnmerge(DstTy, Unmerge->getSourceReg());
1043 unsigned DstIdx = (Elt0UnmergeIdx * EltSize) / DstTy.
getSizeInBits();
1045 UpdatedDefs, Observer);
1063 unsigned NumElts = Unmerge->getNumDefs();
1064 for (
unsigned i = 0; i <
MI.getNumSources(); i += NumElts) {
1065 unsigned EltUnmergeIdx;
1067 EltSize, EltUnmergeIdx);
1069 if ((!UnmergeI) || (UnmergeI->getNumDefs() != NumElts) ||
1070 (EltUnmergeIdx != 0))
1075 ConcatSources.
push_back(UnmergeI->getSourceReg());
1078 MIB.setInstrAndDebugLoc(
MI);
1079 MIB.buildMergeLikeInstr(Dst, ConcatSources);
1092 unsigned NumDefs =
MI.getNumDefs();
1094 std::optional<DefinitionAndSourceRegister> DefSrcReg =
1100 LLT OpTy = MRI.getType(SrcReg);
1101 LLT DestTy = MRI.getType(
MI.getReg(0));
1102 unsigned SrcDefIdx =
getDefIndex(*SrcDef, DefSrcReg->Reg);
1104 Builder.setInstrAndDebugLoc(
MI);
1108 markInstAndDefDead(
MI, *SrcDef, DeadInsts, SrcDefIdx);
1118 Register SrcUnmergeSrc = SrcUnmerge->getSourceReg();
1119 LLT SrcUnmergeSrcTy = MRI.getType(SrcUnmergeSrc);
1125 {TargetOpcode::G_UNMERGE_VALUES, {
OpTy, SrcUnmergeSrcTy}});
1126 switch (ActionStep.
Action) {
1128 if (!
OpTy.isVector() || !LI.isLegal({TargetOpcode::G_UNMERGE_VALUES,
1129 {DestTy, SrcUnmergeSrcTy}}))
1144 auto NewUnmerge = Builder.buildUnmerge(DestTy, SrcUnmergeSrc);
1149 for (
unsigned I = 0;
I != NumDefs; ++
I) {
1152 MRI, Builder, UpdatedDefs, Observer);
1155 markInstAndDefDead(
MI, *SrcUnmerge, DeadInsts, SrcDefIdx);
1160 unsigned ConvertOp = 0;
1163 unsigned SrcOp = SrcDef->getOpcode();
1164 if (isArtifactCast(
SrcOp)) {
1170 ConvertOp,
OpTy, DestTy)) {
1178 if (NumMergeRegs < NumDefs) {
1179 if (NumDefs % NumMergeRegs != 0)
1182 Builder.setInstr(
MI);
1190 const unsigned NewNumDefs = NumDefs / NumMergeRegs;
1191 for (
unsigned Idx = 0; Idx < NumMergeRegs; ++Idx) {
1193 for (
unsigned j = 0, DefIdx = Idx * NewNumDefs;
j < NewNumDefs;
1198 LLT MergeDstTy = MRI.getType(SrcDef->getOperand(0).getReg());
1203 LLT MergeEltTy = MergeDstTy.
divide(NumMergeRegs);
1218 Register TmpReg = MRI.createGenericVirtualRegister(MergeEltTy);
1219 Builder.buildInstr(ConvertOp, {TmpReg},
1221 Builder.buildUnmerge(DstRegs, TmpReg);
1225 UpdatedDefs.append(DstRegs.
begin(), DstRegs.
end());
1228 }
else if (NumMergeRegs > NumDefs) {
1229 if (ConvertOp != 0 || NumMergeRegs % NumDefs != 0)
1232 Builder.setInstr(
MI);
1240 const unsigned NumRegs = NumMergeRegs / NumDefs;
1241 for (
unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
1243 for (
unsigned j = 0, Idx = NumRegs * DefIdx + 1;
j < NumRegs;
1248 Builder.buildMergeLikeInstr(DefReg, Regs);
1249 UpdatedDefs.push_back(DefReg);
1255 if (!ConvertOp && DestTy != MergeSrcTy) {
1256 if (DestTy.isPointer())
1257 ConvertOp = TargetOpcode::G_INTTOPTR;
1259 ConvertOp = TargetOpcode::G_PTRTOINT;
1261 ConvertOp = TargetOpcode::G_BITCAST;
1265 Builder.setInstr(
MI);
1267 for (
unsigned Idx = 0; Idx < NumDefs; ++Idx) {
1268 Register DefReg =
MI.getOperand(Idx).getReg();
1271 if (!MRI.use_empty(DefReg)) {
1272 Builder.buildInstr(ConvertOp, {DefReg}, {MergeSrc});
1273 UpdatedDefs.push_back(DefReg);
1277 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1281 assert(DestTy == MergeSrcTy &&
1282 "Bitcast and the other kinds of conversions should "
1283 "have happened earlier");
1285 Builder.setInstr(
MI);
1286 for (
unsigned Idx = 0; Idx < NumDefs; ++Idx) {
1287 Register DstReg =
MI.getOperand(Idx).getReg();
1294 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1301 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT);
1316 Register SrcReg = lookThroughCopyInstrs(
MI.getOperand(1).getReg());
1318 if (MergeI && MergeI->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF) {
1319 Builder.setInstrAndDebugLoc(
MI);
1320 Builder.buildUndef(DstReg);
1322 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1328 LLT DstTy = MRI.getType(DstReg);
1329 LLT SrcTy = MRI.getType(SrcReg);
1333 unsigned Offset =
MI.getOperand(2).getImm();
1335 unsigned MergeSrcSize = SrcTy.getSizeInBits() / NumMergeSrcs;
1336 unsigned MergeSrcIdx =
Offset / MergeSrcSize;
1339 unsigned EndMergeSrcIdx = (
Offset + ExtractDstSize - 1) / MergeSrcSize;
1342 if (MergeSrcIdx != EndMergeSrcIdx)
1346 Builder.setInstr(
MI);
1348 Offset - MergeSrcIdx * MergeSrcSize);
1350 markInstAndDefDead(
MI, *MergeI, DeadInsts);
1366 if (!DeadInsts.
empty())
1367 deleteMarkedDeadInsts(DeadInsts, WrapperObserver);
1375 switch (
MI.getOpcode()) {
1378 case TargetOpcode::G_ANYEXT:
1381 case TargetOpcode::G_ZEXT:
1384 case TargetOpcode::G_SEXT:
1387 case TargetOpcode::G_UNMERGE_VALUES:
1389 UpdatedDefs, WrapperObserver);
1391 case TargetOpcode::G_MERGE_VALUES:
1392 case TargetOpcode::G_BUILD_VECTOR:
1393 case TargetOpcode::G_CONCAT_VECTORS:
1396 for (
MachineInstr &U : MRI.use_instructions(
MI.getOperand(0).getReg())) {
1397 if (U.getOpcode() == TargetOpcode::G_UNMERGE_VALUES ||
1398 U.getOpcode() == TargetOpcode::G_TRUNC) {
1404 UpdatedDefs, WrapperObserver);
1406 case TargetOpcode::G_EXTRACT:
1409 case TargetOpcode::G_TRUNC:
1424 while (!UpdatedDefs.
empty()) {
1428 switch (
Use.getOpcode()) {
1430 case TargetOpcode::G_ANYEXT:
1431 case TargetOpcode::G_ZEXT:
1432 case TargetOpcode::G_SEXT:
1433 case TargetOpcode::G_UNMERGE_VALUES:
1434 case TargetOpcode::G_EXTRACT:
1435 case TargetOpcode::G_TRUNC:
1436 case TargetOpcode::G_BUILD_VECTOR:
1440 case TargetOpcode::G_ASSERT_SEXT:
1441 case TargetOpcode::G_ASSERT_ZEXT:
1442 case TargetOpcode::G_ASSERT_ALIGN:
1443 case TargetOpcode::COPY: {
1445 if (Copy.isVirtual())
1462 switch (
MI.getOpcode()) {
1463 case TargetOpcode::COPY:
1464 case TargetOpcode::G_TRUNC:
1465 case TargetOpcode::G_ZEXT:
1466 case TargetOpcode::G_ANYEXT:
1467 case TargetOpcode::G_SEXT:
1468 case TargetOpcode::G_EXTRACT:
1469 case TargetOpcode::G_ASSERT_SEXT:
1470 case TargetOpcode::G_ASSERT_ZEXT:
1471 case TargetOpcode::G_ASSERT_ALIGN:
1472 return MI.getOperand(1).getReg();
1473 case TargetOpcode::G_UNMERGE_VALUES:
1474 return MI.getOperand(
MI.getNumOperands() - 1).getReg();
1487 unsigned DefIdx = 0) {
1498 while (PrevMI != &
DefMI) {
1499 Register PrevRegSrc = getArtifactSrcReg(*PrevMI);
1503 if (TmpDef != &
DefMI) {
1507 "Expecting copy or artifact cast here");
1516 if (PrevMI == &
DefMI) {
1545 unsigned DefIdx = 0) {
1547 markDefDead(
MI,
DefMI, DeadInsts, DefIdx);
1558 for (
auto *DeadMI : DeadInsts) {
1561 DeadMI->eraseFromParent();
1578 bool isConstantUnsupported(
LLT Ty)
const {
1580 return isInstUnsupported({TargetOpcode::G_CONSTANT, {Ty}});
1583 return isInstUnsupported({TargetOpcode::G_CONSTANT, {EltTy}}) ||
1584 isInstUnsupported({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}});
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
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
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.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
static LLVM_ABI DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc 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.
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.
LLT changeElementCount(ElementCount EC) const
Return a vector or scalar with the same element type and the new element count.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
LLT getScalarType() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isFloat() const
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
LLT divide(int Factor) const
Return a type that is Factor times smaller.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
This class provides utilities for finding source registers of specific bit ranges in an artifact.
Register findValueFromDef(Register DefReg, unsigned StartBit, unsigned Size, LLT DstTy)
Try to find a source of the value defined in the def DefReg, starting at position StartBit with size ...
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)
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)
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)
LegalizationArtifactCombiner(MachineIRBuilder &B, MachineRegisterInfo &MRI, const LegalizerInfo &LI, GISelValueTracking *VT=nullptr)
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.
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,...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
bool use_empty(Register RegNo) const
use_empty - Return true if there are no instructions using the specified register.
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.
@ 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.
@ NotFound
Sentinel value for when no action was found in the specified table.
@ MoreElements
The (vector) operation should be implemented by widening the input vector and ignoring the lanes adde...
operand_type_match m_Reg()
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
Or< Preds... > m_any_of(Preds &&... preds)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
And< Preds... > m_all_of(Preds &&... preds)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
bool isPreISelGenericOptimizationHint(unsigned Opcode)
LLVM_ABI bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI LLVM_READNONE LLT getCoverTy(LLT OrigTy, LLT TargetTy)
Return smallest type that covers both OrigTy and TargetTy and is multiple of TargetTy.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
LLVM_ABI 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.