28#include "llvm/IR/IntrinsicsAArch64.h"
31#include <initializer_list>
33#define DEBUG_TYPE "aarch64-legalinfo"
67 std::initializer_list<LLT> PackedVectorAllTypeList = {
73 std::initializer_list<LLT> ScalarAndPtrTypesList = {s8, s16, s32, s64, p0};
77 const TargetMachine &TM = ST.getTargetLowering()->getTargetMachine();
80 if (!ST.hasNEON() || !ST.hasFPARMv8()) {
87 const bool HasFP16 = ST.hasFullFP16();
88 const LLT &MinFPScalar = HasFP16 ? s16 : s32;
90 const bool HasCSSC = ST.hasCSSC();
91 const bool HasRCPC3 = ST.hasRCPC3();
92 const bool HasSVE = ST.hasSVE();
95 {G_IMPLICIT_DEF, G_FREEZE, G_CONSTANT_FOLD_BARRIER})
96 .legalFor({p0, s8, s16, s32, s64})
97 .legalFor({v2s8, v4s8, v8s8, v16s8, v2s16, v4s16, v8s16, v2s32, v4s32,
99 .widenScalarToNextPow2(0)
112 .legalFor(PackedVectorAllTypeList)
126 .widenScalarToNextPow2(0)
131 .maxScalarIf(
typeInSet(0, {s64, p0}), 1, s32);
136 .widenScalarToNextPow2(1)
141 .maxScalarIf(
typeInSet(1, {s64, p0}), 0, s32)
142 .maxScalarIf(
typeInSet(1, {s128}), 0, s64);
145 .legalFor({s32, s64, v8s8, v16s8, v4s16, v8s16, v2s32, v4s32, v2s64})
146 .legalFor(HasSVE, {nxv16s8, nxv8s16, nxv4s32, nxv2s64})
147 .widenScalarToNextPow2(0)
155 return Query.
Types[0].getNumElements() <= 2;
160 return Query.
Types[0].getNumElements() <= 4;
165 return Query.
Types[0].getNumElements() <= 16;
172 .
legalFor({s32, s64, v8s8, v16s8, v4s16, v8s16, v2s32, v4s32, v2s64})
173 .widenScalarToNextPow2(0)
181 return Query.
Types[0].getNumElements() <= 2;
186 return Query.
Types[0].getNumElements() <= 4;
191 return Query.
Types[0].getNumElements() <= 16;
199 const auto &SrcTy = Query.
Types[0];
200 const auto &AmtTy = Query.
Types[1];
201 return !SrcTy.isVector() && SrcTy.getSizeInBits() == 32 &&
202 AmtTy.getSizeInBits() == 32;
216 .widenScalarToNextPow2(0)
230 .
legalFor({{p0, s64}, {v2p0, v2s64}})
231 .clampScalarOrElt(1, s64, s64)
237 .legalFor({s32, s64})
239 .clampScalar(0, s32, s64)
244 .lowerFor({s8, s16, s32, s64, v2s32, v4s32, v2s64})
253 .widenScalarToNextPow2(0, 32)
258 .legalFor({s64, v16s8, v8s16, v4s32})
262 .legalFor({v8s8, v16s8, v4s16, v8s16, v2s32, v4s32})
263 .legalFor(HasCSSC, {s32, s64})
264 .minScalar(HasCSSC, 0, s32)
273 .legalFor(PackedVectorAllTypeList)
277 return SrcTy.isScalar() && SrcTy.getSizeInBits() < 128;
281 [=](
const LegalityQuery &Query) {
return std::make_pair(0, v4s16); })
284 [=](
const LegalityQuery &Query) {
return std::make_pair(0, v2s32); })
285 .clampNumElements(0, v8s8, v16s8)
293 .legalFor({v8s8, v16s8, v4s16, v8s16, v2s32, v4s32})
297 {G_SADDE, G_SSUBE, G_UADDE, G_USUBE, G_SADDO, G_SSUBO, G_UADDO, G_USUBO})
298 .legalFor({{s32, s32}, {s64, s32}})
299 .clampScalar(0, s32, s64)
304 .customFor({{s32, s32}, {s32, s64}, {s64, s64}})
310 return Q.
Types[0].isScalar() && Q.
Types[1].getScalarSizeInBits() < 64;
316 .customFor({{s32, s32}, {s64, s64}});
320 .
legalFor(HasCSSC, {{s32, s32}, {s64, s64}})
321 .legalFor({{v8s8, v8s8}, {v16s8, v16s8}})
322 .customFor(!HasCSSC, {{s32, s32}, {s64, s64}})
323 .customFor({{s128, s128},
329 .clampScalar(0, s32, s128)
349 .widenScalarToNextPow2(1, 32)
366 .customFor(!HasCSSC, {s32, s64});
372 .widenScalarToNextPow2(0, 32)
384 .
legalFor({s32, s64, v4s16, v8s16, v2s32, v4s32, v2s64})
393 .legalFor({v8s8, v16s8, v4s16, v8s16, v2s32, v4s32, v2s64})
394 .legalFor(HasSVE, {nxv16s8, nxv8s16, nxv4s32, nxv2s64})
395 .clampNumElements(0, v8s8, v16s8)
404 {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FSQRT, G_FMAXNUM, G_FMINNUM,
405 G_FMAXIMUM, G_FMINIMUM, G_FCEIL, G_FFLOOR, G_FRINT, G_FNEARBYINT,
406 G_INTRINSIC_TRUNC, G_INTRINSIC_ROUND, G_INTRINSIC_ROUNDEVEN})
407 .legalFor({s32, s64, v2s32, v4s32, v2s64})
408 .legalFor(HasFP16, {s16, v4s16, v8s16})
418 .legalFor({s32, s64, v2s32, v4s32, v2s64})
419 .legalFor(HasFP16, {s16, v4s16, v8s16})
434 .legalFor({{s64, MinFPScalar}, {s64, s32}, {s64, s64}})
435 .libcallFor({{s64, s128}})
436 .minScalarOrElt(1, MinFPScalar);
439 G_FLOG10, G_FTAN, G_FEXP, G_FEXP2, G_FEXP10,
440 G_FACOS, G_FASIN, G_FATAN, G_FATAN2, G_FCOSH,
450 .
libcallFor({{s32, s32}, {s64, s32}, {s128, s32}});
455 .legalFor({{s64, s32}, {s64, s64}});
469 for (
unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
472 if (
Op == G_SEXTLOAD)
477 .legalForTypesWithMemDesc({{s32, p0, s8, 8},
485 {v2s32, p0, s64, 8}})
486 .widenScalarToNextPow2(0)
487 .clampScalar(0, s32, s64)
490 .unsupportedIfMemSizeNotPow2()
497 return ValTy.isPointerVector() && ValTy.getAddressSpace() == 0;
502 return HasRCPC3 && Query.
Types[0] == s128 &&
506 return Query.
Types[0] == s128 &&
509 .legalForTypesWithMemDesc({{s8, p0, s8, 8},
516 {v16s8, p0, s128, 8},
518 {v8s16, p0, s128, 8},
520 {v4s32, p0, s128, 8},
521 {v2s64, p0, s128, 8}})
523 .legalForTypesWithMemDesc(
524 {{s32, p0, s8, 8}, {s32, p0, s16, 8}, {s64, p0, s32, 8}})
525 .legalForTypesWithMemDesc({
527 {nxv16s8, p0, nxv16s8, 8},
528 {nxv8s16, p0, nxv8s16, 8},
529 {nxv4s32, p0, nxv4s32, 8},
530 {nxv2s64, p0, nxv2s64, 8},
532 .widenScalarToNextPow2(0, 8)
543 return Query.
Types[0].isScalar() &&
545 Query.
Types[0].getSizeInBits() > 32;
554 .customIf(IsPtrVecPred)
560 return HasRCPC3 && Query.
Types[0] == s128 &&
564 return Query.
Types[0] == s128 &&
567 .legalForTypesWithMemDesc(
568 {{s8, p0, s8, 8}, {s16, p0, s8, 8},
571 {s16, p0, s16, 8}, {s32, p0, s16, 8},
573 {s32, p0, s8, 8}, {s32, p0, s16, 8}, {s32, p0, s32, 8},
574 {s64, p0, s64, 8}, {s64, p0, s32, 8},
575 {p0, p0, s64, 8}, {s128, p0, s128, 8}, {v16s8, p0, s128, 8},
576 {v8s8, p0, s64, 8}, {v4s16, p0, s64, 8}, {v8s16, p0, s128, 8},
577 {v2s32, p0, s64, 8}, {v4s32, p0, s128, 8}, {v2s64, p0, s128, 8}})
578 .legalForTypesWithMemDesc({
583 {nxv16s8, p0, nxv16s8, 8},
584 {nxv8s16, p0, nxv8s16, 8},
585 {nxv4s32, p0, nxv4s32, 8},
586 {nxv2s64, p0, nxv2s64, 8},
588 .clampScalar(0, s8, s64)
591 return Query.
Types[0].isScalar() &&
595 .clampMaxNumElements(0, s8, 16)
604 return Query.
Types[0].getSizeInBits() ==
605 Query.
MMODescrs[0].MemoryTy.getSizeInBits();
611 .customIf(IsPtrVecPred)
629 {p0, v16s8, v16s8, 8},
630 {p0, v4s16, v4s16, 8},
631 {p0, v8s16, v8s16, 8},
632 {p0, v2s32, v2s32, 8},
633 {p0, v4s32, v4s32, 8},
634 {p0, v2s64, v2s64, 8},
640 auto IndexedLoadBasicPred = [=](
const LegalityQuery &Query) {
668 return MemTy == s8 || MemTy == s16;
670 return MemTy == s8 || MemTy == s16 || MemTy == s32;
678 .widenScalarToNextPow2(0)
682 .legalFor(HasFP16, {s16})
683 .clampScalar(0, MinFPScalar, s128);
687 .
legalFor({{s32, s32}, {s32, s64}, {s32, p0}})
696 return Ty.isVector() && !SrcTy.isPointerVector() &&
697 Ty.getElementType() != SrcTy.getElementType();
705 return Query.
Types[1].isPointerVector();
722 .legalFor(HasFP16, {{s32, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
731 return Ty.isVector() && !SrcTy.isPointerVector() &&
732 Ty.getElementType() != SrcTy.getElementType();
735 .clampNumElements(1, v4s16, v8s16)
743 unsigned DstSize = Query.
Types[0].getSizeInBits();
746 if (Query.
Types[0].isVector())
749 if (DstSize < 8 || DstSize >= 128 || !
isPowerOf2_32(DstSize))
757 unsigned SrcSize = SrcTy.getSizeInBits();
764 .legalIf(ExtLegalFunc)
765 .
legalFor({{v8s16, v8s8}, {v4s32, v4s16}, {v2s64, v2s32}})
766 .clampScalar(0, s64, s64)
773 return (Query.
Types[0].getScalarSizeInBits() >
774 Query.
Types[1].getScalarSizeInBits() * 2) &&
775 Query.
Types[0].isVector() &&
776 (Query.
Types[1].getScalarSizeInBits() == 8 ||
777 Query.
Types[1].getScalarSizeInBits() == 16);
779 .clampMinNumElements(1, s8, 8)
784 .
legalFor({{v8s8, v8s16}, {v4s16, v4s32}, {v2s32, v2s64}})
795 return DstTy.
isVector() && SrcTy.getSizeInBits() > 128 &&
798 .clampMinNumElements(0, s8, 8)
803 .legalFor({{v8s8, v8s16}, {v4s16, v4s32}, {v2s32, v2s64}});
807 .legalFor(PackedVectorAllTypeList)
818 {{s16, s32}, {s16, s64}, {s32, s64}, {v4s16, v4s32}, {v2s32, v2s64}})
819 .libcallFor({{s16, s128}, {s32, s128}, {s64, s128}})
820 .clampNumElements(0, v4s16, v4s16)
826 {{s32, s16}, {s64, s16}, {s64, s32}, {v4s32, v4s16}, {v2s64, v2s32}})
827 .libcallFor({{s128, s64}, {s128, s32}, {s128, s16}})
828 .clampNumElements(0, v4s32, v4s32)
834 .legalFor({{s32, s32},
842 {{s32, s16}, {s64, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
849 return Query.
Types[1] == s16 && Query.
Types[0].getSizeInBits() > 64;
858 return Query.
Types[0].getScalarSizeInBits() <= 64 &&
859 Query.
Types[0].getScalarSizeInBits() >
860 Query.
Types[1].getScalarSizeInBits();
865 return Query.
Types[1].getScalarSizeInBits() <= 64 &&
866 Query.
Types[0].getScalarSizeInBits() <
867 Query.
Types[1].getScalarSizeInBits();
870 .clampNumElements(0, v4s16, v8s16)
874 {{s32, s128}, {s64, s128}, {s128, s128}, {s128, s32}, {s128, s64}});
877 .legalFor({{s32, s32},
886 {{s16, s16}, {s32, s16}, {s64, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
894 return Query.
Types[1] == s16 && Query.
Types[0].getSizeInBits() > 64;
904 unsigned ITySize = Query.
Types[0].getScalarSizeInBits();
905 return (ITySize == 16 || ITySize == 32 || ITySize == 64) &&
906 ITySize > Query.
Types[1].getScalarSizeInBits();
911 unsigned FTySize = Query.
Types[1].getScalarSizeInBits();
912 return (FTySize == 16 || FTySize == 32 || FTySize == 64) &&
913 Query.
Types[0].getScalarSizeInBits() < FTySize;
922 .legalFor({{s32, s32},
930 {{s16, s32}, {s16, s64}, {v4s16, v4s16}, {v8s16, v8s16}})
937 return Query.
Types[1].isVector() &&
938 Query.
Types[1].getScalarSizeInBits() == 64 &&
939 Query.
Types[0].getScalarSizeInBits() == 16;
941 .widenScalarOrEltToNextPow2OrMinSize(0, HasFP16 ? 16 : 32)
945 return Query.
Types[0].getScalarSizeInBits() == 32 &&
946 Query.
Types[1].getScalarSizeInBits() == 64;
951 return Query.
Types[1].getScalarSizeInBits() <= 64 &&
952 Query.
Types[0].getScalarSizeInBits() <
953 Query.
Types[1].getScalarSizeInBits();
958 return Query.
Types[0].getScalarSizeInBits() <= 64 &&
959 Query.
Types[0].getScalarSizeInBits() >
960 Query.
Types[1].getScalarSizeInBits();
963 .clampNumElements(0, v4s16, v8s16)
977 .clampScalar(0, s32, s32);
981 .
legalFor({{s32, s32}, {s64, s32}, {p0, s32}})
982 .widenScalarToNextPow2(0)
1001 .
legalFor({{s64, p0}, {v2s64, v2p0}})
1002 .widenScalarToNextPow2(0, 64)
1008 return Query.
Types[0].getSizeInBits() != Query.
Types[1].getSizeInBits();
1010 .legalFor({{p0, s64}, {v2p0, v2s64}})
1011 .clampMaxNumElements(1, s64, 2);
1018 .legalForCartesianProduct({s64, v8s8, v4s16, v2s32})
1019 .legalForCartesianProduct({s128, v16s8, v8s16, v4s32, v2s64, v2p0})
1024 return DstTy.
isScalar() && SrcTy.isVector() &&
1025 SrcTy.getScalarSizeInBits() == 1;
1028 return Query.
Types[0].isVector() != Query.
Types[1].isVector();
1042 .clampScalar(0, s8, s64)
1049 bool UseOutlineAtomics = ST.outlineAtomics() && !ST.hasLSE();
1052 .
legalFor(!UseOutlineAtomics, {{s32, p0}, {s64, p0}})
1053 .customFor(!UseOutlineAtomics, {{s128, p0}})
1054 .libcallFor(UseOutlineAtomics,
1055 {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}, {s128, p0}})
1056 .clampScalar(0, s32, s64);
1059 G_ATOMICRMW_SUB, G_ATOMICRMW_AND, G_ATOMICRMW_OR,
1061 .legalFor(!UseOutlineAtomics, {{s32, p0}, {s64, p0}})
1062 .libcallFor(UseOutlineAtomics,
1063 {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
1064 .clampScalar(0, s32, s64);
1069 {G_ATOMICRMW_MIN, G_ATOMICRMW_MAX, G_ATOMICRMW_UMIN, G_ATOMICRMW_UMAX})
1071 .clampScalar(0, s32, s64);
1076 for (
unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
1077 unsigned BigTyIdx =
Op == G_MERGE_VALUES ? 0 : 1;
1078 unsigned LitTyIdx =
Op == G_MERGE_VALUES ? 1 : 0;
1085 switch (Q.
Types[BigTyIdx].getSizeInBits()) {
1093 switch (Q.
Types[LitTyIdx].getSizeInBits()) {
1107 .
legalFor(HasSVE, {{s16, nxv16s8, s64},
1108 {s16, nxv8s16, s64},
1109 {s32, nxv4s32, s64},
1110 {s64, nxv2s64, s64}})
1112 const LLT &EltTy = Query.
Types[1].getElementType();
1113 if (Query.
Types[1].isScalableVector())
1115 return Query.
Types[0] != EltTy;
1120 return VecTy == v8s8 || VecTy == v16s8 || VecTy == v2s16 ||
1121 VecTy == v4s16 || VecTy == v8s16 || VecTy == v2s32 ||
1122 VecTy == v4s32 || VecTy == v2s64 || VecTy == v2p0;
1128 return Query.
Types[1].isFixedVector() &&
1129 Query.
Types[1].getNumElements() <= 2;
1134 return Query.
Types[1].isFixedVector() &&
1135 Query.
Types[1].getNumElements() <= 4;
1140 return Query.
Types[1].isFixedVector() &&
1141 Query.
Types[1].getNumElements() <= 8;
1146 return Query.
Types[1].isFixedVector() &&
1147 Query.
Types[1].getNumElements() <= 16;
1150 .minScalarOrElt(0, s8)
1161 typeInSet(0, {v8s8, v16s8, v4s16, v8s16, v2s32, v4s32, v2s64, v2p0}))
1162 .legalFor(HasSVE, {{nxv16s8, s32, s64},
1163 {nxv8s16, s32, s64},
1164 {nxv4s32, s32, s64},
1165 {nxv2s64, s64, s64}})
1184 .clampNumElements(0, v4s32, v4s32)
1202 {v8s8, v16s8, v4s16, v8s16, v2s32, v4s32, v2s64}, DstTy);
1208 return !Query.
Types[0].isVector() || !Query.
Types[1].isVector();
1212 return Query.
Types[0].isVector() && Query.
Types[1].isVector() &&
1213 Query.
Types[0].getNumElements() >
1214 Query.
Types[1].getNumElements();
1220 return Query.
Types[0].isVector() && Query.
Types[1].isVector() &&
1221 Query.
Types[0].getNumElements() <
1222 Query.
Types[1].getNumElements();
1225 .widenScalarOrEltToNextPow2OrMinSize(0, 8)
1238 .
legalFor({{v16s8, v8s8}, {v8s16, v4s16}, {v4s32, v2s32}})
1241 return Query.
Types[0].getSizeInBits() <= 128 &&
1242 Query.
Types[1].getSizeInBits() <= 64;
1251 SrcTy.getNumElements())));
1255 .
legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
1261 .
legalFor(HasSVE, {{nxv4s32, s32}, {nxv2s64, s64}});
1280 .customForCartesianProduct({p0}, {s8}, {s64})
1284 .legalForCartesianProduct({p0}, {p0}, {s64})
1300 .
legalFor({{s32, v2s32}, {s32, v4s32}, {s64, v2s64}})
1301 .legalFor(HasFP16, {{s16, v4s16}, {s16, v8s16}})
1302 .minScalarOrElt(0, MinFPScalar)
1344 G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM})
1345 .legalFor({{s32, v2s32}, {s32, v4s32}, {s64, v2s64}})
1346 .legalFor(HasFP16, {{s16, v4s16}, {s16, v8s16}})
1347 .minScalarOrElt(0, MinFPScalar)
1362 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX})
1363 .legalFor({{s8, v8s8},
1371 return Query.
Types[1].isVector() &&
1372 Query.
Types[1].getElementType() != s8 &&
1373 Query.
Types[1].getNumElements() & 1;
1376 .clampMaxNumElements(1, s64, 2)
1384 {G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
1391 if (SrcTy.isScalar())
1396 return SrcTy.getSizeInBits() > 64;
1400 return std::make_pair(1, SrcTy.divide(2));
1410 G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE})
1420 verify(*ST.getInstrInfo());
1429 switch (
MI.getOpcode()) {
1433 case TargetOpcode::G_VAARG:
1434 return legalizeVaArg(
MI,
MRI, MIRBuilder);
1435 case TargetOpcode::G_LOAD:
1436 case TargetOpcode::G_STORE:
1437 return legalizeLoadStore(
MI,
MRI, MIRBuilder, Observer);
1438 case TargetOpcode::G_SHL:
1439 case TargetOpcode::G_ASHR:
1440 case TargetOpcode::G_LSHR:
1441 return legalizeShlAshrLshr(
MI,
MRI, MIRBuilder, Observer);
1442 case TargetOpcode::G_GLOBAL_VALUE:
1443 return legalizeSmallCMGlobalValue(
MI,
MRI, MIRBuilder, Observer);
1444 case TargetOpcode::G_SBFX:
1445 case TargetOpcode::G_UBFX:
1446 return legalizeBitfieldExtract(
MI,
MRI, Helper);
1447 case TargetOpcode::G_FSHL:
1448 case TargetOpcode::G_FSHR:
1449 return legalizeFunnelShift(
MI,
MRI, MIRBuilder, Observer, Helper);
1450 case TargetOpcode::G_ROTR:
1451 return legalizeRotate(
MI,
MRI, Helper);
1452 case TargetOpcode::G_CTPOP:
1453 return legalizeCTPOP(
MI,
MRI, Helper);
1454 case TargetOpcode::G_ATOMIC_CMPXCHG:
1455 return legalizeAtomicCmpxchg128(
MI,
MRI, Helper);
1456 case TargetOpcode::G_CTTZ:
1457 return legalizeCTTZ(
MI, Helper);
1458 case TargetOpcode::G_BZERO:
1459 case TargetOpcode::G_MEMCPY:
1460 case TargetOpcode::G_MEMMOVE:
1461 case TargetOpcode::G_MEMSET:
1462 return legalizeMemOps(
MI, Helper);
1463 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1464 return legalizeExtractVectorElt(
MI,
MRI, Helper);
1465 case TargetOpcode::G_DYN_STACKALLOC:
1466 return legalizeDynStackAlloc(
MI, Helper);
1467 case TargetOpcode::G_PREFETCH:
1468 return legalizePrefetch(
MI, Helper);
1469 case TargetOpcode::G_ABS:
1471 case TargetOpcode::G_ICMP:
1472 return legalizeICMP(
MI,
MRI, MIRBuilder);
1473 case TargetOpcode::G_BITCAST:
1474 return legalizeBitcast(
MI, Helper);
1482 assert(
MI.getOpcode() == TargetOpcode::G_BITCAST &&
"Unexpected opcode");
1483 auto [DstReg, DstTy, SrcReg, SrcTy] =
MI.getFirst2RegLLTs();
1486 if (!DstTy.isScalar() || !SrcTy.isVector() ||
1491 MI.eraseFromParent();
1500 assert(
MI.getOpcode() == TargetOpcode::G_FSHL ||
1501 MI.getOpcode() == TargetOpcode::G_FSHR);
1505 Register ShiftNo =
MI.getOperand(3).getReg();
1506 LLT ShiftTy =
MRI.getType(ShiftNo);
1511 LLT OperationTy =
MRI.getType(
MI.getOperand(0).getReg());
1515 if (!VRegAndVal || VRegAndVal->Value.urem(
BitWidth) == 0)
1521 Amount =
MI.getOpcode() == TargetOpcode::G_FSHL ?
BitWidth - Amount : Amount;
1525 if (ShiftTy.
getSizeInBits() == 64 &&
MI.getOpcode() == TargetOpcode::G_FSHR &&
1532 if (
MI.getOpcode() == TargetOpcode::G_FSHR) {
1534 MI.getOperand(3).setReg(Cast64.getReg(0));
1539 else if (
MI.getOpcode() == TargetOpcode::G_FSHL) {
1540 MIRBuilder.
buildInstr(TargetOpcode::G_FSHR, {
MI.getOperand(0).getReg()},
1541 {
MI.getOperand(1).getReg(),
MI.getOperand(2).getReg(),
1543 MI.eraseFromParent();
1552 Register SrcReg1 =
MI.getOperand(2).getReg();
1553 Register SrcReg2 =
MI.getOperand(3).getReg();
1554 LLT DstTy =
MRI.getType(DstReg);
1555 LLT SrcTy =
MRI.getType(SrcReg1);
1572 MIRBuilder.
buildNot(DstReg, CmpReg);
1574 MI.eraseFromParent();
1584 LLT AmtTy =
MRI.getType(AmtReg);
1590 MI.getOperand(2).setReg(NewAmt.getReg(0));
1595bool AArch64LegalizerInfo::legalizeSmallCMGlobalValue(
1598 assert(
MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
1603 auto &GlobalOp =
MI.getOperand(1);
1605 if (GlobalOp.isSymbol())
1607 const auto* GV = GlobalOp.getGlobal();
1608 if (GV->isThreadLocal())
1611 auto &
TM = ST->getTargetLowering()->getTargetMachine();
1612 unsigned OpFlags = ST->ClassifyGlobalReference(GV, TM);
1617 auto Offset = GlobalOp.getOffset();
1622 MRI.setRegClass(ADRP.getReg(0), &AArch64::GPR64RegClass);
1639 "Should not have folded in an offset for a tagged global!");
1641 .addGlobalAddress(GV, 0x100000000,
1644 MRI.setRegClass(ADRP.getReg(0), &AArch64::GPR64RegClass);
1647 MIRBuilder.
buildInstr(AArch64::G_ADD_LOW, {DstReg}, {ADRP})
1648 .addGlobalAddress(GV,
Offset,
1650 MI.eraseFromParent();
1659 auto LowerUnaryOp = [&
MI, &MIB](
unsigned Opcode) {
1661 MI.eraseFromParent();
1664 auto LowerBinOp = [&
MI, &MIB](
unsigned Opcode) {
1666 {
MI.getOperand(2),
MI.getOperand(3)});
1667 MI.eraseFromParent();
1670 auto LowerTriOp = [&
MI, &MIB](
unsigned Opcode) {
1672 {
MI.getOperand(2),
MI.getOperand(3),
MI.getOperand(4)});
1673 MI.eraseFromParent();
1678 switch (IntrinsicID) {
1679 case Intrinsic::vacopy: {
1680 unsigned PtrSize = ST->isTargetILP32() ? 4 : 8;
1681 unsigned VaListSize =
1682 (ST->isTargetDarwin() || ST->isTargetWindows())
1684 : ST->isTargetILP32() ? 20 : 32;
1692 VaListSize,
Align(PtrSize)));
1696 VaListSize,
Align(PtrSize)));
1697 MI.eraseFromParent();
1700 case Intrinsic::get_dynamic_area_offset: {
1702 MI.eraseFromParent();
1705 case Intrinsic::aarch64_mops_memset_tag: {
1706 assert(
MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
1709 auto &
Value =
MI.getOperand(3);
1711 Value.setReg(ExtValueReg);
1714 case Intrinsic::aarch64_prefetch: {
1715 auto &AddrVal =
MI.getOperand(1);
1717 int64_t IsWrite =
MI.getOperand(2).getImm();
1718 int64_t
Target =
MI.getOperand(3).getImm();
1719 int64_t IsStream =
MI.getOperand(4).getImm();
1720 int64_t IsData =
MI.getOperand(5).getImm();
1722 unsigned PrfOp = (IsWrite << 4) |
1728 MI.eraseFromParent();
1731 case Intrinsic::aarch64_neon_uaddv:
1732 case Intrinsic::aarch64_neon_saddv:
1733 case Intrinsic::aarch64_neon_umaxv:
1734 case Intrinsic::aarch64_neon_smaxv:
1735 case Intrinsic::aarch64_neon_uminv:
1736 case Intrinsic::aarch64_neon_sminv: {
1737 bool IsSigned = IntrinsicID == Intrinsic::aarch64_neon_saddv ||
1738 IntrinsicID == Intrinsic::aarch64_neon_smaxv ||
1739 IntrinsicID == Intrinsic::aarch64_neon_sminv;
1741 auto OldDst =
MI.getOperand(0).getReg();
1742 auto OldDstTy =
MRI.getType(OldDst);
1743 LLT NewDstTy =
MRI.getType(
MI.getOperand(2).getReg()).getElementType();
1744 if (OldDstTy == NewDstTy)
1747 auto NewDst =
MRI.createGenericVirtualRegister(NewDstTy);
1750 MI.getOperand(0).setReg(NewDst);
1754 MIB.
buildExtOrTrunc(IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT,
1759 case Intrinsic::aarch64_neon_uaddlp:
1760 case Intrinsic::aarch64_neon_saddlp: {
1761 unsigned Opc = IntrinsicID == Intrinsic::aarch64_neon_uaddlp
1763 : AArch64::G_SADDLP;
1765 MI.eraseFromParent();
1769 case Intrinsic::aarch64_neon_uaddlv:
1770 case Intrinsic::aarch64_neon_saddlv: {
1771 unsigned Opc = IntrinsicID == Intrinsic::aarch64_neon_uaddlv
1773 : AArch64::G_SADDLV;
1776 LLT DstTy =
MRI.getType(DstReg);
1800 MI.eraseFromParent();
1804 case Intrinsic::aarch64_neon_smax:
1805 return LowerBinOp(TargetOpcode::G_SMAX);
1806 case Intrinsic::aarch64_neon_smin:
1807 return LowerBinOp(TargetOpcode::G_SMIN);
1808 case Intrinsic::aarch64_neon_umax:
1809 return LowerBinOp(TargetOpcode::G_UMAX);
1810 case Intrinsic::aarch64_neon_umin:
1811 return LowerBinOp(TargetOpcode::G_UMIN);
1812 case Intrinsic::aarch64_neon_fmax:
1813 return LowerBinOp(TargetOpcode::G_FMAXIMUM);
1814 case Intrinsic::aarch64_neon_fmin:
1815 return LowerBinOp(TargetOpcode::G_FMINIMUM);
1816 case Intrinsic::aarch64_neon_fmaxnm:
1817 return LowerBinOp(TargetOpcode::G_FMAXNUM);
1818 case Intrinsic::aarch64_neon_fminnm:
1819 return LowerBinOp(TargetOpcode::G_FMINNUM);
1820 case Intrinsic::aarch64_neon_smull:
1821 return LowerBinOp(AArch64::G_SMULL);
1822 case Intrinsic::aarch64_neon_umull:
1823 return LowerBinOp(AArch64::G_UMULL);
1824 case Intrinsic::aarch64_neon_sabd:
1825 return LowerBinOp(TargetOpcode::G_ABDS);
1826 case Intrinsic::aarch64_neon_uabd:
1827 return LowerBinOp(TargetOpcode::G_ABDU);
1828 case Intrinsic::aarch64_neon_abs: {
1830 MIB.
buildInstr(TargetOpcode::G_ABS, {
MI.getOperand(0)}, {
MI.getOperand(2)});
1831 MI.eraseFromParent();
1834 case Intrinsic::aarch64_neon_sqadd: {
1835 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector())
1836 return LowerBinOp(TargetOpcode::G_SADDSAT);
1839 case Intrinsic::aarch64_neon_sqsub: {
1840 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector())
1841 return LowerBinOp(TargetOpcode::G_SSUBSAT);
1844 case Intrinsic::aarch64_neon_uqadd: {
1845 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector())
1846 return LowerBinOp(TargetOpcode::G_UADDSAT);
1849 case Intrinsic::aarch64_neon_uqsub: {
1850 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector())
1851 return LowerBinOp(TargetOpcode::G_USUBSAT);
1854 case Intrinsic::aarch64_neon_udot:
1855 return LowerTriOp(AArch64::G_UDOT);
1856 case Intrinsic::aarch64_neon_sdot:
1857 return LowerTriOp(AArch64::G_SDOT);
1858 case Intrinsic::aarch64_neon_sqxtn:
1859 return LowerUnaryOp(TargetOpcode::G_TRUNC_SSAT_S);
1860 case Intrinsic::aarch64_neon_sqxtun:
1861 return LowerUnaryOp(TargetOpcode::G_TRUNC_SSAT_U);
1862 case Intrinsic::aarch64_neon_uqxtn:
1863 return LowerUnaryOp(TargetOpcode::G_TRUNC_USAT_U);
1865 case Intrinsic::vector_reverse:
1873bool AArch64LegalizerInfo::legalizeShlAshrLshr(
1876 assert(
MI.getOpcode() == TargetOpcode::G_ASHR ||
1877 MI.getOpcode() == TargetOpcode::G_LSHR ||
1878 MI.getOpcode() == TargetOpcode::G_SHL);
1891 MI.getOperand(2).setReg(ExtCst.getReg(0));
1912bool AArch64LegalizerInfo::legalizeLoadStore(
1915 assert(
MI.getOpcode() == TargetOpcode::G_STORE ||
1916 MI.getOpcode() == TargetOpcode::G_LOAD);
1927 const LLT ValTy =
MRI.getType(ValReg);
1932 bool IsLoad =
MI.getOpcode() == TargetOpcode::G_LOAD;
1936 ST->hasLSE2() && ST->hasRCPC3() && (IsLoadAcquire || IsStoreRelease);
1942 Opcode = IsLoad ? AArch64::LDIAPPX : AArch64::STILPX;
1948 assert(ST->hasLSE2() &&
"ldp/stp not single copy atomic without +lse2");
1950 Opcode = IsLoad ? AArch64::LDPXi : AArch64::STPXi;
1953 MachineInstrBuilder NewI;
1955 NewI = MIRBuilder.
buildInstr(Opcode, {s64, s64}, {});
1961 Opcode, {}, {
Split->getOperand(0),
Split->getOperand(1)});
1965 NewI.
addUse(
MI.getOperand(1).getReg());
1976 *
MRI.getTargetRegisterInfo(),
1977 *ST->getRegBankInfo());
1978 MI.eraseFromParent();
1984 LLVM_DEBUG(
dbgs() <<
"Tried to do custom legalization on wrong load/store");
1990 auto &MMO = **
MI.memoperands_begin();
1993 if (
MI.getOpcode() == TargetOpcode::G_STORE) {
1997 auto NewLoad = MIRBuilder.
buildLoad(NewTy,
MI.getOperand(1), MMO);
2000 MI.eraseFromParent();
2007 MachineFunction &MF = MIRBuilder.
getMF();
2008 Align Alignment(
MI.getOperand(2).getImm());
2010 Register ListPtr =
MI.getOperand(1).getReg();
2012 LLT PtrTy =
MRI.getType(ListPtr);
2022 MachineInstrBuilder DstPtr;
2023 if (Alignment > PtrAlign) {
2027 auto ListTmp = MIRBuilder.
buildPtrAdd(PtrTy,
List, AlignMinus1.getReg(0));
2032 LLT ValTy =
MRI.getType(Dst);
2037 ValTy, std::max(Alignment, PtrAlign)));
2048 MI.eraseFromParent();
2052bool AArch64LegalizerInfo::legalizeBitfieldExtract(
2083 MachineIRBuilder &MIRBuilder = Helper.
MIRBuilder;
2086 LLT Ty =
MRI.getType(Val);
2090 "Expected src and dst to have the same type!");
2098 auto Add = MIRBuilder.
buildAdd(s64, CTPOP1, CTPOP2);
2101 MI.eraseFromParent();
2105 if (!ST->hasNEON() ||
2106 MI.getMF()->getFunction().hasFnAttribute(Attribute::NoImplicitFloat)) {
2118 assert((Size == 32 || Size == 64 || Size == 128) &&
"Expected only 32, 64, or 128 bit scalars!");
2120 Val = MIRBuilder.buildZExt(LLT::scalar(64), Val).getReg(0);
2132 LLT Dt = Ty == LLT::fixed_vector(2, 64) ? LLT::fixed_vector(4, 32) : Ty;
2133 auto Zeros = MIRBuilder.buildConstant(Dt, 0);
2134 auto Ones = MIRBuilder.buildConstant(VTy, 1);
2135 MachineInstrBuilder Sum;
2137 if (Ty == LLT::fixed_vector(2, 64)) {
2139 MIRBuilder.buildInstr(AArch64::G_UDOT, {Dt}, {Zeros, Ones, CTPOP});
2140 Sum = MIRBuilder.buildInstr(AArch64::G_UADDLP, {Ty}, {UDOT});
2142 Sum = MIRBuilder.
buildInstr(AArch64::G_UDOT, {Dt}, {Zeros, Ones,
CTPOP});
2144 Sum = MIRBuilder.
buildInstr(AArch64::G_UDOT, {Dt}, {Zeros, Ones,
CTPOP});
2150 MI.eraseFromParent();
2158 Opc = Intrinsic::aarch64_neon_uaddlv;
2159 HAddTys.push_back(LLT::scalar(32));
2161 Opc = Intrinsic::aarch64_neon_uaddlp;
2164 Opc = Intrinsic::aarch64_neon_uaddlp;
2168 Opc = Intrinsic::aarch64_neon_uaddlp;
2173 Opc = Intrinsic::aarch64_neon_uaddlp;
2176 Opc = Intrinsic::aarch64_neon_uaddlp;
2182 for (
LLT HTy : HAddTys) {
2192 MI.eraseFromParent();
2196bool AArch64LegalizerInfo::legalizeAtomicCmpxchg128(
2198 MachineIRBuilder &MIRBuilder = Helper.
MIRBuilder;
2200 auto Addr =
MI.getOperand(1).getReg();
2201 auto DesiredI = MIRBuilder.
buildUnmerge({s64, s64},
MI.getOperand(2));
2202 auto NewI = MIRBuilder.
buildUnmerge({s64, s64},
MI.getOperand(3));
2203 auto DstLo =
MRI.createGenericVirtualRegister(s64);
2204 auto DstHi =
MRI.createGenericVirtualRegister(s64);
2206 MachineInstrBuilder CAS;
2217 auto Ordering = (*
MI.memoperands_begin())->getMergedOrdering();
2221 Opcode = AArch64::CASPAX;
2224 Opcode = AArch64::CASPLX;
2228 Opcode = AArch64::CASPALX;
2231 Opcode = AArch64::CASPX;
2236 auto CASDst =
MRI.createGenericVirtualRegister(s128);
2237 auto CASDesired =
MRI.createGenericVirtualRegister(s128);
2238 auto CASNew =
MRI.createGenericVirtualRegister(s128);
2239 MIRBuilder.
buildInstr(TargetOpcode::REG_SEQUENCE, {CASDesired}, {})
2240 .addUse(DesiredI->getOperand(0).getReg())
2242 .
addUse(DesiredI->getOperand(1).getReg())
2243 .
addImm(AArch64::subo64);
2244 MIRBuilder.
buildInstr(TargetOpcode::REG_SEQUENCE, {CASNew}, {})
2248 .
addImm(AArch64::subo64);
2250 CAS = MIRBuilder.
buildInstr(Opcode, {CASDst}, {CASDesired, CASNew, Addr});
2258 auto Ordering = (*
MI.memoperands_begin())->getMergedOrdering();
2262 Opcode = AArch64::CMP_SWAP_128_ACQUIRE;
2265 Opcode = AArch64::CMP_SWAP_128_RELEASE;
2269 Opcode = AArch64::CMP_SWAP_128;
2272 Opcode = AArch64::CMP_SWAP_128_MONOTONIC;
2276 auto Scratch =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2277 CAS = MIRBuilder.
buildInstr(Opcode, {DstLo, DstHi, Scratch},
2278 {Addr, DesiredI->getOperand(0),
2279 DesiredI->getOperand(1), NewI->
getOperand(0),
2285 *
MRI.getTargetRegisterInfo(),
2286 *ST->getRegBankInfo());
2289 MI.eraseFromParent();
2295 MachineIRBuilder &MIRBuilder = Helper.
MIRBuilder;
2296 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
2297 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
2299 MIRBuilder.
buildCTLZ(
MI.getOperand(0).getReg(), BitReverse);
2300 MI.eraseFromParent();
2306 MachineIRBuilder &MIRBuilder = Helper.
MIRBuilder;
2309 if (
MI.getOpcode() == TargetOpcode::G_MEMSET) {
2312 auto &
Value =
MI.getOperand(1);
2315 Value.setReg(ExtValueReg);
2322bool AArch64LegalizerInfo::legalizeExtractVectorElt(
2336bool AArch64LegalizerInfo::legalizeDynStackAlloc(
2338 MachineFunction &MF = *
MI.getParent()->getParent();
2339 MachineIRBuilder &MIRBuilder = Helper.
MIRBuilder;
2340 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
2352 Register AllocSize =
MI.getOperand(1).getReg();
2356 "Unexpected type for dynamic alloca");
2358 "Unexpected type for dynamic alloca");
2360 LLT PtrTy =
MRI.getType(Dst);
2366 MIRBuilder.
buildInstr(AArch64::PROBED_STACKALLOC_DYN, {}, {SPTmp});
2367 MRI.setRegClass(NewMI.getReg(0), &AArch64::GPR64commonRegClass);
2368 MIRBuilder.
setInsertPt(*NewMI->getParent(), NewMI);
2371 MI.eraseFromParent();
2378 auto &AddrVal =
MI.getOperand(0);
2380 int64_t IsWrite =
MI.getOperand(1).getImm();
2381 int64_t Locality =
MI.getOperand(2).getImm();
2382 int64_t
IsData =
MI.getOperand(3).getImm();
2384 bool IsStream = Locality == 0;
2385 if (Locality != 0) {
2386 assert(Locality <= 3 &&
"Prefetch locality out-of-range");
2390 Locality = 3 - Locality;
2393 unsigned PrfOp = (IsWrite << 4) | (!IsData << 3) | (Locality << 1) | IsStream;
2396 MI.eraseFromParent();
unsigned const MachineRegisterInfo * MRI
static void matchLDPSTPAddrMode(Register Root, Register &Base, int &Offset, MachineRegisterInfo &MRI)
This file declares the targeting of the Machinelegalizer class for AArch64.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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)
static constexpr MCPhysReg SPReg
bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override
Called for instructions with the Custom LegalizationAction.
bool legalizeIntrinsic(LegalizerHelper &Helper, MachineInstr &MI) const override
AArch64LegalizerInfo(const AArch64Subtarget &ST)
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
int64_t getSExtValue() const
Get sign extended value.
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
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.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
static constexpr LLT scalable_vector(unsigned MinNumElements, unsigned ScalarSizeInBits)
Get a low-level scalable vector of some number of elements and element width.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
constexpr bool isPointerVector() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
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 LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
constexpr ElementCount getElementCount() const
constexpr LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
constexpr LLT changeElementCount(ElementCount EC) const
Return a vector or scalar with the same element type and the new element count.
LLVM_ABI void computeTables()
Compute any ancillary tables needed to quickly decide how an operation should be handled.
LegalizeRuleSet & minScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at least as wide as Ty.
LegalizeRuleSet & widenScalarOrEltToNextPow2OrMinSize(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar or vector element type to the next power of two that is at least MinSize.
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & maxScalarEltSameAsIf(LegalityPredicate Predicate, unsigned TypeIdx, unsigned SmallTypeIdx)
Conditionally narrow the scalar or elt to match the size of another.
LegalizeRuleSet & unsupported()
The instruction is unsupported.
LegalizeRuleSet & scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx)
Change the type TypeIdx to have the same scalar size as type SameSizeIdx.
LegalizeRuleSet & bitcastIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
The specified type index is coerced if predicate is true.
LegalizeRuleSet & libcallFor(std::initializer_list< LLT > Types)
LegalizeRuleSet & maxScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at most as wide as Ty.
LegalizeRuleSet & minScalarOrElt(unsigned TypeIdx, const LLT Ty)
Ensure the scalar or element is at least as wide as Ty.
LegalizeRuleSet & clampMaxNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MaxElements)
Limit the number of elements in EltTy vectors to at most MaxElements.
LegalizeRuleSet & clampMinNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MinElements)
Limit the number of elements in EltTy vectors to at least MinElements.
LegalizeRuleSet & widenVectorEltsToVectorMinSize(unsigned TypeIdx, unsigned VectorSize)
Ensure the vector size is at least as wide as VectorSize by promoting the element.
LegalizeRuleSet & lowerIfMemSizeNotPow2()
Lower a memory operation if the memory size, rounded to bytes, is not a power of 2.
LegalizeRuleSet & minScalarEltSameAsIf(LegalityPredicate Predicate, unsigned TypeIdx, unsigned LargeTypeIdx)
Conditionally widen the scalar or elt to match the size of another.
LegalizeRuleSet & customForCartesianProduct(std::initializer_list< LLT > Types)
LegalizeRuleSet & lowerIfMemSizeNotByteSizePow2()
Lower a memory operation if the memory access size is not a round power of 2 byte size.
LegalizeRuleSet & moreElementsToNextPow2(unsigned TypeIdx)
Add more elements to the vector to reach the next power of two.
LegalizeRuleSet & narrowScalarIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
Narrow the scalar to the one selected by the mutation if the predicate is true.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & moreElementsIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
Add more elements to reach the type selected by the mutation if the predicate is true.
LegalizeRuleSet & lowerFor(std::initializer_list< LLT > Types)
The instruction is lowered when type index 0 is any type in the given list.
LegalizeRuleSet & scalarizeIf(LegalityPredicate Predicate, unsigned TypeIdx)
LegalizeRuleSet & lowerIf(LegalityPredicate Predicate)
The instruction is lowered if predicate is true.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & custom()
Unconditionally custom lower.
LegalizeRuleSet & minScalarSameAs(unsigned TypeIdx, unsigned LargeTypeIdx)
Widen the scalar to match the size of another.
LegalizeRuleSet & unsupportedIf(LegalityPredicate Predicate)
LegalizeRuleSet & minScalarOrEltIf(LegalityPredicate Predicate, unsigned TypeIdx, const LLT Ty)
Ensure the scalar or element is at least as wide as Ty.
LegalizeRuleSet & widenScalarIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
Widen the scalar to the one selected by the mutation if the predicate is true.
LegalizeRuleSet & alwaysLegal()
LegalizeRuleSet & clampNumElements(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the number of elements for the given vectors to at least MinTy's number of elements and at most...
LegalizeRuleSet & maxScalarIf(LegalityPredicate Predicate, unsigned TypeIdx, const LLT Ty)
Conditionally limit the maximum size of the scalar.
LegalizeRuleSet & customIf(LegalityPredicate Predicate)
LegalizeRuleSet & widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar to the next power of two that is at least MinSize.
LegalizeRuleSet & scalarize(unsigned TypeIdx)
LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)
The instruction is legal when type indexes 0 and 1 are both in the given list.
LegalizeRuleSet & legalForTypesWithMemDesc(std::initializer_list< LegalityPredicates::TypePairAndMemDesc > TypesAndMemDesc)
The instruction is legal when type indexes 0 and 1 along with the memory size and minimum alignment i...
unsigned immIdx(unsigned ImmIdx)
LegalizeRuleSet & widenScalarOrEltToNextPow2(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar or vector element type to the next power of two that is at least MinSize.
LegalizeRuleSet & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
LLVM_ABI LegalizeResult lowerDynStackAlloc(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerBitCount(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerExtractInsertVectorElt(MachineInstr &MI)
Lower a vector extract or insert by writing the vector to a stack temporary and reloading the element...
LLVM_ABI LegalizeResult lowerAbsToCNeg(MachineInstr &MI)
const TargetLowering & getTargetLowering() const
LLVM_ABI LegalizeResult lowerFunnelShiftAsShifts(MachineInstr &MI)
LLVM_ABI MachineInstrBuilder createStackStoreLoad(const DstOp &Res, const SrcOp &Val)
Create a store of Val to a stack temporary and return a load as the same type as Res.
@ Legalized
Instruction has been legalized and the MachineFunction changed.
@ UnableToLegalize
Some kind of error has occurred and we could not legalize this instruction.
GISelChangeObserver & Observer
To keep track of changes made by the LegalizerHelper.
LLVM_ABI Register getDynStackAllocTargetPtr(Register SPReg, Register AllocSize, Align Alignment, LLT PtrTy)
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
const LegacyLegalizerInfo & getLegacyLegalizerInfo() const
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
MachineInstrBuilder buildAdd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ADD Op0, Op1.
MachineInstrBuilder buildNot(const DstOp &Dst, const SrcOp &Src0)
Build and insert a bitwise not, NegOne = G_CONSTANT -1 Res = G_OR Op0, NegOne.
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
MachineInstrBuilder buildExtract(const DstOp &Res, const SrcOp &Src, uint64_t Index)
Build and insert Res0, ... = G_EXTRACT Src, Idx0.
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineBasicBlock::iterator getInsertPt()
Current insertion point for new instructions.
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildIntrinsic(Intrinsic::ID ID, ArrayRef< Register > Res, bool HasSideEffects, bool isConvergent)
Build and insert a G_INTRINSIC instruction.
MachineInstrBuilder buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
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 buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
MachineInstrBuilder buildBitReverse(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITREVERSE Src.
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildCTPOP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTPOP Op0, Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildExtOrTrunc(unsigned ExtOpc, const DstOp &Res, const SrcOp &Op)
Build and insert Res = ExtOpc, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes of...
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineInstrBuilder buildAnyExt(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ANYEXT Op0.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
MachineInstrBuilder buildMaskLowPtrBits(const DstOp &Res, const SrcOp &Op0, uint32_t NumBits)
Build and insert Res = G_PTRMASK Op0, G_CONSTANT (1 << NumBits) - 1.
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.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
Representation of each machine instruction.
const MachineOperand & getOperand(unsigned i) const
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
Wrapper class representing virtual and physical registers.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Register getStackPointerRegisterToSaveRestore() const
If a physical register, this specifies the register that llvm.savestack/llvm.restorestack should save...
Primary interface to the complete machine description for the target machine.
Target - Wrapper for Target specific information.
LLVM Value Representation.
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.
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_PREL
MO_PREL - Indicates that the bits of the symbol operand represented by MO_G0 etc are PC relative.
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TAGGED
MO_TAGGED - With MO_PAGE, indicates that the page includes a memory tag in bits 56-63.
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
LLVM_ABI LegalityPredicate scalarOrEltWiderThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar or a vector with an element type that's wider than the ...
LLVM_ABI LegalityPredicate isPointerVector(unsigned TypeIdx)
True iff the specified type index is a vector of pointers (with any address space).
LLVM_ABI LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
LLVM_ABI LegalityPredicate smallerThan(unsigned TypeIdx0, unsigned TypeIdx1)
True iff the first type index has a smaller total bit size than second type index.
LLVM_ABI LegalityPredicate atomicOrderingAtLeastOrStrongerThan(unsigned MMOIdx, AtomicOrdering Ordering)
True iff the specified MMO index has at an atomic ordering of at Ordering or stronger.
Predicate any(Predicate P0, Predicate P1)
True iff P0 or P1 are true.
LLVM_ABI LegalityPredicate isVector(unsigned TypeIdx)
True iff the specified type index is a vector.
Predicate all(Predicate P0, Predicate P1)
True iff P0 and P1 are true.
LLVM_ABI LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
LLVM_ABI LegalityPredicate scalarWiderThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar that's wider than the given size.
@ Bitcast
Perform the operation on a different, but equivalently sized type.
LLVM_ABI LegalizeMutation moreElementsToNextPow2(unsigned TypeIdx, unsigned Min=0)
Add more elements to the type for the given type index to the next power of.
LLVM_ABI LegalizeMutation scalarize(unsigned TypeIdx)
Break up the vector type for the given type index into the element type.
LLVM_ABI LegalizeMutation widenScalarOrEltToNextPow2(unsigned TypeIdx, unsigned Min=0)
Widen the scalar type or vector element type for the given type index to the next power of 2.
LLVM_ABI LegalizeMutation changeTo(unsigned TypeIdx, LLT Ty)
Select this specific type for the given type index.
LLVM_ABI LegalizeMutation changeElementSizeTo(unsigned TypeIdx, unsigned FromTypeIdx)
Change the scalar size or element size to have the same scalar size as type index FromIndex.
operand_type_match m_Reg()
ConstantMatch< APInt > m_ICst(APInt &Cst)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
Invariant opcodes: All instruction sets have these as their low opcodes.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
LLVM_ABI bool constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
std::function< bool(const LegalityQuery &)> LegalityPredicate
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
AtomicOrdering
Atomic ordering for LLVM's memory model.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
DWARFExpression::Operation Op
constexpr bool isShiftedInt(int64_t x)
Checks if a signed integer is an N bit number shifted left by S.
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
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.
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
unsigned Log2(Align A)
Returns the log2 of the alignment.
This struct is a compact representation of a valid (non-zero power of two) alignment.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< MemDesc > MMODescrs
Operations which require memory can use this to place requirements on the memory type for each MMO.
This class contains a discriminated union of information about pointers in memory operands,...