28#include "llvm/IR/IntrinsicsAArch64.h"
31#include <initializer_list>
33#define DEBUG_TYPE "aarch64-legalinfo"
36using namespace LegalizeActions;
37using namespace LegalizeMutations;
38using namespace LegalityPredicates;
39using namespace MIPatternMatch;
43 using namespace TargetOpcode;
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({v16s8, v8s16, v4s32, v2s64, v2p0, v8s8, v4s16, v2s32, v4s8,
99 .widenScalarToNextPow2(0)
112 .legalFor(PackedVectorAllTypeList)
124 .
legalFor({s32, s64, v4s16, v8s16, v2s32, v4s32, v2s64})
126 .clampScalar(0, s32, s64)
127 .clampNumElements(0, v4s16, v8s16)
128 .clampNumElements(0, v2s32, v4s32)
129 .clampNumElements(0, v2s64, v2s64)
130 .moreElementsToNextPow2(0);
133 .legalFor({s32, s64, v2s32, v2s64, v4s32, v4s16, v8s16, v16s8, v8s8})
134 .legalFor(HasSVE, {nxv16s8, nxv8s16, nxv4s32, nxv2s64})
135 .widenScalarToNextPow2(0)
143 return Query.
Types[0].getNumElements() <= 2;
148 return Query.
Types[0].getNumElements() <= 4;
153 return Query.
Types[0].getNumElements() <= 16;
160 .
legalFor({s32, s64, v2s32, v2s64, v4s32, v4s16, v8s16, v16s8, v8s8})
161 .widenScalarToNextPow2(0)
169 return Query.
Types[0].getNumElements() <= 2;
174 return Query.
Types[0].getNumElements() <= 4;
179 return Query.
Types[0].getNumElements() <= 16;
187 const auto &SrcTy = Query.
Types[0];
188 const auto &AmtTy = Query.
Types[1];
189 return !SrcTy.isVector() && SrcTy.getSizeInBits() == 32 &&
190 AmtTy.getSizeInBits() == 32;
204 .widenScalarToNextPow2(0)
216 .
legalFor({{p0, s64}, {v2p0, v2s64}})
217 .clampScalarOrElt(1, s64, s64)
223 .legalFor({s32, s64})
225 .clampScalar(0, s32, s64)
230 .lowerFor({s8, s16, s32, s64, v2s64, v4s32, v2s32})
233 .minScalarOrElt(0, s32)
234 .clampNumElements(0, v2s32, v4s32)
235 .clampNumElements(0, v2s64, v2s64)
239 .widenScalarToNextPow2(0, 32)
244 .legalFor({s64, v8s16, v16s8, v4s32})
248 .legalFor({v8s8, v16s8, v4s16, v8s16, v2s32, v4s32})
249 .legalFor(HasCSSC, {s32, s64})
250 .minScalar(HasCSSC, 0, s32)
260 {G_SADDE, G_SSUBE, G_UADDE, G_USUBE, G_SADDO, G_SSUBO, G_UADDO, G_USUBO})
261 .legalFor({{s32, s32}, {s64, s32}})
262 .clampScalar(0, s32, s64)
267 {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FSQRT, G_FMAXNUM, G_FMINNUM,
268 G_FMAXIMUM, G_FMINIMUM, G_FCEIL, G_FFLOOR, G_FRINT, G_FNEARBYINT,
269 G_INTRINSIC_TRUNC, G_INTRINSIC_ROUND, G_INTRINSIC_ROUNDEVEN})
270 .legalFor({s32, s64, v2s32, v4s32, v2s64})
271 .legalFor(HasFP16, {s16, v4s16, v8s16})
281 .legalFor({s32, s64, v2s32, v4s32, v2s64})
282 .legalFor(HasFP16, {s16, v4s16, v8s16})
297 .legalFor({{s64, MinFPScalar}, {s64, s32}, {s64, s64}})
298 .libcallFor({{s64, s128}})
299 .minScalarOrElt(1, MinFPScalar);
302 G_FLOG10, G_FTAN, G_FEXP, G_FEXP2, G_FEXP10,
303 G_FACOS, G_FASIN, G_FATAN, G_FATAN2, G_FCOSH,
309 .libcallFor({s32, s64, s128});
313 .
libcallFor({{s32, s32}, {s64, s32}, {s128, s32}});
337 for (
unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
340 if (
Op == G_SEXTLOAD)
345 .legalForTypesWithMemDesc({{s32, p0, s8, 8},
353 {v2s32, p0, s64, 8}})
354 .widenScalarToNextPow2(0)
355 .clampScalar(0, s32, s64)
358 .unsupportedIfMemSizeNotPow2()
370 return HasRCPC3 && Query.
Types[0] == s128 &&
374 return Query.
Types[0] == s128 &&
377 .legalForTypesWithMemDesc({{s8, p0, s8, 8},
384 {v16s8, p0, s128, 8},
386 {v8s16, p0, s128, 8},
388 {v4s32, p0, s128, 8},
389 {v2s64, p0, s128, 8}})
391 .legalForTypesWithMemDesc(
392 {{s32, p0, s8, 8}, {s32, p0, s16, 8}, {s64, p0, s32, 8}})
393 .legalForTypesWithMemDesc({
395 {nxv16s8, p0, nxv16s8, 8},
396 {nxv8s16, p0, nxv8s16, 8},
397 {nxv4s32, p0, nxv4s32, 8},
398 {nxv2s64, p0, nxv2s64, 8},
400 .widenScalarToNextPow2(0, 8)
411 return Query.
Types[0].isScalar() &&
413 Query.
Types[0].getSizeInBits() > 32;
422 .customIf(IsPtrVecPred)
428 return HasRCPC3 && Query.
Types[0] == s128 &&
432 return Query.
Types[0] == s128 &&
435 .legalForTypesWithMemDesc(
436 {{s8, p0, s8, 8}, {s16, p0, s8, 8},
439 {s16, p0, s16, 8}, {s32, p0, s16, 8},
441 {s32, p0, s8, 8}, {s32, p0, s16, 8}, {s32, p0, s32, 8},
442 {s64, p0, s64, 8}, {s64, p0, s32, 8},
443 {p0, p0, s64, 8}, {s128, p0, s128, 8}, {v16s8, p0, s128, 8},
444 {v8s8, p0, s64, 8}, {v4s16, p0, s64, 8}, {v8s16, p0, s128, 8},
445 {v2s32, p0, s64, 8}, {v4s32, p0, s128, 8}, {v2s64, p0, s128, 8}})
446 .legalForTypesWithMemDesc({
451 {nxv16s8, p0, nxv16s8, 8},
452 {nxv8s16, p0, nxv8s16, 8},
453 {nxv4s32, p0, nxv4s32, 8},
454 {nxv2s64, p0, nxv2s64, 8},
456 .clampScalar(0, s8, s64)
459 return Query.
Types[0].isScalar() &&
463 .clampMaxNumElements(0, s8, 16)
472 return Query.
Types[0].getSizeInBits() ==
473 Query.
MMODescrs[0].MemoryTy.getSizeInBits();
479 .customIf(IsPtrVecPred)
497 {p0, v16s8, v16s8, 8},
498 {p0, v4s16, v4s16, 8},
499 {p0, v8s16, v8s16, 8},
500 {p0, v2s32, v2s32, 8},
501 {p0, v4s32, v4s32, 8},
502 {p0, v2s64, v2s64, 8},
508 auto IndexedLoadBasicPred = [=](
const LegalityQuery &Query) {
536 return MemTy == s8 || MemTy == s16;
538 return MemTy == s8 || MemTy == s16 || MemTy == s32;
546 .widenScalarToNextPow2(0)
550 .legalFor(HasFP16, {s16})
551 .clampScalar(0, MinFPScalar, s128);
555 .
legalFor({{s32, s32}, {s32, s64}, {s32, p0}})
557 .clampScalar(1, s32, s64)
558 .clampScalar(0, s32, s32)
560 .minScalarEltSameAsIf(
573 return Query.
Types[1].isPointerVector();
577 .clampNumElements(1, v8s8, v16s8)
578 .clampNumElements(1, v4s16, v8s16)
579 .clampNumElements(1, v2s32, v4s32)
580 .clampNumElements(1, v2s64, v2s64)
581 .clampNumElements(1, v2p0, v2p0)
590 .legalFor(HasFP16, {{s32, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
592 .clampScalar(0, s32, s32)
593 .minScalarOrElt(1, MinFPScalar)
595 .minScalarEltSameAsIf(
603 .clampNumElements(1, v4s16, v8s16)
604 .clampNumElements(1, v2s32, v4s32)
605 .clampMaxNumElements(1, s64, 2)
606 .moreElementsToNextPow2(1)
607 .libcallFor({{s32, s128}});
611 unsigned DstSize = Query.
Types[0].getSizeInBits();
614 if (Query.
Types[0].isVector())
617 if (DstSize < 8 || DstSize >= 128 || !
isPowerOf2_32(DstSize))
632 .legalIf(ExtLegalFunc)
633 .
legalFor({{v2s64, v2s32}, {v4s32, v4s16}, {v8s16, v8s8}})
634 .clampScalar(0, s64, s64)
641 return (Query.
Types[0].getScalarSizeInBits() >
642 Query.
Types[1].getScalarSizeInBits() * 2) &&
643 Query.
Types[0].isVector() &&
644 (Query.
Types[1].getScalarSizeInBits() == 8 ||
645 Query.
Types[1].getScalarSizeInBits() == 16);
647 .clampMinNumElements(1, s8, 8)
651 .
legalFor({{v2s32, v2s64}, {v4s16, v4s32}, {v8s8, v8s16}})
653 .clampMaxNumElements(0, s8, 8)
654 .clampMaxNumElements(0, s16, 4)
655 .clampMaxNumElements(0, s32, 2)
665 .clampMinNumElements(0, s8, 8)
666 .clampMinNumElements(0, s16, 4)
671 .legalFor(PackedVectorAllTypeList)
682 {{s16, s32}, {s16, s64}, {s32, s64}, {v4s16, v4s32}, {v2s32, v2s64}})
683 .libcallFor({{s16, s128}, {s32, s128}, {s64, s128}})
684 .clampNumElements(0, v4s16, v4s16)
690 {{s32, s16}, {s64, s16}, {s64, s32}, {v4s32, v4s16}, {v2s64, v2s32}})
691 .libcallFor({{s128, s64}, {s128, s32}, {s128, s16}})
692 .clampNumElements(0, v4s32, v4s32)
698 .legalFor({{s32, s32},
706 {{s32, s16}, {s64, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
713 return Query.
Types[1] == s16 && Query.
Types[0].getSizeInBits() > 64;
717 .widenScalarOrEltToNextPow2OrMinSize(0)
719 .widenScalarOrEltToNextPow2OrMinSize(1, HasFP16 ? 16 : 32)
722 return Query.
Types[0].getScalarSizeInBits() <= 64 &&
723 Query.
Types[0].getScalarSizeInBits() >
724 Query.
Types[1].getScalarSizeInBits();
729 return Query.
Types[1].getScalarSizeInBits() <= 64 &&
730 Query.
Types[0].getScalarSizeInBits() <
731 Query.
Types[1].getScalarSizeInBits();
734 .clampNumElements(0, v4s16, v8s16)
735 .clampNumElements(0, v2s32, v4s32)
736 .clampMaxNumElements(0, s64, 2)
738 {{s32, s128}, {s64, s128}, {s128, s128}, {s128, s32}, {s128, s64}});
741 .legalFor({{s32, s32},
749 {{s32, s16}, {s64, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
757 return Query.
Types[1] == s16 && Query.
Types[0].getSizeInBits() > 64;
762 .widenScalarToNextPow2(0, 32)
764 .widenScalarOrEltToNextPow2OrMinSize(1, HasFP16 ? 16 : 32)
767 unsigned ITySize = Query.
Types[0].getScalarSizeInBits();
768 return (ITySize == 16 || ITySize == 32 || ITySize == 64) &&
769 ITySize > Query.
Types[1].getScalarSizeInBits();
774 unsigned FTySize = Query.
Types[1].getScalarSizeInBits();
775 return (FTySize == 16 || FTySize == 32 || FTySize == 64) &&
776 Query.
Types[0].getScalarSizeInBits() < FTySize;
780 .clampNumElements(0, v4s16, v8s16)
781 .clampNumElements(0, v2s32, v4s32)
782 .clampMaxNumElements(0, s64, 2);
785 .legalFor({{s32, s32},
793 {{s16, s32}, {s16, s64}, {v4s16, v4s16}, {v8s16, v8s16}})
802 return Query.
Types[1].getScalarSizeInBits() <= 64 &&
803 Query.
Types[0].getScalarSizeInBits() <
804 Query.
Types[1].getScalarSizeInBits();
809 return Query.
Types[0].getScalarSizeInBits() <= 64 &&
810 Query.
Types[0].getScalarSizeInBits() >
811 Query.
Types[1].getScalarSizeInBits();
814 .clampNumElements(0, v4s16, v8s16)
827 .clampScalar(0, s32, s32);
831 .
legalFor({{s32, s32}, {s64, s32}, {p0, s32}})
832 .widenScalarToNextPow2(0)
851 .
legalFor({{s64, p0}, {v2s64, v2p0}})
852 .widenScalarToNextPow2(0, 64)
858 return Query.
Types[0].getSizeInBits() != Query.
Types[1].getSizeInBits();
860 .legalFor({{p0, s64}, {v2p0, v2s64}})
861 .clampMaxNumElements(1, s64, 2);
868 .legalForCartesianProduct({s64, v8s8, v4s16, v2s32})
869 .legalForCartesianProduct({s128, v16s8, v8s16, v4s32, v2s64, v2p0})
878 return Query.
Types[0].isVector() != Query.
Types[1].isVector();
881 .clampNumElements(0, v8s8, v16s8)
882 .clampNumElements(0, v4s16, v8s16)
883 .clampNumElements(0, v2s32, v4s32)
892 .clampScalar(0, s8, s64)
899 bool UseOutlineAtomics = ST.outlineAtomics() && !ST.hasLSE();
902 .
legalFor(!UseOutlineAtomics, {{s32, p0}, {s64, p0}})
903 .customFor(!UseOutlineAtomics, {{s128, p0}})
904 .libcallFor(UseOutlineAtomics,
905 {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}, {s128, p0}})
906 .clampScalar(0, s32, s64);
909 G_ATOMICRMW_SUB, G_ATOMICRMW_AND, G_ATOMICRMW_OR,
911 .legalFor(!UseOutlineAtomics, {{s32, p0}, {s64, p0}})
912 .libcallFor(UseOutlineAtomics,
913 {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
914 .clampScalar(0, s32, s64);
919 {G_ATOMICRMW_MIN, G_ATOMICRMW_MAX, G_ATOMICRMW_UMIN, G_ATOMICRMW_UMAX})
926 for (
unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
927 unsigned BigTyIdx =
Op == G_MERGE_VALUES ? 0 : 1;
928 unsigned LitTyIdx =
Op == G_MERGE_VALUES ? 1 : 0;
935 switch (Q.
Types[BigTyIdx].getSizeInBits()) {
943 switch (Q.
Types[LitTyIdx].getSizeInBits()) {
957 .
legalFor(HasSVE, {{s16, nxv16s8, s64},
960 {s64, nxv2s64, s64}})
962 const LLT &EltTy = Query.
Types[1].getElementType();
963 if (Query.
Types[1].isScalableVector())
965 return Query.
Types[0] != EltTy;
970 return VecTy == v2s16 || VecTy == v4s16 || VecTy == v8s16 ||
971 VecTy == v4s32 || VecTy == v2s64 || VecTy == v2s32 ||
972 VecTy == v8s8 || VecTy == v16s8 || VecTy == v2p0;
978 return Query.
Types[1].isFixedVector() &&
979 Query.
Types[1].getNumElements() <= 2;
984 return Query.
Types[1].isFixedVector() &&
985 Query.
Types[1].getNumElements() <= 4;
990 return Query.
Types[1].isFixedVector() &&
991 Query.
Types[1].getNumElements() <= 8;
996 return Query.
Types[1].isFixedVector() &&
997 Query.
Types[1].getNumElements() <= 16;
1000 .minScalarOrElt(0, s8)
1010 typeInSet(0, {v16s8, v8s8, v8s16, v4s16, v4s32, v2s32, v2s64, v2p0}))
1011 .
legalFor(HasSVE, {{nxv16s8, s32, s64},
1012 {nxv8s16, s32, s64},
1013 {nxv4s32, s32, s64},
1014 {nxv2s64, s64, s64}})
1016 .widenVectorEltsToVectorMinSize(0, 64)
1017 .clampNumElements(0, v8s8, v16s8)
1018 .clampNumElements(0, v4s16, v8s16)
1019 .clampNumElements(0, v2s32, v4s32)
1020 .clampMaxNumElements(0, s64, 2)
1021 .clampMaxNumElements(0, p0, 2);
1032 .clampNumElements(0, v4s32, v4s32)
1043 {s32, s64, v8s8, v16s8, v4s16, v8s16, v2s32, v4s32})
1045 .widenScalarToNextPow2(1, 32)
1046 .clampScalar(1, s32, s64)
1047 .scalarSameSizeAs(0, 1);
1053 .widenScalarToNextPow2(0, 32)
1065 .customFor(!HasCSSC, {s32, s64});
1076 {v2s64, v2s32, v4s32, v4s16, v16s8, v8s8, v8s16}, DstTy);
1082 return !Query.
Types[0].isVector() || !Query.
Types[1].isVector();
1086 return Query.
Types[0].isVector() && Query.
Types[1].isVector() &&
1087 Query.
Types[0].getNumElements() >
1088 Query.
Types[1].getNumElements();
1094 return Query.
Types[0].isVector() && Query.
Types[1].isVector() &&
1095 Query.
Types[0].getNumElements() <
1096 Query.
Types[1].getNumElements();
1099 .widenScalarOrEltToNextPow2OrMinSize(0, 8)
1100 .clampNumElements(0, v8s8, v16s8)
1101 .clampNumElements(0, v4s16, v8s16)
1102 .clampNumElements(0, v4s32, v4s32)
1103 .clampNumElements(0, v2s64, v2s64)
1112 .
legalFor({{v4s32, v2s32}, {v8s16, v4s16}, {v16s8, v8s8}})
1115 return Query.
Types[0].getSizeInBits() <= 128 &&
1116 Query.
Types[1].getSizeInBits() <= 64;
1143 .customForCartesianProduct({p0}, {s8}, {s64})
1147 .legalForCartesianProduct({p0}, {p0}, {s64})
1162 .legalFor(PackedVectorAllTypeList)
1170 [=](
const LegalityQuery &Query) {
return std::make_pair(0, v4s16); })
1173 [=](
const LegalityQuery &Query) {
return std::make_pair(0, v2s32); })
1174 .clampNumElements(0, v8s8, v16s8)
1185 .
legalFor({{s32, v2s32}, {s32, v4s32}, {s64, v2s64}})
1186 .legalFor(HasFP16, {{s16, v4s16}, {s16, v8s16}})
1187 .minScalarOrElt(0, MinFPScalar)
1218 .clampMaxNumElements(1, s64, 2)
1225 G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM})
1226 .legalFor({{s32, v4s32}, {s32, v2s32}, {s64, v2s64}})
1227 .legalFor(HasFP16, {{s16, v4s16}, {s16, v8s16}})
1228 .minScalarOrElt(0, MinFPScalar)
1242 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX})
1243 .legalFor({{s8, v8s8},
1251 return Query.
Types[1].isVector() &&
1252 Query.
Types[1].getElementType() != s8 &&
1253 Query.
Types[1].getNumElements() & 1;
1256 .clampMaxNumElements(1, s64, 2)
1264 {G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
1280 return std::make_pair(1, SrcTy.
divide(2));
1289 .customFor({{s32, s32}, {s32, s64}, {s64, s64}})
1293 .
legalFor({{s32, s64}, {s64, s64}})
1295 return Q.
Types[0].isScalar() && Q.
Types[1].getScalarSizeInBits() < 64;
1301 .customFor({{s32, s32}, {s64, s64}});
1305 .
legalFor(HasCSSC, {{s32, s32}, {s64, s64}})
1306 .legalFor({{v8s8, v8s8}, {v16s8, v16s8}})
1307 .customFor(!HasCSSC, {{s32, s32}, {s64, s64}})
1308 .customFor({{s128, s128},
1314 .clampScalar(0, s32, s128)
1320 .legalFor({v2s64, v2s32, v4s32, v4s16, v8s16, v8s8, v16s8})
1321 .legalFor(HasSVE, {nxv2s64, nxv4s32, nxv8s16, nxv16s8})
1322 .clampNumElements(0, v8s8, v16s8)
1333 .legalFor({{s64, s32}, {s64, s64}});
1349 G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE})
1359 .
legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
1365 .
legalFor(HasSVE, {{nxv4s32, s32}, {nxv2s64, s64}});
1368 verify(*ST.getInstrInfo());
1377 switch (
MI.getOpcode()) {
1381 case TargetOpcode::G_VAARG:
1382 return legalizeVaArg(
MI,
MRI, MIRBuilder);
1383 case TargetOpcode::G_LOAD:
1384 case TargetOpcode::G_STORE:
1385 return legalizeLoadStore(
MI,
MRI, MIRBuilder, Observer);
1386 case TargetOpcode::G_SHL:
1387 case TargetOpcode::G_ASHR:
1388 case TargetOpcode::G_LSHR:
1389 return legalizeShlAshrLshr(
MI,
MRI, MIRBuilder, Observer);
1390 case TargetOpcode::G_GLOBAL_VALUE:
1391 return legalizeSmallCMGlobalValue(
MI,
MRI, MIRBuilder, Observer);
1392 case TargetOpcode::G_SBFX:
1393 case TargetOpcode::G_UBFX:
1394 return legalizeBitfieldExtract(
MI,
MRI, Helper);
1395 case TargetOpcode::G_FSHL:
1396 case TargetOpcode::G_FSHR:
1397 return legalizeFunnelShift(
MI,
MRI, MIRBuilder, Observer, Helper);
1398 case TargetOpcode::G_ROTR:
1399 return legalizeRotate(
MI,
MRI, Helper);
1400 case TargetOpcode::G_CTPOP:
1401 return legalizeCTPOP(
MI,
MRI, Helper);
1402 case TargetOpcode::G_ATOMIC_CMPXCHG:
1403 return legalizeAtomicCmpxchg128(
MI,
MRI, Helper);
1404 case TargetOpcode::G_CTTZ:
1405 return legalizeCTTZ(
MI, Helper);
1406 case TargetOpcode::G_BZERO:
1407 case TargetOpcode::G_MEMCPY:
1408 case TargetOpcode::G_MEMMOVE:
1409 case TargetOpcode::G_MEMSET:
1410 return legalizeMemOps(
MI, Helper);
1411 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1412 return legalizeExtractVectorElt(
MI,
MRI, Helper);
1413 case TargetOpcode::G_DYN_STACKALLOC:
1414 return legalizeDynStackAlloc(
MI, Helper);
1415 case TargetOpcode::G_PREFETCH:
1416 return legalizePrefetch(
MI, Helper);
1417 case TargetOpcode::G_ABS:
1419 case TargetOpcode::G_ICMP:
1420 return legalizeICMP(
MI,
MRI, MIRBuilder);
1421 case TargetOpcode::G_BITCAST:
1422 return legalizeBitcast(
MI, Helper);
1430 assert(
MI.getOpcode() == TargetOpcode::G_BITCAST &&
"Unexpected opcode");
1431 auto [DstReg, DstTy, SrcReg, SrcTy] =
MI.getFirst2RegLLTs();
1434 if (!DstTy.isScalar() || !SrcTy.isVector() ||
1439 MI.eraseFromParent();
1448 assert(
MI.getOpcode() == TargetOpcode::G_FSHL ||
1449 MI.getOpcode() == TargetOpcode::G_FSHR);
1453 Register ShiftNo =
MI.getOperand(3).getReg();
1454 LLT ShiftTy =
MRI.getType(ShiftNo);
1459 LLT OperationTy =
MRI.getType(
MI.getOperand(0).getReg());
1463 if (!VRegAndVal || VRegAndVal->Value.urem(
BitWidth) == 0)
1469 Amount =
MI.getOpcode() == TargetOpcode::G_FSHL ?
BitWidth - Amount : Amount;
1473 if (ShiftTy.
getSizeInBits() == 64 &&
MI.getOpcode() == TargetOpcode::G_FSHR &&
1480 if (
MI.getOpcode() == TargetOpcode::G_FSHR) {
1482 MI.getOperand(3).setReg(Cast64.getReg(0));
1487 else if (
MI.getOpcode() == TargetOpcode::G_FSHL) {
1489 {
MI.getOperand(1).
getReg(),
MI.getOperand(2).getReg(),
1491 MI.eraseFromParent();
1500 Register SrcReg1 =
MI.getOperand(2).getReg();
1501 Register SrcReg2 =
MI.getOperand(3).getReg();
1502 LLT DstTy =
MRI.getType(DstReg);
1503 LLT SrcTy =
MRI.getType(SrcReg1);
1520 MIRBuilder.
buildNot(DstReg, CmpReg);
1522 MI.eraseFromParent();
1532 LLT AmtTy =
MRI.getType(AmtReg);
1538 MI.getOperand(2).setReg(NewAmt.getReg(0));
1543bool AArch64LegalizerInfo::legalizeSmallCMGlobalValue(
1546 assert(
MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
1551 auto &GlobalOp =
MI.getOperand(1);
1553 if (GlobalOp.isSymbol())
1555 const auto* GV = GlobalOp.getGlobal();
1556 if (GV->isThreadLocal())
1565 auto Offset = GlobalOp.getOffset();
1570 MRI.setRegClass(
ADRP.getReg(0), &AArch64::GPR64RegClass);
1587 "Should not have folded in an offset for a tagged global!");
1589 .addGlobalAddress(GV, 0x100000000,
1592 MRI.setRegClass(
ADRP.getReg(0), &AArch64::GPR64RegClass);
1596 .addGlobalAddress(GV,
Offset,
1598 MI.eraseFromParent();
1604 auto LowerBinOp = [&
MI](
unsigned Opcode) {
1607 {
MI.getOperand(2),
MI.getOperand(3)});
1608 MI.eraseFromParent();
1613 switch (IntrinsicID) {
1614 case Intrinsic::vacopy: {
1616 unsigned VaListSize =
1628 VaListSize,
Align(PtrSize)));
1632 VaListSize,
Align(PtrSize)));
1633 MI.eraseFromParent();
1636 case Intrinsic::get_dynamic_area_offset: {
1639 MI.eraseFromParent();
1642 case Intrinsic::aarch64_mops_memset_tag: {
1643 assert(
MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
1647 auto &
Value =
MI.getOperand(3);
1649 Value.setReg(ExtValueReg);
1652 case Intrinsic::aarch64_prefetch: {
1654 auto &AddrVal =
MI.getOperand(1);
1656 int64_t IsWrite =
MI.getOperand(2).getImm();
1657 int64_t
Target =
MI.getOperand(3).getImm();
1658 int64_t IsStream =
MI.getOperand(4).getImm();
1659 int64_t IsData =
MI.getOperand(5).getImm();
1661 unsigned PrfOp = (IsWrite << 4) |
1667 MI.eraseFromParent();
1670 case Intrinsic::aarch64_neon_uaddv:
1671 case Intrinsic::aarch64_neon_saddv:
1672 case Intrinsic::aarch64_neon_umaxv:
1673 case Intrinsic::aarch64_neon_smaxv:
1674 case Intrinsic::aarch64_neon_uminv:
1675 case Intrinsic::aarch64_neon_sminv: {
1678 bool IsSigned = IntrinsicID == Intrinsic::aarch64_neon_saddv ||
1679 IntrinsicID == Intrinsic::aarch64_neon_smaxv ||
1680 IntrinsicID == Intrinsic::aarch64_neon_sminv;
1682 auto OldDst =
MI.getOperand(0).getReg();
1683 auto OldDstTy =
MRI.getType(OldDst);
1684 LLT NewDstTy =
MRI.getType(
MI.getOperand(2).getReg()).getElementType();
1685 if (OldDstTy == NewDstTy)
1688 auto NewDst =
MRI.createGenericVirtualRegister(NewDstTy);
1691 MI.getOperand(0).setReg(NewDst);
1695 MIB.
buildExtOrTrunc(IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT,
1700 case Intrinsic::aarch64_neon_uaddlp:
1701 case Intrinsic::aarch64_neon_saddlp: {
1704 unsigned Opc = IntrinsicID == Intrinsic::aarch64_neon_uaddlp
1706 : AArch64::G_SADDLP;
1708 MI.eraseFromParent();
1712 case Intrinsic::aarch64_neon_uaddlv:
1713 case Intrinsic::aarch64_neon_saddlv: {
1717 unsigned Opc = IntrinsicID == Intrinsic::aarch64_neon_uaddlv
1719 : AArch64::G_SADDLV;
1722 LLT DstTy =
MRI.getType(DstReg);
1746 MI.eraseFromParent();
1750 case Intrinsic::aarch64_neon_smax:
1751 return LowerBinOp(TargetOpcode::G_SMAX);
1752 case Intrinsic::aarch64_neon_smin:
1753 return LowerBinOp(TargetOpcode::G_SMIN);
1754 case Intrinsic::aarch64_neon_umax:
1755 return LowerBinOp(TargetOpcode::G_UMAX);
1756 case Intrinsic::aarch64_neon_umin:
1757 return LowerBinOp(TargetOpcode::G_UMIN);
1758 case Intrinsic::aarch64_neon_fmax:
1759 return LowerBinOp(TargetOpcode::G_FMAXIMUM);
1760 case Intrinsic::aarch64_neon_fmin:
1761 return LowerBinOp(TargetOpcode::G_FMINIMUM);
1762 case Intrinsic::aarch64_neon_fmaxnm:
1763 return LowerBinOp(TargetOpcode::G_FMAXNUM);
1764 case Intrinsic::aarch64_neon_fminnm:
1765 return LowerBinOp(TargetOpcode::G_FMINNUM);
1766 case Intrinsic::aarch64_neon_smull:
1767 return LowerBinOp(AArch64::G_SMULL);
1768 case Intrinsic::aarch64_neon_umull:
1769 return LowerBinOp(AArch64::G_UMULL);
1770 case Intrinsic::aarch64_neon_abs: {
1773 MIB.
buildInstr(TargetOpcode::G_ABS, {
MI.getOperand(0)}, {
MI.getOperand(2)});
1774 MI.eraseFromParent();
1778 case Intrinsic::vector_reverse:
1786bool AArch64LegalizerInfo::legalizeShlAshrLshr(
1789 assert(
MI.getOpcode() == TargetOpcode::G_ASHR ||
1790 MI.getOpcode() == TargetOpcode::G_LSHR ||
1791 MI.getOpcode() == TargetOpcode::G_SHL);
1804 MI.getOperand(2).setReg(ExtCst.getReg(0));
1817 isShiftedInt<7, 3>(NewOffset)) {
1825bool AArch64LegalizerInfo::legalizeLoadStore(
1828 assert(
MI.getOpcode() == TargetOpcode::G_STORE ||
1829 MI.getOpcode() == TargetOpcode::G_LOAD);
1840 const LLT ValTy =
MRI.getType(ValReg);
1845 bool IsLoad =
MI.getOpcode() == TargetOpcode::G_LOAD;
1849 ST->hasLSE2() && ST->hasRCPC3() && (IsLoadAcquire || IsStoreRelease);
1855 Opcode = IsLoad ? AArch64::LDIAPPX : AArch64::STILPX;
1861 assert(ST->hasLSE2() &&
"ldp/stp not single copy atomic without +lse2");
1863 Opcode = IsLoad ? AArch64::LDPXi : AArch64::STPXi;
1868 NewI = MIRBuilder.
buildInstr(Opcode, {s64, s64}, {});
1874 Opcode, {}, {
Split->getOperand(0),
Split->getOperand(1)});
1878 NewI.
addUse(
MI.getOperand(1).getReg());
1889 *
MRI.getTargetRegisterInfo(),
1891 MI.eraseFromParent();
1897 LLVM_DEBUG(
dbgs() <<
"Tried to do custom legalization on wrong load/store");
1903 auto &MMO = **
MI.memoperands_begin();
1906 if (
MI.getOpcode() == TargetOpcode::G_STORE) {
1910 auto NewLoad = MIRBuilder.
buildLoad(NewTy,
MI.getOperand(1), MMO);
1913 MI.eraseFromParent();
1921 Align Alignment(
MI.getOperand(2).getImm());
1923 Register ListPtr =
MI.getOperand(1).getReg();
1925 LLT PtrTy =
MRI.getType(ListPtr);
1936 if (Alignment > PtrAlign) {
1940 auto ListTmp = MIRBuilder.
buildPtrAdd(PtrTy,
List, AlignMinus1.getReg(0));
1945 LLT ValTy =
MRI.getType(Dst);
1950 ValTy, std::max(Alignment, PtrAlign)));
1961 MI.eraseFromParent();
1965bool AArch64LegalizerInfo::legalizeBitfieldExtract(
1999 LLT Ty =
MRI.getType(Val);
2003 "Expected src and dst to have the same type!");
2011 auto Add = MIRBuilder.
buildAdd(s64, CTPOP1, CTPOP2);
2014 MI.eraseFromParent();
2018 if (!ST->hasNEON() ||
2019 MI.getMF()->getFunction().hasFnAttribute(Attribute::NoImplicitFloat)) {
2031 assert((
Size == 32 ||
Size == 64 ||
Size == 128) &&
"Expected only 32, 64, or 128 bit scalars!");
2055 Sum = MIRBuilder.
buildInstr(AArch64::G_UDOT, {Dt}, {Zeros, Ones,
CTPOP});
2057 Sum = MIRBuilder.
buildInstr(AArch64::G_UDOT, {Dt}, {Zeros, Ones,
CTPOP});
2063 MI.eraseFromParent();
2071 Opc = Intrinsic::aarch64_neon_uaddlv;
2074 Opc = Intrinsic::aarch64_neon_uaddlp;
2077 Opc = Intrinsic::aarch64_neon_uaddlp;
2081 Opc = Intrinsic::aarch64_neon_uaddlp;
2086 Opc = Intrinsic::aarch64_neon_uaddlp;
2089 Opc = Intrinsic::aarch64_neon_uaddlp;
2095 for (
LLT HTy : HAddTys) {
2105 MI.eraseFromParent();
2109bool AArch64LegalizerInfo::legalizeAtomicCmpxchg128(
2113 auto Addr =
MI.getOperand(1).getReg();
2114 auto DesiredI = MIRBuilder.
buildUnmerge({s64, s64},
MI.getOperand(2));
2115 auto NewI = MIRBuilder.
buildUnmerge({s64, s64},
MI.getOperand(3));
2116 auto DstLo =
MRI.createGenericVirtualRegister(s64);
2117 auto DstHi =
MRI.createGenericVirtualRegister(s64);
2130 auto Ordering = (*
MI.memoperands_begin())->getMergedOrdering();
2134 Opcode = AArch64::CASPAX;
2137 Opcode = AArch64::CASPLX;
2141 Opcode = AArch64::CASPALX;
2144 Opcode = AArch64::CASPX;
2149 auto CASDst =
MRI.createGenericVirtualRegister(s128);
2150 auto CASDesired =
MRI.createGenericVirtualRegister(s128);
2151 auto CASNew =
MRI.createGenericVirtualRegister(s128);
2152 MIRBuilder.
buildInstr(TargetOpcode::REG_SEQUENCE, {CASDesired}, {})
2153 .addUse(DesiredI->getOperand(0).getReg())
2155 .
addUse(DesiredI->getOperand(1).getReg())
2156 .
addImm(AArch64::subo64);
2157 MIRBuilder.
buildInstr(TargetOpcode::REG_SEQUENCE, {CASNew}, {})
2161 .
addImm(AArch64::subo64);
2163 CAS = MIRBuilder.
buildInstr(Opcode, {CASDst}, {CASDesired, CASNew,
Addr});
2171 auto Ordering = (*
MI.memoperands_begin())->getMergedOrdering();
2175 Opcode = AArch64::CMP_SWAP_128_ACQUIRE;
2178 Opcode = AArch64::CMP_SWAP_128_RELEASE;
2182 Opcode = AArch64::CMP_SWAP_128;
2185 Opcode = AArch64::CMP_SWAP_128_MONOTONIC;
2189 auto Scratch =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2190 CAS = MIRBuilder.
buildInstr(Opcode, {DstLo, DstHi, Scratch},
2191 {
Addr, DesiredI->getOperand(0),
2192 DesiredI->getOperand(1), NewI->
getOperand(0),
2198 *
MRI.getTargetRegisterInfo(),
2202 MI.eraseFromParent();
2210 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
2212 MIRBuilder.
buildCTLZ(
MI.getOperand(0).getReg(), BitReverse);
2213 MI.eraseFromParent();
2222 if (
MI.getOpcode() == TargetOpcode::G_MEMSET) {
2225 auto &
Value =
MI.getOperand(1);
2228 Value.setReg(ExtValueReg);
2235bool AArch64LegalizerInfo::legalizeExtractVectorElt(
2249bool AArch64LegalizerInfo::legalizeDynStackAlloc(
2265 Register AllocSize =
MI.getOperand(1).getReg();
2269 "Unexpected type for dynamic alloca");
2271 "Unexpected type for dynamic alloca");
2273 LLT PtrTy =
MRI.getType(Dst);
2279 MIRBuilder.
buildInstr(AArch64::PROBED_STACKALLOC_DYN, {}, {SPTmp});
2280 MRI.setRegClass(NewMI.getReg(0), &AArch64::GPR64commonRegClass);
2281 MIRBuilder.
setInsertPt(*NewMI->getParent(), NewMI);
2284 MI.eraseFromParent();
2291 auto &AddrVal =
MI.getOperand(0);
2293 int64_t IsWrite =
MI.getOperand(1).getImm();
2294 int64_t Locality =
MI.getOperand(2).getImm();
2295 int64_t
IsData =
MI.getOperand(3).getImm();
2297 bool IsStream = Locality == 0;
2298 if (Locality != 0) {
2299 assert(Locality <= 3 &&
"Prefetch locality out-of-range");
2303 Locality = 3 - Locality;
2306 unsigned PrfOp = (IsWrite << 4) | (!IsData << 3) | (Locality << 1) | IsStream;
2309 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.
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.
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static constexpr Register SPReg
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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)
bool isTargetWindows() const
const AArch64InstrInfo * getInstrInfo() const override
bool isTargetDarwin() const
bool isTargetILP32() const
const AArch64TargetLowering * getTargetLowering() const override
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
const RegisterBankInfo * getRegBankInfo() const override
Class for arbitrary precision integers.
APInt zext(unsigned width) const
Zero extend to a new width.
APInt urem(const APInt &RHS) const
Unsigned remainder operation.
int64_t getSExtValue() const
Get sign extended value.
StringRef getValueAsString() const
Return the attribute's value as a string.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
This class represents an Operation in the Expression.
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.
constexpr LLT divide(int Factor) const
Return a type that is Factor times smaller.
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 & 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...
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.
LegalizeResult lowerDynStackAlloc(MachineInstr &MI)
LegalizeResult lowerBitCount(MachineInstr &MI)
LegalizeResult lowerExtractInsertVectorElt(MachineInstr &MI)
Lower a vector extract or insert by writing the vector to a stack temporary and reloading the element...
LegalizeResult lowerAbsToCNeg(MachineInstr &MI)
const TargetLowering & getTargetLowering() const
LegalizeResult lowerFunnelShiftAsShifts(MachineInstr &MI)
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.
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.
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,...
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.
const TargetMachine & getTargetMachine() const
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,...
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 ...
LegalityPredicate isPointerVector(unsigned TypeIdx)
True iff the specified type index is a vector of pointers (with any address space).
LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
LegalityPredicate smallerThan(unsigned TypeIdx0, unsigned TypeIdx1)
True iff the first type index has a smaller total bit size than second type index.
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.
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.
LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
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.
LegalizeMutation moreElementsToNextPow2(unsigned TypeIdx, unsigned Min=0)
Add more elements to the type for the given type index to the next power of.
LegalizeMutation scalarize(unsigned TypeIdx)
Break up the vector type for the given type index into the element type.
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.
LegalizeMutation changeTo(unsigned TypeIdx, LLT Ty)
Select this specific type for the given type index.
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)
This is an optimization pass for GlobalISel generic memory operations.
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...
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
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.
constexpr unsigned BitWidth
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.
std::function< bool(const LegalityQuery &)> LegalityPredicate
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,...