51#define GET_GICOMBINER_DEPS
52#include "AArch64GenPostLegalizeGILowering.inc"
53#undef GET_GICOMBINER_DEPS
55#define DEBUG_TYPE "aarch64-postlegalizer-lowering"
61#define GET_GICOMBINER_TYPES
62#include "AArch64GenPostLegalizeGILowering.inc"
63#undef GET_GICOMBINER_TYPES
70struct ShuffleVectorPseudo {
75 std::initializer_list<SrcOp> SrcOps)
76 :
Opc(
Opc), Dst(Dst), SrcOps(SrcOps){};
77 ShuffleVectorPseudo() =
default;
89 int NumInputElements) {
90 if (M.size() !=
static_cast<size_t>(NumInputElements))
92 int NumLHSMatch = 0, NumRHSMatch = 0;
93 int LastLHSMismatch = -1, LastRHSMismatch = -1;
94 for (
int Idx = 0; Idx < NumInputElements; ++Idx) {
100 M[Idx] == Idx ? ++NumLHSMatch : LastLHSMismatch = Idx;
101 M[Idx] == Idx + NumInputElements ? ++NumRHSMatch : LastRHSMismatch = Idx;
103 const int NumNeededToMatch = NumInputElements - 1;
104 if (NumLHSMatch == NumNeededToMatch)
105 return std::make_pair(
true, LastLHSMismatch);
106 if (NumRHSMatch == NumNeededToMatch)
107 return std::make_pair(
false, LastRHSMismatch);
114 ShuffleVectorPseudo &MatchInfo) {
115 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
119 LLT Ty =
MRI.getType(Dst);
120 unsigned EltSize = Ty.getScalarSizeInBits();
126 unsigned NumElts = Ty.getNumElements();
129 for (
unsigned LaneSize : {64U, 32U, 16U}) {
130 if (
isREVMask(ShuffleMask, EltSize, NumElts, LaneSize)) {
133 Opcode = AArch64::G_REV64;
134 else if (LaneSize == 32U)
135 Opcode = AArch64::G_REV32;
137 Opcode = AArch64::G_BSWAP;
139 MatchInfo = ShuffleVectorPseudo(Opcode, Dst, {Src});
150 ShuffleVectorPseudo &MatchInfo) {
151 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
152 unsigned WhichResult;
153 unsigned OperandOrder = 0;
156 unsigned NumElts =
MRI.getType(Dst).getNumElements();
157 bool TRNMask =
isTRNMask(ShuffleMask, NumElts, WhichResult, OperandOrder);
160 unsigned Opc = (WhichResult == 0) ? AArch64::G_TRN1 : AArch64::G_TRN2;
161 Register V1 =
MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
162 Register V2 =
MI.getOperand(OperandOrder == 0 && TRNMask ? 2 : 1).getReg();
163 MatchInfo = ShuffleVectorPseudo(
Opc, Dst, {
V1, V2});
173 ShuffleVectorPseudo &MatchInfo) {
174 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
175 unsigned WhichResult;
178 unsigned NumElts =
MRI.getType(Dst).getNumElements();
179 bool UZPMask =
isUZPMask(ShuffleMask, NumElts, WhichResult);
182 unsigned Opc = (WhichResult == 0) ? AArch64::G_UZP1 : AArch64::G_UZP2;
184 Register V2 =
MI.getOperand(UZPMask ? 2 : 1).getReg();
185 MatchInfo = ShuffleVectorPseudo(
Opc, Dst, {
V1, V2});
190 ShuffleVectorPseudo &MatchInfo) {
191 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
192 unsigned WhichResult;
193 unsigned OperandOrder = 0;
196 unsigned NumElts =
MRI.getType(Dst).getNumElements();
197 bool ZIPMask =
isZIPMask(ShuffleMask, NumElts, WhichResult, OperandOrder);
200 unsigned Opc = (WhichResult == 0) ? AArch64::G_ZIP1 : AArch64::G_ZIP2;
201 Register V1 =
MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
202 Register V2 =
MI.getOperand(OperandOrder == 0 && ZIPMask ? 2 : 1).getReg();
203 MatchInfo = ShuffleVectorPseudo(
Opc, Dst, {
V1, V2});
210 ShuffleVectorPseudo &MatchInfo) {
229 auto *InsMI =
getOpcodeDef(TargetOpcode::G_INSERT_VECTOR_ELT,
230 MI.getOperand(1).getReg(),
MRI);
234 if (!
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, InsMI->getOperand(1).getReg(),
242 MatchInfo = ShuffleVectorPseudo(TargetOpcode::G_SPLAT_VECTOR,
243 MI.getOperand(0).getReg(),
244 {InsMI->getOperand(2).getReg()});
251 ShuffleVectorPseudo &MatchInfo) {
252 assert(Lane >= 0 &&
"Expected positive lane?");
253 int NumElements =
MRI.getType(
MI.getOperand(1).getReg()).getNumElements();
258 MI.getOperand(Lane < NumElements ? 1 : 2).getReg(),
MRI);
260 if (NumElements <= Lane)
265 Register Reg = BuildVecMI->getOperand(Lane + 1).getReg();
266 MatchInfo = ShuffleVectorPseudo(TargetOpcode::G_SPLAT_VECTOR,
267 MI.getOperand(0).getReg(), {Reg});
272 ShuffleVectorPseudo &MatchInfo) {
273 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
277 int Lane = *MaybeLane;
281 if (matchDupFromInsertVectorElt(Lane,
MI,
MRI, MatchInfo))
283 if (matchDupFromBuildVector(Lane,
MI,
MRI, MatchInfo))
289 ShuffleVectorPseudo &MatchInfo) {
290 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
292 LLT DstTy =
MRI.getType(Dst);
295 auto Mask =
MI.getOperand(3).getShuffleMask();
296 uint64_t ExtFactor =
MRI.getType(
V1).getScalarSizeInBits() / 8;
304 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst,
313 Imm = Mask[0] * ExtFactor;
314 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst,
322 ShuffleVectorPseudo &MatchInfo) {
324 if (MatchInfo.Opc == TargetOpcode::G_BSWAP) {
325 assert(MatchInfo.SrcOps.size() == 1);
326 LLT DstTy =
MRI.getType(MatchInfo.Dst);
333 auto BS1 = MIRBuilder.
buildInstr(TargetOpcode::G_BITCAST, {BSTy},
334 MatchInfo.SrcOps[0]);
335 auto BS2 = MIRBuilder.
buildInstr(MatchInfo.Opc, {BSTy}, {BS1});
336 MIRBuilder.
buildInstr(TargetOpcode::G_BITCAST, {MatchInfo.Dst}, {BS2});
338 MIRBuilder.
buildInstr(MatchInfo.Opc, {MatchInfo.Dst}, MatchInfo.SrcOps);
339 MI.eraseFromParent();
347 if (MatchInfo.SrcOps[2].getImm() == 0)
348 MIRBuilder.
buildCopy(MatchInfo.Dst, MatchInfo.SrcOps[0]);
352 MatchInfo.SrcOps[2].getImm());
353 MIRBuilder.
buildInstr(MatchInfo.Opc, {MatchInfo.Dst},
354 {MatchInfo.SrcOps[0], MatchInfo.SrcOps[1], Cst});
356 MI.eraseFromParent();
360 if (
MBB->getParent()->getFunction().hasOptSize())
367 if (preferTBLToMultiInstrShuffle(
MI.getParent()))
379 LLT DstTy =
MRI.getType(Dst);
381 "Expected 128bit vector in applyFullRev");
384 auto Rev = MIRBuilder.
buildInstr(AArch64::G_REV64, {DstTy}, {Src});
385 MIRBuilder.
buildInstr(AArch64::G_EXT, {Dst}, {Rev, Rev, Cst});
386 MI.eraseFromParent();
390 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT);
400 Builder.setInstrAndDebugLoc(Insert);
403 LLT VecTy =
MRI.getType(Insert.getReg(0));
404 LLT EltTy =
MRI.getType(Insert.getElementReg());
405 LLT IdxTy =
MRI.getType(Insert.getIndexReg());
418 auto StackTemp = Builder.buildFrameIndex(FramePtrTy, FrameIdx);
420 Builder.buildStore(Insert.getOperand(1), StackTemp, PtrInfo,
Align(8));
425 "Expected a power-2 vector size");
426 auto Mask = Builder.buildConstant(IdxTy, VecTy.
getNumElements() - 1);
428 auto EltSize = Builder.buildConstant(IdxTy, EltTy.
getSizeInBytes());
431 Builder.buildPtrAdd(
MRI.getType(StackTemp.getReg(0)), StackTemp,
Mul)
435 Builder.buildStore(Insert.getElementReg(), EltPtr, PtrInfo,
Align(1));
437 Builder.buildLoad(Insert.getReg(0), StackTemp, PtrInfo,
Align(8));
438 Insert.eraseFromParent();
453 std::tuple<Register, int, Register, int> &MatchInfo) {
454 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
457 int NumElts =
MRI.getType(Dst).getNumElements();
458 auto DstIsLeftAndDstLane =
isINSMask(ShuffleMask, NumElts);
459 if (!DstIsLeftAndDstLane)
463 std::tie(DstIsLeft, DstLane) = *DstIsLeftAndDstLane;
469 int SrcLane = ShuffleMask[DstLane];
470 if (SrcLane >= NumElts) {
475 MatchInfo = std::make_tuple(DstVec, DstLane, SrcVec, SrcLane);
481 std::tuple<Register, int, Register, int> &MatchInfo) {
482 Builder.setInstrAndDebugLoc(
MI);
484 auto ScalarTy =
MRI.getType(Dst).getElementType();
486 int DstLane, SrcLane;
487 std::tie(DstVec, DstLane, SrcVec, SrcLane) = MatchInfo;
488 auto SrcCst = Builder.buildConstant(
LLT::integer(64), SrcLane);
489 auto Extract = Builder.buildExtractVectorElement(ScalarTy, SrcVec, SrcCst);
490 auto DstCst = Builder.buildConstant(
LLT::integer(64), DstLane);
491 Builder.buildInsertVectorElement(Dst, DstVec, Extract, DstCst);
492 MI.eraseFromParent();
498 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
499 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
500 assert(Ty.getSizeInBits() == 64 || Ty.getSizeInBits() == 128);
501 if (Ty.getNumElements() != 4)
505 return Entries.
size() == 1 || !preferTBLToMultiInstrShuffle(
MI.getParent());
524 LLT VT =
MRI.getType(
MI.getOperand(0).getReg());
534 unsigned ExtLane = (Entry.RHSID >> 8) & 0xff;
535 unsigned ToLane = Entry.RHSID & 0xff;
536 bool Input2 = Entry.RHSID >> 16;
541 "Expected 16 or 32 bit shuffle elements");
556 unsigned ExtLane = (Entry.RHSID >> 8) & 0xff;
557 unsigned ToLane = Entry.RHSID & 0xff;
558 bool Input2 = Entry.RHSID >> 16;
587 Opcode = AArch64::G_DUPLANE8;
589 Opcode = AArch64::G_DUPLANE16;
591 Opcode = AArch64::G_DUPLANE32;
593 Opcode = AArch64::G_DUPLANE64;
600 {OpLHS, Undef.getReg(0)})
614 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals),
615 MIB.buildConstant(LLT::integer(32), Imm)})
622 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
628 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
634 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
640 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
646 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
652 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
658 MRI.replaceRegWith(
MI.getOperand(0).getReg(), Vals.
back());
659 MI.eraseFromParent();
665 assert(
MI.getOpcode() == TargetOpcode::G_ASHR ||
666 MI.getOpcode() == TargetOpcode::G_LSHR);
667 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
675 unsigned Opc =
MI.getOpcode();
676 assert(
Opc == TargetOpcode::G_ASHR ||
Opc == TargetOpcode::G_LSHR);
678 Opc == TargetOpcode::G_ASHR ? AArch64::G_VASHR : AArch64::G_VLSHR;
681 MI.eraseFromParent();
721 if (!IsAndLHS && !
MRI.hasOneNonDBGUse(
LHS))
738std::optional<std::pair<uint64_t, CmpInst::Predicate>>
741 const auto &Ty =
MRI.getType(
RHS);
744 assert((Ty.getSizeInBits() == 32 || Ty.getSizeInBits() == 64) &&
745 "Expected 32 or 64 bit compare only?");
752 APInt C = ValAndVReg->Value;
774 if (
C.isMinSignedValue())
787 assert(!
C.isZero() &&
"C should not be zero here!");
799 if (
C.isMaxSignedValue())
831 if (NumberOfInstrToLoadImm(OriginalC) > NumberOfInstrToLoadImm(NewC))
845bool matchAdjustICmpImmAndPred(
847 std::pair<uint64_t, CmpInst::Predicate> &MatchInfo) {
848 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
852 if (
auto MaybeNewImmAndPred = tryAdjustICmpImmAndPred(
LHS,
RHS,
Pred,
MRI)) {
853 MatchInfo = *MaybeNewImmAndPred;
859void applyAdjustICmpImmAndPred(
860 MachineInstr &
MI, std::pair<uint64_t, CmpInst::Predicate> &MatchInfo,
868 RHS.setReg(Cst->getOperand(0).getReg());
869 MI.getOperand(1).setPredicate(MatchInfo.second);
874 std::pair<unsigned, int> &MatchInfo) {
875 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
877 const LLT SrcTy =
MRI.getType(Src1Reg);
878 const LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
885 if (*LaneIdx >= SrcTy.getNumElements())
895 switch (SrcTy.getNumElements()) {
897 if (ScalarSize == 64)
898 Opc = AArch64::G_DUPLANE64;
899 else if (ScalarSize == 32)
900 Opc = AArch64::G_DUPLANE32;
903 if (ScalarSize == 32)
904 Opc = AArch64::G_DUPLANE32;
905 else if (ScalarSize == 16)
906 Opc = AArch64::G_DUPLANE16;
910 Opc = AArch64::G_DUPLANE8;
911 else if (ScalarSize == 16)
912 Opc = AArch64::G_DUPLANE16;
916 Opc = AArch64::G_DUPLANE8;
924 MatchInfo.first =
Opc;
925 MatchInfo.second = *LaneIdx;
931 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
933 const LLT SrcTy =
MRI.getType(Src1Reg);
935 B.setInstrAndDebugLoc(
MI);
936 auto Lane =
B.buildConstant(
LLT::integer(64), MatchInfo.second);
941 if (SrcTy.getSizeInBits() == 64) {
942 auto Undef =
B.buildUndef(SrcTy);
943 DupSrc =
B.buildConcatVectors(SrcTy.multiplyElements(2),
944 {Src1Reg, Undef.getReg(0)})
947 B.buildInstr(MatchInfo.first, {MI.getOperand(0).getReg()}, {DupSrc, Lane});
948 MI.eraseFromParent();
953 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
954 const LLT SrcTy =
MRI.getType(Src1Reg);
955 if (SrcTy.getSizeInBits() != 128 && SrcTy.getSizeInBits() != 64)
957 return SrcTy.isVector() && !SrcTy.isScalable() &&
958 (Unmerge.getNumOperands() == (
unsigned)SrcTy.getNumElements() + 1 ||
959 (Unmerge.getNumDefs() == 2 && SrcTy.getSizeInBits() == 128 &&
960 MRI.getType(Unmerge.getReg(0)).getSizeInBits() == 64));
966 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
967 const LLT SrcTy =
MRI.getType(Src1Reg);
968 const LLT DstTy =
MRI.getType(Unmerge.getReg(0));
969 assert((SrcTy.isVector() && !SrcTy.isScalable()) &&
970 "Expected a fixed length vector");
973 assert(Unmerge.getNumDefs() == 2);
974 if (!
MRI.use_nodbg_empty(Unmerge.getReg(0)))
975 B.buildExtractSubvector(Unmerge.getReg(0), Src1Reg, 0);
976 if (!
MRI.use_nodbg_empty(Unmerge.getReg(1)))
977 B.buildExtractSubvector(Unmerge.getReg(1), Src1Reg,
978 SrcTy.getNumElements() / 2);
980 for (
int I = 0;
I < SrcTy.getNumElements(); ++
I)
981 if (!
MRI.use_nodbg_empty(Unmerge.getReg(
I)))
982 B.buildExtractVectorElementConstant(Unmerge.getReg(
I), Src1Reg,
I);
984 MI.eraseFromParent();
989 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
1001 unsigned NumNonUndef = 0;
1008 else if (
Op.getReg() !=
Reg)
1014 return Reg && NumNonUndef > 1;
1019 B.setInstrAndDebugLoc(
MI);
1020 B.buildInstr(TargetOpcode::G_SPLAT_VECTOR, {
MI.getOperand(0).getReg()},
1022 MI.eraseFromParent();
1026 std::pair<Register, Register> &Srcs,
1028 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
1029 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
1043 unsigned NumOps =
MI.getNumOperands() - 1;
1047 unsigned NumNonUndef1 = 0, NumNonUndef2 = 0;
1048 for (
unsigned I = 0;
I <
NumOps / 2;
I++) {
1053 else if (Src1 != Reg1)
1062 else if (Src2 != Reg2)
1068 Srcs = {Reg1, Reg2};
1069 return NumNonUndef1 >= 1 && NumNonUndef2 >= 1 &&
1070 NumNonUndef1 + NumNonUndef2 >= 3 && Reg1 != Reg2;
1074 std::pair<Register, Register> &Srcs,
1076 B.setInstrAndDebugLoc(
MI);
1077 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
1079 auto D1 = Srcs.first
1080 ?
B.buildInstr(AArch64::G_SPLAT_VECTOR, {HalfTy}, {Srcs.first})
1081 :
B.buildUndef(HalfTy);
1082 auto D2 = Srcs.second
1083 ?
B.buildInstr(AArch64::G_SPLAT_VECTOR, {HalfTy}, {Srcs.second})
1084 :
B.buildUndef(HalfTy);
1085 B.buildConcatVectors(
MI.getOperand(0), {D1.getReg(0), D2.getReg(0)});
1086 MI.eraseFromParent();
1095 if (
MI.getOpcode() == TargetOpcode::G_SEXT_INREG)
1097 if (
MI.getOpcode() == TargetOpcode::G_AND) {
1101 uint64_t Mask = ValAndVReg->Value.getZExtValue();
1102 return (Mask == 0xFF || Mask == 0xFFFF || Mask == 0xFFFFFFFF);
1109 if (!
MRI.hasOneNonDBGUse(CmpOp))
1113 if (IsSupportedExtend(*Def))
1116 unsigned Opc = Def->getOpcode();
1117 if (
Opc == TargetOpcode::G_SHL ||
Opc == TargetOpcode::G_LSHR ||
1118 Opc == TargetOpcode::G_ASHR) {
1119 auto MaybeShiftAmt =
1121 if (MaybeShiftAmt) {
1122 uint64_t ShiftAmt = MaybeShiftAmt->Value.getZExtValue();
1125 if (IsSupportedExtend(*ShiftLHS))
1126 return (ShiftAmt <= 4) ? 2 : 1;
1127 LLT Ty =
MRI.getType(Def->getOperand(0).getReg());
1130 unsigned ShiftSize = Ty.getSizeInBits();
1131 if ((ShiftSize == 32 && ShiftAmt <= 31) ||
1132 (ShiftSize == 64 && ShiftAmt <= 63))
1143 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
1184 MI.getOperand(2).setReg(
RHS);
1185 MI.getOperand(3).setReg(
LHS);
1233 assert(
MI.getOpcode() == TargetOpcode::G_FCMP);
1237 LLT DstTy =
MRI.getType(Dst);
1238 if (!DstTy.
isVector() || !ST.hasNEON())
1241 unsigned EltSize =
MRI.getType(
LHS).getScalarSizeInBits();
1242 if (EltSize == 16 && !ST.hasFullFP16())
1244 if (EltSize != 16 && EltSize != 32 && EltSize != 64)
1253 assert(
MI.getOpcode() == TargetOpcode::G_FCMP);
1262 LLT DstTy =
MRI.getType(Dst);
1264 bool Invert =
false;
1285 auto Cmp = getVectorFCMP(
CC,
LHS,
RHS, NoNans,
MRI);
1290 auto Cmp2 = getVectorFCMP(CC2,
LHS,
RHS, NoNans,
MRI);
1291 auto Cmp2Dst = Cmp2(MIB);
1292 auto Cmp1Dst = Cmp(MIB);
1297 MRI.replaceRegWith(Dst, CmpRes);
1298 MI.eraseFromParent();
1306 for (
unsigned I = 0;
I < GBuildVec->getNumSources(); ++
I) {
1310 if (!ConstVal.has_value())
1320 LLT DstTy =
MRI.getType(GBuildVec->getReg(0));
1321 Register DstReg =
B.buildUndef(DstTy).getReg(0);
1323 for (
unsigned I = 0;
I < GBuildVec->getNumSources(); ++
I) {
1324 Register SrcReg = GBuildVec->getSourceReg(
I);
1329 B.buildInsertVectorElement(DstTy, DstReg, SrcReg, IdxReg).getReg(0);
1331 B.buildCopy(GBuildVec->getReg(0), DstReg);
1332 GBuildVec->eraseFromParent();
1340 std::pair<APInt, unsigned> &MatchInfo) {
1341 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
1342 if (!ST.isNeonAvailable())
1344 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
1346 if (Ty.getSizeInBits() != 64 && Ty.getSizeInBits() != 128)
1348 unsigned EltSize = Ty.getScalarSizeInBits();
1351 for (
unsigned Idx = 1; Idx <
MI.getNumOperands(); Idx++) {
1356 Imm |=
C->Value.trunc(EltSize)
1357 .zext(Ty.getSizeInBits())
1358 .shl((Idx - 1) * EltSize);
1369 MatchInfo.first = NImm;
1370 MatchInfo.second =
Size;
1375 (ST.hasFullFP16() &&
Check(
Imm, 16));
1380 std::pair<APInt, unsigned> &MatchInfo) {
1381 B.setInstrAndDebugLoc(
MI);
1382 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
1384 unsigned EltSize = MatchInfo.second;
1385 unsigned NumLanes = Ty.getSizeInBits() / EltSize;
1386 LLT VTy = NumLanes == 1
1390 for (
unsigned I = 0;
I < NumLanes;
I++)
1391 Imms.
push_back(MatchInfo.first.extractBits(EltSize,
I * EltSize));
1395 :
B.buildBuildVectorConstant(VTy, Imms);
1396 auto FNeg =
B.buildFNeg(Ty == VTy ?
DstOp(
MI.getOperand(0)) :
DstOp(VTy), BV);
1398 B.buildBitcast(
MI.getOperand(0), FNeg);
1399 MI.eraseFromParent();
1404 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
1408 if (
MRI.getType(DstReg).isVector())
1414 return MRI.getType(SrcReg).getSizeInBits() <= 64;
1420 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
1422 MI.getOperand(0).setReg(SrcReg);
1430 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1432 LLT DstTy =
MRI.getType(DstReg);
1438 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1439 B.setInstrAndDebugLoc(
MI);
1449 if (Unmerge.getNumDefs() != 2)
1451 if (!
MRI.use_nodbg_empty(Unmerge.getReg(1)))
1454 LLT DstTy =
MRI.getType(Unmerge.getReg(0));
1466 if (!LowestVal || LowestVal->Value.getZExtValue() != DstTy.
getSizeInBytes())
1472 MatchInfo = ExtSrc1;
1482 MI.getOperand(0).setReg(
MI.getOperand(1).getReg());
1483 MI.getOperand(1).setReg(Dst1);
1484 MI.getOperand(2).setReg(SrcReg);
1495 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1501 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
1502 "Expected a G_MUL instruction");
1505 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1513class AArch64PostLegalizerLoweringImpl :
public Combiner {
1516 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig;
1520 AArch64PostLegalizerLoweringImpl(
1522 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1525 static const char *
getName() {
return "AArch6400PreLegalizerCombiner"; }
1530#define GET_GICOMBINER_CLASS_MEMBERS
1531#include "AArch64GenPostLegalizeGILowering.inc"
1532#undef GET_GICOMBINER_CLASS_MEMBERS
1535#define GET_GICOMBINER_IMPL
1536#include "AArch64GenPostLegalizeGILowering.inc"
1537#undef GET_GICOMBINER_IMPL
1539AArch64PostLegalizerLoweringImpl::AArch64PostLegalizerLoweringImpl(
1541 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1543 :
Combiner(MF, CInfo, nullptr, CSEInfo),
1544 Helper(Observer,
B,
true), RuleConfig(RuleConfig),
1547#include
"AArch64GenPostLegalizeGILowering.inc"
1552bool runPostLegalizerLowering(
1554 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig) {
1562 F.hasOptSize(),
F.hasMinSize());
1564 CInfo.MaxIterations = 1;
1567 CInfo.EnableFullDCE =
false;
1568 AArch64PostLegalizerLoweringImpl Impl(MF, CInfo,
nullptr,
1570 return Impl.combineMachineInstrs();
1577 AArch64PostLegalizerLoweringLegacy();
1579 StringRef getPassName()
const override {
1580 return "AArch64PostLegalizerLowering";
1584 void getAnalysisUsage(AnalysisUsage &AU)
const override;
1587 AArch64PostLegalizerLoweringImplRuleConfig RuleConfig;
1591void AArch64PostLegalizerLoweringLegacy::getAnalysisUsage(
1598AArch64PostLegalizerLoweringLegacy::AArch64PostLegalizerLoweringLegacy()
1599 : MachineFunctionPass(
ID) {
1600 if (!RuleConfig.parseCommandLineOption())
1604bool AArch64PostLegalizerLoweringLegacy::runOnMachineFunction(
1607 return runPostLegalizerLowering(MF, RuleConfig);
1610char AArch64PostLegalizerLoweringLegacy::ID = 0;
1612 "Lower AArch64 MachineInstrs after legalization",
false,
1615 "Lower AArch64 MachineInstrs after legalization",
false,
1620 std::make_unique<AArch64PostLegalizerLoweringImplRuleConfig>()) {
1621 if (!RuleConfig->parseCommandLineOption())
1634 const bool Changed = runPostLegalizerLowering(MF, *RuleConfig);
1646 return new AArch64PostLegalizerLoweringLegacy();
static bool isINSMask(ArrayRef< int > M, int NumInputElements, bool &DstIsLeft, int &Anomaly)
static unsigned getCmpOperandFoldingProfit(SDValue Op, bool AllowExtend)
Returns how profitable it is to fold a comparison's operand's shift and/or extension operations.
static bool shouldBeAdjustedToZero(SDValue LHS, const APInt &C, ISD::CondCode &CC)
This file declares the targeting of the Machinelegalizer class for AArch64.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define GET_GICOMBINER_CONSTRUCTOR_INITS
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This contains common combine transformations that may be used in a combine pass,or by the target else...
Option class for Targets to specify which operations are combined how and when.
This contains the base class for all Combiners generated by TableGen.
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...
static constexpr Value * getValue(Ty &ValueOrUse)
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
static bool isAtomic(MachineBasicBlock::iterator I)
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static StringRef getName(Value *V)
MachineRegisterInfo & MRI
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
~AArch64PostLegalizerLoweringPass()
AArch64PostLegalizerLoweringPass()
static const fltSemantics & IEEEdouble()
Class for arbitrary precision integers.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Represents analyses that only rely on functions' control flow.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ ICMP_ULT
unsigned less than
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
FunctionPass class - This class is used to implement most global optimizations.
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.
static constexpr LLT float64()
Get a 64-bit IEEE double value.
LLT changeElementCount(ElementCount EC) const
Return a vector or scalar with the same element type and the new element count.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
LLT getScalarType() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr ElementCount getElementCount() 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)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
static constexpr LLT float32()
Get a 32-bit IEEE float value.
static LLT floatIEEE(unsigned SizeInBits)
LLVM_ABI LegalizeResult lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by splitting it into simpler parts, hopefully understood by the target.
LLVM_ABI LegalizeResult fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
Legalize a vector instruction by splitting into multiple components, each acting on the same scalar t...
An RAII based helper class to modify MachineFunctionProperties when running pass.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineFunctionProperties & getProperties() const
Get the function properties.
Helper class to build MachineInstr.
MachineInstrBuilder buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
MachineInstrBuilder buildNot(const DstOp &Dst, const SrcOp &Src0)
Build and insert a bitwise not, NegOne = G_CONSTANT -1 Res = G_OR Op0, NegOne.
MachineInstrBuilder buildConcatVectors(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_CONCAT_VECTORS Op0, ...
MachineInstrBuilder buildExtractVectorElementConstant(const DstOp &Res, const SrcOp &Val, const int Idx)
Build and insert Res = G_EXTRACT_VECTOR_ELT Val, Idx.
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 buildInsertVectorElement(const DstOp &Res, const SrcOp &Val, const SrcOp &Elt, const SrcOp &Idx)
Build and insert Res = G_INSERT_VECTOR_ELT Val, Elt, Idx.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
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.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
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,...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Wrapper class representing virtual and physical registers.
static LLVM_ABI bool isReverseMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask swaps the order of elements from exactly one source vector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
constexpr LeafTy divideCoefficientBy(ScalarTy RHS) const
We do not provide the '/' operator here because division for polynomial types does not work in the sa...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool isVShiftRImm(Register Reg, const MachineRegisterInfo &MRI, LLT Ty, int64_t &Cnt)
void changeVectorFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2, bool &Invert)
Find the AArch64 condition codes necessary to represent P for a vector floating point comparison.
bool isCMN(const MachineInstr *MaybeSub, const CmpInst::Predicate &Pred, const MachineRegisterInfo &MRI)
static bool isLegalCmpImmed(const APInt &C)
isLegalCmpImmed -
bool expandVectorMOVImm(APInt Imm, SmallVectorImpl< ImmInsnModel > &Insn, const AArch64Subtarget &ST)
void expandMOVImm(uint64_t Imm, unsigned BitSize, SmallVectorImpl< ImmInsnModel > &Insn)
Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more real move-immediate instructions to...
operand_type_match m_Reg()
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
ImplicitDefMatch m_GImplicitDef()
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
bool isZIPMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut, unsigned &OperandOrderOut)
Return true for zip1 or zip2 masks of the form: <0, 8, 1, 9, 2, 10, 3, 11> (WhichResultOut = 0,...
@ Undef
Value of the register doesn't matter.
bool isEXTMask(ArrayRef< int > M, unsigned NumElts, bool &ReverseEXT, unsigned &Imm)
Check if an EXT instruction can handle the shuffle mask when the vector sources of the shuffle are di...
auto successors(const MachineBasicBlock *BB)
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
bool generatePerfectShuffle(ArrayRef< int > Mask, unsigned NumElts, SmallVector< ShuffleEntry > &Entries)
generatePerfectShuffle - Given a Mask, attempt to generate the optimal sequence of instructions using...
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64PostLegalizerLowering()
LLVM_ABI bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
bool isSingletonEXTMask(ArrayRef< int > M, unsigned NumElts, unsigned &Imm)
check if an EXT instruction can handle the shuffle mask when the vector sources of the shuffle are th...
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool isUZPMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut)
Return true for uzp1 or uzp2 masks of the form: <0, 2, 4, 6, 8, 10, 12, 14> or <1,...
bool isREVMask(ArrayRef< int > M, unsigned EltSize, unsigned NumElts, unsigned BlockSize)
isREVMask - Check if a vector shuffle corresponds to a REV instruction with the specified blocksize.
bool isUZP_v_undef_Mask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResult)
isUZP_v_undef_Mask - Special case of isUZPMask for canonical form of "vector_shuffle v,...
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
LLVM_ABI bool isBuildVectorAllOnes(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
bool isZIP_v_undef_Mask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResult)
isZIP_v_undef_Mask - Special case of isZIPMask for canonical form of "vector_shuffle v,...
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool isTRN_v_undef_Mask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResult)
isTRN_v_undef_Mask - Special case of isTRNMask for canonical form of "vector_shuffle v,...
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
bool isTRNMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut, unsigned &OperandOrderOut)
Return true for trn1 or trn2 masks of the form: <0, 8, 2, 10, 4, 12, 6, 14> (WhichResultOut = 0,...
LLVM_ABI int getSplatIndex(ArrayRef< int > Mask)
If all non-negative Mask elements are the same value, return that value.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Implement std::hash so that hash_code can be used in STL containers.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
@ SinglePass
Enables Observer-based DCE and additional heuristics that retry combining defined and used instructio...
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
ShuffleEntry - Represent a shuffle entry in the decomposion of a vector shuffle.