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({v2s8, v4s8, v8s8, v16s8, v2s16, v4s16, v8s16, v2s32, v4s32,
99 .widenScalarToNextPow2(0)
112 .legalFor(PackedVectorAllTypeList)
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)
228 .
legalFor({{p0, s64}, {v2p0, v2s64}})
229 .clampScalarOrElt(1, s64, s64)
235 .legalFor({s32, s64})
237 .clampScalar(0, s32, s64)
242 .lowerFor({s8, s16, s32, s64, v2s32, v4s32, v2s64})
245 .minScalarOrElt(0, s32)
246 .clampNumElements(0, v2s32, v4s32)
247 .clampNumElements(0, v2s64, v2s64)
251 .widenScalarToNextPow2(0, 32)
256 .legalFor({s64, v16s8, v8s16, v4s32})
260 .legalFor({v8s8, v16s8, v4s16, v8s16, v2s32, v4s32})
261 .legalFor(HasCSSC, {s32, s64})
262 .minScalar(HasCSSC, 0, s32)
271 .legalFor(PackedVectorAllTypeList)
279 [=](
const LegalityQuery &Query) {
return std::make_pair(0, v4s16); })
282 [=](
const LegalityQuery &Query) {
return std::make_pair(0, v2s32); })
283 .clampNumElements(0, v8s8, v16s8)
291 .legalFor({v8s8, v16s8, v4s16, v8s16, v2s32, v4s32})
295 {G_SADDE, G_SSUBE, G_UADDE, G_USUBE, G_SADDO, G_SSUBO, G_UADDO, G_USUBO})
296 .legalFor({{s32, s32}, {s64, s32}})
297 .clampScalar(0, s32, s64)
302 .customFor({{s32, s32}, {s32, s64}, {s64, s64}})
308 return Q.
Types[0].isScalar() && Q.
Types[1].getScalarSizeInBits() < 64;
314 .customFor({{s32, s32}, {s64, s64}});
318 .
legalFor(HasCSSC, {{s32, s32}, {s64, s64}})
319 .legalFor({{v8s8, v8s8}, {v16s8, v16s8}})
320 .customFor(!HasCSSC, {{s32, s32}, {s64, s64}})
321 .customFor({{s128, s128},
327 .clampScalar(0, s32, s128)
347 .widenScalarToNextPow2(1, 32)
364 .customFor(!HasCSSC, {s32, s64});
370 .widenScalarToNextPow2(0, 32)
382 .
legalFor({s32, s64, v4s16, v8s16, v2s32, v4s32, v2s64})
384 .clampScalar(0, s32, s64)
385 .clampNumElements(0, v4s16, v8s16)
386 .clampNumElements(0, v2s32, v4s32)
387 .clampNumElements(0, v2s64, v2s64)
388 .moreElementsToNextPow2(0);
391 .legalFor({v8s8, v16s8, v4s16, v8s16, v2s32, v4s32, v2s64})
392 .legalFor(HasSVE, {nxv16s8, nxv8s16, nxv4s32, nxv2s64})
393 .clampNumElements(0, v8s8, v16s8)
402 {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FSQRT, G_FMAXNUM, G_FMINNUM,
403 G_FMAXIMUM, G_FMINIMUM, G_FCEIL, G_FFLOOR, G_FRINT, G_FNEARBYINT,
404 G_INTRINSIC_TRUNC, G_INTRINSIC_ROUND, G_INTRINSIC_ROUNDEVEN})
405 .legalFor({s32, s64, v2s32, v4s32, v2s64})
406 .legalFor(HasFP16, {s16, v4s16, v8s16})
416 .legalFor({s32, s64, v2s32, v4s32, v2s64})
417 .legalFor(HasFP16, {s16, v4s16, v8s16})
432 .legalFor({{s64, MinFPScalar}, {s64, s32}, {s64, s64}})
433 .libcallFor({{s64, s128}})
434 .minScalarOrElt(1, MinFPScalar);
437 G_FLOG10, G_FTAN, G_FEXP, G_FEXP2, G_FEXP10,
438 G_FACOS, G_FASIN, G_FATAN, G_FATAN2, G_FCOSH,
444 .libcallFor({s32, s64, s128});
448 .
libcallFor({{s32, s32}, {s64, s32}, {s128, s32}});
453 .legalFor({{s64, s32}, {s64, s64}});
467 for (
unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
470 if (
Op == G_SEXTLOAD)
475 .legalForTypesWithMemDesc({{s32, p0, s8, 8},
483 {v2s32, p0, s64, 8}})
484 .widenScalarToNextPow2(0)
485 .clampScalar(0, s32, s64)
488 .unsupportedIfMemSizeNotPow2()
500 return HasRCPC3 && Query.
Types[0] == s128 &&
504 return Query.
Types[0] == s128 &&
507 .legalForTypesWithMemDesc({{s8, p0, s8, 8},
514 {v16s8, p0, s128, 8},
516 {v8s16, p0, s128, 8},
518 {v4s32, p0, s128, 8},
519 {v2s64, p0, s128, 8}})
521 .legalForTypesWithMemDesc(
522 {{s32, p0, s8, 8}, {s32, p0, s16, 8}, {s64, p0, s32, 8}})
523 .legalForTypesWithMemDesc({
525 {nxv16s8, p0, nxv16s8, 8},
526 {nxv8s16, p0, nxv8s16, 8},
527 {nxv4s32, p0, nxv4s32, 8},
528 {nxv2s64, p0, nxv2s64, 8},
530 .widenScalarToNextPow2(0, 8)
541 return Query.
Types[0].isScalar() &&
543 Query.
Types[0].getSizeInBits() > 32;
552 .customIf(IsPtrVecPred)
558 return HasRCPC3 && Query.
Types[0] == s128 &&
562 return Query.
Types[0] == s128 &&
565 .legalForTypesWithMemDesc(
566 {{s8, p0, s8, 8}, {s16, p0, s8, 8},
569 {s16, p0, s16, 8}, {s32, p0, s16, 8},
571 {s32, p0, s8, 8}, {s32, p0, s16, 8}, {s32, p0, s32, 8},
572 {s64, p0, s64, 8}, {s64, p0, s32, 8},
573 {p0, p0, s64, 8}, {s128, p0, s128, 8}, {v16s8, p0, s128, 8},
574 {v8s8, p0, s64, 8}, {v4s16, p0, s64, 8}, {v8s16, p0, s128, 8},
575 {v2s32, p0, s64, 8}, {v4s32, p0, s128, 8}, {v2s64, p0, s128, 8}})
576 .legalForTypesWithMemDesc({
581 {nxv16s8, p0, nxv16s8, 8},
582 {nxv8s16, p0, nxv8s16, 8},
583 {nxv4s32, p0, nxv4s32, 8},
584 {nxv2s64, p0, nxv2s64, 8},
586 .clampScalar(0, s8, s64)
589 return Query.
Types[0].isScalar() &&
593 .clampMaxNumElements(0, s8, 16)
602 return Query.
Types[0].getSizeInBits() ==
603 Query.
MMODescrs[0].MemoryTy.getSizeInBits();
609 .customIf(IsPtrVecPred)
627 {p0, v16s8, v16s8, 8},
628 {p0, v4s16, v4s16, 8},
629 {p0, v8s16, v8s16, 8},
630 {p0, v2s32, v2s32, 8},
631 {p0, v4s32, v4s32, 8},
632 {p0, v2s64, v2s64, 8},
638 auto IndexedLoadBasicPred = [=](
const LegalityQuery &Query) {
666 return MemTy == s8 || MemTy == s16;
668 return MemTy == s8 || MemTy == s16 || MemTy == s32;
676 .widenScalarToNextPow2(0)
680 .legalFor(HasFP16, {s16})
681 .clampScalar(0, MinFPScalar, s128);
685 .
legalFor({{s32, s32}, {s32, s64}, {s32, p0}})
687 .clampScalar(1, s32, s64)
688 .clampScalar(0, s32, s32)
690 .minScalarEltSameAsIf(
703 return Query.
Types[1].isPointerVector();
707 .clampNumElements(1, v8s8, v16s8)
708 .clampNumElements(1, v4s16, v8s16)
709 .clampNumElements(1, v2s32, v4s32)
710 .clampNumElements(1, v2s64, v2s64)
711 .clampNumElements(1, v2p0, v2p0)
720 .legalFor(HasFP16, {{s32, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
722 .clampScalar(0, s32, s32)
723 .minScalarOrElt(1, MinFPScalar)
725 .minScalarEltSameAsIf(
733 .clampNumElements(1, v4s16, v8s16)
734 .clampNumElements(1, v2s32, v4s32)
735 .clampMaxNumElements(1, s64, 2)
736 .moreElementsToNextPow2(1)
737 .libcallFor({{s32, s128}});
741 unsigned DstSize = Query.
Types[0].getSizeInBits();
744 if (Query.
Types[0].isVector())
747 if (DstSize < 8 || DstSize >= 128 || !
isPowerOf2_32(DstSize))
762 .legalIf(ExtLegalFunc)
763 .
legalFor({{v8s16, v8s8}, {v4s32, v4s16}, {v2s64, v2s32}})
764 .clampScalar(0, s64, s64)
771 return (Query.
Types[0].getScalarSizeInBits() >
772 Query.
Types[1].getScalarSizeInBits() * 2) &&
773 Query.
Types[0].isVector() &&
774 (Query.
Types[1].getScalarSizeInBits() == 8 ||
775 Query.
Types[1].getScalarSizeInBits() == 16);
777 .clampMinNumElements(1, s8, 8)
782 .
legalFor({{v8s8, v8s16}, {v4s16, v4s32}, {v2s32, v2s64}})
784 .clampMaxNumElements(0, s8, 8)
785 .clampMaxNumElements(0, s16, 4)
786 .clampMaxNumElements(0, s32, 2)
796 .clampMinNumElements(0, s8, 8)
797 .clampMinNumElements(0, s16, 4)
801 .legalFor({{v8s8, v8s16}, {v4s16, v4s32}, {v2s32, v2s64}});
805 .legalFor(PackedVectorAllTypeList)
816 {{s16, s32}, {s16, s64}, {s32, s64}, {v4s16, v4s32}, {v2s32, v2s64}})
817 .libcallFor({{s16, s128}, {s32, s128}, {s64, s128}})
818 .clampNumElements(0, v4s16, v4s16)
824 {{s32, s16}, {s64, s16}, {s64, s32}, {v4s32, v4s16}, {v2s64, v2s32}})
825 .libcallFor({{s128, s64}, {s128, s32}, {s128, s16}})
826 .clampNumElements(0, v4s32, v4s32)
832 .legalFor({{s32, s32},
840 {{s32, s16}, {s64, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
847 return Query.
Types[1] == s16 && Query.
Types[0].getSizeInBits() > 64;
851 .widenScalarOrEltToNextPow2OrMinSize(0)
853 .widenScalarOrEltToNextPow2OrMinSize(1, HasFP16 ? 16 : 32)
856 return Query.
Types[0].getScalarSizeInBits() <= 64 &&
857 Query.
Types[0].getScalarSizeInBits() >
858 Query.
Types[1].getScalarSizeInBits();
863 return Query.
Types[1].getScalarSizeInBits() <= 64 &&
864 Query.
Types[0].getScalarSizeInBits() <
865 Query.
Types[1].getScalarSizeInBits();
868 .clampNumElements(0, v4s16, v8s16)
869 .clampNumElements(0, v2s32, v4s32)
870 .clampMaxNumElements(0, s64, 2)
872 {{s32, s128}, {s64, s128}, {s128, s128}, {s128, s32}, {s128, s64}});
875 .legalFor({{s32, s32},
884 {{s16, s16}, {s32, s16}, {s64, s16}, {v4s16, v4s16}, {v8s16, v8s16}})
892 return Query.
Types[1] == s16 && Query.
Types[0].getSizeInBits() > 64;
897 .widenScalarToNextPow2(0, 32)
899 .widenScalarOrEltToNextPow2OrMinSize(1, HasFP16 ? 16 : 32)
902 unsigned ITySize = Query.
Types[0].getScalarSizeInBits();
903 return (ITySize == 16 || ITySize == 32 || ITySize == 64) &&
904 ITySize > Query.
Types[1].getScalarSizeInBits();
909 unsigned FTySize = Query.
Types[1].getScalarSizeInBits();
910 return (FTySize == 16 || FTySize == 32 || FTySize == 64) &&
911 Query.
Types[0].getScalarSizeInBits() < FTySize;
915 .clampNumElements(0, v4s16, v8s16)
916 .clampNumElements(0, v2s32, v4s32)
917 .clampMaxNumElements(0, s64, 2);
920 .legalFor({{s32, s32},
928 {{s16, s32}, {s16, s64}, {v4s16, v4s16}, {v8s16, v8s16}})
935 return Query.
Types[1].isVector() &&
936 Query.
Types[1].getScalarSizeInBits() == 64 &&
937 Query.
Types[0].getScalarSizeInBits() == 16;
939 .widenScalarOrEltToNextPow2OrMinSize(0, HasFP16 ? 16 : 32)
943 return Query.
Types[0].getScalarSizeInBits() == 32 &&
944 Query.
Types[1].getScalarSizeInBits() == 64;
949 return Query.
Types[1].getScalarSizeInBits() <= 64 &&
950 Query.
Types[0].getScalarSizeInBits() <
951 Query.
Types[1].getScalarSizeInBits();
956 return Query.
Types[0].getScalarSizeInBits() <= 64 &&
957 Query.
Types[0].getScalarSizeInBits() >
958 Query.
Types[1].getScalarSizeInBits();
961 .clampNumElements(0, v4s16, v8s16)
975 .clampScalar(0, s32, s32);
979 .
legalFor({{s32, s32}, {s64, s32}, {p0, s32}})
980 .widenScalarToNextPow2(0)
999 .
legalFor({{s64, p0}, {v2s64, v2p0}})
1000 .widenScalarToNextPow2(0, 64)
1006 return Query.
Types[0].getSizeInBits() != Query.
Types[1].getSizeInBits();
1008 .legalFor({{p0, s64}, {v2p0, v2s64}})
1009 .clampMaxNumElements(1, s64, 2);
1016 .legalForCartesianProduct({s64, v8s8, v4s16, v2s32})
1017 .legalForCartesianProduct({s128, v16s8, v8s16, v4s32, v2s64, v2p0})
1026 return Query.
Types[0].isVector() != Query.
Types[1].isVector();
1029 .clampNumElements(0, v8s8, v16s8)
1030 .clampNumElements(0, v4s16, v8s16)
1031 .clampNumElements(0, v2s32, v4s32)
1040 .clampScalar(0, s8, s64)
1047 bool UseOutlineAtomics = ST.outlineAtomics() && !ST.hasLSE();
1050 .
legalFor(!UseOutlineAtomics, {{s32, p0}, {s64, p0}})
1051 .customFor(!UseOutlineAtomics, {{s128, p0}})
1052 .libcallFor(UseOutlineAtomics,
1053 {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}, {s128, p0}})
1054 .clampScalar(0, s32, s64);
1057 G_ATOMICRMW_SUB, G_ATOMICRMW_AND, G_ATOMICRMW_OR,
1059 .legalFor(!UseOutlineAtomics, {{s32, p0}, {s64, p0}})
1060 .libcallFor(UseOutlineAtomics,
1061 {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
1062 .clampScalar(0, s32, s64);
1067 {G_ATOMICRMW_MIN, G_ATOMICRMW_MAX, G_ATOMICRMW_UMIN, G_ATOMICRMW_UMAX})
1074 for (
unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
1075 unsigned BigTyIdx =
Op == G_MERGE_VALUES ? 0 : 1;
1076 unsigned LitTyIdx =
Op == G_MERGE_VALUES ? 1 : 0;
1083 switch (Q.
Types[BigTyIdx].getSizeInBits()) {
1091 switch (Q.
Types[LitTyIdx].getSizeInBits()) {
1105 .
legalFor(HasSVE, {{s16, nxv16s8, s64},
1106 {s16, nxv8s16, s64},
1107 {s32, nxv4s32, s64},
1108 {s64, nxv2s64, s64}})
1110 const LLT &EltTy = Query.
Types[1].getElementType();
1111 if (Query.
Types[1].isScalableVector())
1113 return Query.
Types[0] != EltTy;
1118 return VecTy == v8s8 || VecTy == v16s8 || VecTy == v2s16 ||
1119 VecTy == v4s16 || VecTy == v8s16 || VecTy == v2s32 ||
1120 VecTy == v4s32 || VecTy == v2s64 || VecTy == v2p0;
1126 return Query.
Types[1].isFixedVector() &&
1127 Query.
Types[1].getNumElements() <= 2;
1132 return Query.
Types[1].isFixedVector() &&
1133 Query.
Types[1].getNumElements() <= 4;
1138 return Query.
Types[1].isFixedVector() &&
1139 Query.
Types[1].getNumElements() <= 8;
1144 return Query.
Types[1].isFixedVector() &&
1145 Query.
Types[1].getNumElements() <= 16;
1148 .minScalarOrElt(0, s8)
1159 typeInSet(0, {v8s8, v16s8, v4s16, v8s16, v2s32, v4s32, v2s64, v2p0}))
1160 .
legalFor(HasSVE, {{nxv16s8, s32, s64},
1161 {nxv8s16, s32, s64},
1162 {nxv4s32, s32, s64},
1163 {nxv2s64, s64, s64}})
1165 .widenVectorEltsToVectorMinSize(0, 64)
1166 .clampNumElements(0, v8s8, v16s8)
1167 .clampNumElements(0, v4s16, v8s16)
1168 .clampNumElements(0, v2s32, v4s32)
1169 .clampMaxNumElements(0, s64, 2)
1170 .clampMaxNumElements(0, p0, 2)
1182 .clampNumElements(0, v4s32, v4s32)
1200 {v8s8, v16s8, v4s16, v8s16, v2s32, v4s32, v2s64}, DstTy);
1206 return !Query.
Types[0].isVector() || !Query.
Types[1].isVector();
1210 return Query.
Types[0].isVector() && Query.
Types[1].isVector() &&
1211 Query.
Types[0].getNumElements() >
1212 Query.
Types[1].getNumElements();
1218 return Query.
Types[0].isVector() && Query.
Types[1].isVector() &&
1219 Query.
Types[0].getNumElements() <
1220 Query.
Types[1].getNumElements();
1223 .widenScalarOrEltToNextPow2OrMinSize(0, 8)
1224 .clampNumElements(0, v8s8, v16s8)
1225 .clampNumElements(0, v4s16, v8s16)
1226 .clampNumElements(0, v4s32, v4s32)
1227 .clampNumElements(0, v2s64, v2s64)
1236 .
legalFor({{v16s8, v8s8}, {v8s16, v4s16}, {v4s32, v2s32}})
1239 return Query.
Types[0].getSizeInBits() <= 128 &&
1240 Query.
Types[1].getSizeInBits() <= 64;
1253 .
legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
1259 .
legalFor(HasSVE, {{nxv4s32, s32}, {nxv2s64, s64}});
1278 .customForCartesianProduct({p0}, {s8}, {s64})
1282 .legalForCartesianProduct({p0}, {p0}, {s64})
1298 .
legalFor({{s32, v2s32}, {s32, v4s32}, {s64, v2s64}})
1299 .legalFor(HasFP16, {{s16, v4s16}, {s16, v8s16}})
1300 .minScalarOrElt(0, MinFPScalar)
1334 .clampMaxNumElements(1, s64, 2)
1335 .clampMaxNumElements(1, s32, 4)
1336 .clampMaxNumElements(1, s16, 8)
1337 .clampMaxNumElements(1, s8, 16)
1338 .widenVectorEltsToVectorMinSize(1, 64)
1342 G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM})
1343 .legalFor({{s32, v2s32}, {s32, v4s32}, {s64, v2s64}})
1344 .legalFor(HasFP16, {{s16, v4s16}, {s16, v8s16}})
1345 .minScalarOrElt(0, MinFPScalar)
1359 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX})
1360 .legalFor({{s8, v8s8},
1368 return Query.
Types[1].isVector() &&
1369 Query.
Types[1].getElementType() != s8 &&
1370 Query.
Types[1].getNumElements() & 1;
1373 .clampMaxNumElements(1, s64, 2)
1381 {G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
1397 return std::make_pair(1, SrcTy.
divide(2));
1407 G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE})
1417 verify(*ST.getInstrInfo());
1426 switch (
MI.getOpcode()) {
1430 case TargetOpcode::G_VAARG:
1431 return legalizeVaArg(
MI,
MRI, MIRBuilder);
1432 case TargetOpcode::G_LOAD:
1433 case TargetOpcode::G_STORE:
1434 return legalizeLoadStore(
MI,
MRI, MIRBuilder, Observer);
1435 case TargetOpcode::G_SHL:
1436 case TargetOpcode::G_ASHR:
1437 case TargetOpcode::G_LSHR:
1438 return legalizeShlAshrLshr(
MI,
MRI, MIRBuilder, Observer);
1439 case TargetOpcode::G_GLOBAL_VALUE:
1440 return legalizeSmallCMGlobalValue(
MI,
MRI, MIRBuilder, Observer);
1441 case TargetOpcode::G_SBFX:
1442 case TargetOpcode::G_UBFX:
1443 return legalizeBitfieldExtract(
MI,
MRI, Helper);
1444 case TargetOpcode::G_FSHL:
1445 case TargetOpcode::G_FSHR:
1446 return legalizeFunnelShift(
MI,
MRI, MIRBuilder, Observer, Helper);
1447 case TargetOpcode::G_ROTR:
1448 return legalizeRotate(
MI,
MRI, Helper);
1449 case TargetOpcode::G_CTPOP:
1450 return legalizeCTPOP(
MI,
MRI, Helper);
1451 case TargetOpcode::G_ATOMIC_CMPXCHG:
1452 return legalizeAtomicCmpxchg128(
MI,
MRI, Helper);
1453 case TargetOpcode::G_CTTZ:
1454 return legalizeCTTZ(
MI, Helper);
1455 case TargetOpcode::G_BZERO:
1456 case TargetOpcode::G_MEMCPY:
1457 case TargetOpcode::G_MEMMOVE:
1458 case TargetOpcode::G_MEMSET:
1459 return legalizeMemOps(
MI, Helper);
1460 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1461 return legalizeExtractVectorElt(
MI,
MRI, Helper);
1462 case TargetOpcode::G_DYN_STACKALLOC:
1463 return legalizeDynStackAlloc(
MI, Helper);
1464 case TargetOpcode::G_PREFETCH:
1465 return legalizePrefetch(
MI, Helper);
1466 case TargetOpcode::G_ABS:
1468 case TargetOpcode::G_ICMP:
1469 return legalizeICMP(
MI,
MRI, MIRBuilder);
1470 case TargetOpcode::G_BITCAST:
1471 return legalizeBitcast(
MI, Helper);
1479 assert(
MI.getOpcode() == TargetOpcode::G_BITCAST &&
"Unexpected opcode");
1480 auto [DstReg, DstTy, SrcReg, SrcTy] =
MI.getFirst2RegLLTs();
1483 if (!DstTy.isScalar() || !SrcTy.isVector() ||
1488 MI.eraseFromParent();
1497 assert(
MI.getOpcode() == TargetOpcode::G_FSHL ||
1498 MI.getOpcode() == TargetOpcode::G_FSHR);
1502 Register ShiftNo =
MI.getOperand(3).getReg();
1503 LLT ShiftTy =
MRI.getType(ShiftNo);
1508 LLT OperationTy =
MRI.getType(
MI.getOperand(0).getReg());
1512 if (!VRegAndVal || VRegAndVal->Value.urem(
BitWidth) == 0)
1518 Amount =
MI.getOpcode() == TargetOpcode::G_FSHL ?
BitWidth - Amount : Amount;
1522 if (ShiftTy.
getSizeInBits() == 64 &&
MI.getOpcode() == TargetOpcode::G_FSHR &&
1529 if (
MI.getOpcode() == TargetOpcode::G_FSHR) {
1531 MI.getOperand(3).setReg(Cast64.getReg(0));
1536 else if (
MI.getOpcode() == TargetOpcode::G_FSHL) {
1538 {
MI.getOperand(1).
getReg(),
MI.getOperand(2).getReg(),
1540 MI.eraseFromParent();
1549 Register SrcReg1 =
MI.getOperand(2).getReg();
1550 Register SrcReg2 =
MI.getOperand(3).getReg();
1551 LLT DstTy =
MRI.getType(DstReg);
1552 LLT SrcTy =
MRI.getType(SrcReg1);
1569 MIRBuilder.
buildNot(DstReg, CmpReg);
1571 MI.eraseFromParent();
1581 LLT AmtTy =
MRI.getType(AmtReg);
1587 MI.getOperand(2).setReg(NewAmt.getReg(0));
1592bool AArch64LegalizerInfo::legalizeSmallCMGlobalValue(
1595 assert(
MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
1600 auto &GlobalOp =
MI.getOperand(1);
1602 if (GlobalOp.isSymbol())
1604 const auto* GV = GlobalOp.getGlobal();
1605 if (GV->isThreadLocal())
1614 auto Offset = GlobalOp.getOffset();
1619 MRI.setRegClass(ADRP.getReg(0), &AArch64::GPR64RegClass);
1636 "Should not have folded in an offset for a tagged global!");
1638 .addGlobalAddress(GV, 0x100000000,
1641 MRI.setRegClass(ADRP.getReg(0), &AArch64::GPR64RegClass);
1644 MIRBuilder.
buildInstr(AArch64::G_ADD_LOW, {DstReg}, {ADRP})
1645 .addGlobalAddress(GV,
Offset,
1647 MI.eraseFromParent();
1656 auto LowerUnaryOp = [&
MI, &MIB](
unsigned Opcode) {
1658 MI.eraseFromParent();
1661 auto LowerBinOp = [&
MI, &MIB](
unsigned Opcode) {
1663 {
MI.getOperand(2),
MI.getOperand(3)});
1664 MI.eraseFromParent();
1667 auto LowerTriOp = [&
MI, &MIB](
unsigned Opcode) {
1669 {
MI.getOperand(2),
MI.getOperand(3),
MI.getOperand(4)});
1670 MI.eraseFromParent();
1675 switch (IntrinsicID) {
1676 case Intrinsic::vacopy: {
1678 unsigned VaListSize =
1689 VaListSize,
Align(PtrSize)));
1693 VaListSize,
Align(PtrSize)));
1694 MI.eraseFromParent();
1697 case Intrinsic::get_dynamic_area_offset: {
1699 MI.eraseFromParent();
1702 case Intrinsic::aarch64_mops_memset_tag: {
1703 assert(
MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
1706 auto &
Value =
MI.getOperand(3);
1708 Value.setReg(ExtValueReg);
1711 case Intrinsic::aarch64_prefetch: {
1712 auto &AddrVal =
MI.getOperand(1);
1714 int64_t IsWrite =
MI.getOperand(2).getImm();
1715 int64_t
Target =
MI.getOperand(3).getImm();
1716 int64_t IsStream =
MI.getOperand(4).getImm();
1717 int64_t IsData =
MI.getOperand(5).getImm();
1719 unsigned PrfOp = (IsWrite << 4) |
1725 MI.eraseFromParent();
1728 case Intrinsic::aarch64_neon_uaddv:
1729 case Intrinsic::aarch64_neon_saddv:
1730 case Intrinsic::aarch64_neon_umaxv:
1731 case Intrinsic::aarch64_neon_smaxv:
1732 case Intrinsic::aarch64_neon_uminv:
1733 case Intrinsic::aarch64_neon_sminv: {
1734 bool IsSigned = IntrinsicID == Intrinsic::aarch64_neon_saddv ||
1735 IntrinsicID == Intrinsic::aarch64_neon_smaxv ||
1736 IntrinsicID == Intrinsic::aarch64_neon_sminv;
1738 auto OldDst =
MI.getOperand(0).getReg();
1739 auto OldDstTy =
MRI.getType(OldDst);
1740 LLT NewDstTy =
MRI.getType(
MI.getOperand(2).getReg()).getElementType();
1741 if (OldDstTy == NewDstTy)
1744 auto NewDst =
MRI.createGenericVirtualRegister(NewDstTy);
1747 MI.getOperand(0).setReg(NewDst);
1751 MIB.
buildExtOrTrunc(IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT,
1756 case Intrinsic::aarch64_neon_uaddlp:
1757 case Intrinsic::aarch64_neon_saddlp: {
1758 unsigned Opc = IntrinsicID == Intrinsic::aarch64_neon_uaddlp
1760 : AArch64::G_SADDLP;
1762 MI.eraseFromParent();
1766 case Intrinsic::aarch64_neon_uaddlv:
1767 case Intrinsic::aarch64_neon_saddlv: {
1768 unsigned Opc = IntrinsicID == Intrinsic::aarch64_neon_uaddlv
1770 : AArch64::G_SADDLV;
1773 LLT DstTy =
MRI.getType(DstReg);
1797 MI.eraseFromParent();
1801 case Intrinsic::aarch64_neon_smax:
1802 return LowerBinOp(TargetOpcode::G_SMAX);
1803 case Intrinsic::aarch64_neon_smin:
1804 return LowerBinOp(TargetOpcode::G_SMIN);
1805 case Intrinsic::aarch64_neon_umax:
1806 return LowerBinOp(TargetOpcode::G_UMAX);
1807 case Intrinsic::aarch64_neon_umin:
1808 return LowerBinOp(TargetOpcode::G_UMIN);
1809 case Intrinsic::aarch64_neon_fmax:
1810 return LowerBinOp(TargetOpcode::G_FMAXIMUM);
1811 case Intrinsic::aarch64_neon_fmin:
1812 return LowerBinOp(TargetOpcode::G_FMINIMUM);
1813 case Intrinsic::aarch64_neon_fmaxnm:
1814 return LowerBinOp(TargetOpcode::G_FMAXNUM);
1815 case Intrinsic::aarch64_neon_fminnm:
1816 return LowerBinOp(TargetOpcode::G_FMINNUM);
1817 case Intrinsic::aarch64_neon_smull:
1818 return LowerBinOp(AArch64::G_SMULL);
1819 case Intrinsic::aarch64_neon_umull:
1820 return LowerBinOp(AArch64::G_UMULL);
1821 case Intrinsic::aarch64_neon_sabd:
1822 return LowerBinOp(TargetOpcode::G_ABDS);
1823 case Intrinsic::aarch64_neon_uabd:
1824 return LowerBinOp(TargetOpcode::G_ABDU);
1825 case Intrinsic::aarch64_neon_abs: {
1827 MIB.
buildInstr(TargetOpcode::G_ABS, {
MI.getOperand(0)}, {
MI.getOperand(2)});
1828 MI.eraseFromParent();
1831 case Intrinsic::aarch64_neon_sqadd: {
1832 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector())
1833 return LowerBinOp(TargetOpcode::G_SADDSAT);
1836 case Intrinsic::aarch64_neon_sqsub: {
1837 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector())
1838 return LowerBinOp(TargetOpcode::G_SSUBSAT);
1841 case Intrinsic::aarch64_neon_uqadd: {
1842 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector())
1843 return LowerBinOp(TargetOpcode::G_UADDSAT);
1846 case Intrinsic::aarch64_neon_uqsub: {
1847 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector())
1848 return LowerBinOp(TargetOpcode::G_USUBSAT);
1851 case Intrinsic::aarch64_neon_udot:
1852 return LowerTriOp(AArch64::G_UDOT);
1853 case Intrinsic::aarch64_neon_sdot:
1854 return LowerTriOp(AArch64::G_SDOT);
1855 case Intrinsic::aarch64_neon_sqxtn:
1856 return LowerUnaryOp(TargetOpcode::G_TRUNC_SSAT_S);
1857 case Intrinsic::aarch64_neon_sqxtun:
1858 return LowerUnaryOp(TargetOpcode::G_TRUNC_SSAT_U);
1859 case Intrinsic::aarch64_neon_uqxtn:
1860 return LowerUnaryOp(TargetOpcode::G_TRUNC_USAT_U);
1862 case Intrinsic::vector_reverse:
1870bool AArch64LegalizerInfo::legalizeShlAshrLshr(
1873 assert(
MI.getOpcode() == TargetOpcode::G_ASHR ||
1874 MI.getOpcode() == TargetOpcode::G_LSHR ||
1875 MI.getOpcode() == TargetOpcode::G_SHL);
1888 MI.getOperand(2).setReg(ExtCst.getReg(0));
1901 isShiftedInt<7, 3>(NewOffset)) {
1909bool AArch64LegalizerInfo::legalizeLoadStore(
1912 assert(
MI.getOpcode() == TargetOpcode::G_STORE ||
1913 MI.getOpcode() == TargetOpcode::G_LOAD);
1924 const LLT ValTy =
MRI.getType(ValReg);
1929 bool IsLoad =
MI.getOpcode() == TargetOpcode::G_LOAD;
1933 ST->hasLSE2() && ST->hasRCPC3() && (IsLoadAcquire || IsStoreRelease);
1939 Opcode = IsLoad ? AArch64::LDIAPPX : AArch64::STILPX;
1945 assert(ST->hasLSE2() &&
"ldp/stp not single copy atomic without +lse2");
1947 Opcode = IsLoad ? AArch64::LDPXi : AArch64::STPXi;
1952 NewI = MIRBuilder.
buildInstr(Opcode, {s64, s64}, {});
1958 Opcode, {}, {
Split->getOperand(0),
Split->getOperand(1)});
1962 NewI.
addUse(
MI.getOperand(1).getReg());
1973 *
MRI.getTargetRegisterInfo(),
1975 MI.eraseFromParent();
1981 LLVM_DEBUG(
dbgs() <<
"Tried to do custom legalization on wrong load/store");
1987 auto &MMO = **
MI.memoperands_begin();
1990 if (
MI.getOpcode() == TargetOpcode::G_STORE) {
1994 auto NewLoad = MIRBuilder.
buildLoad(NewTy,
MI.getOperand(1), MMO);
1997 MI.eraseFromParent();
2005 Align Alignment(
MI.getOperand(2).getImm());
2007 Register ListPtr =
MI.getOperand(1).getReg();
2009 LLT PtrTy =
MRI.getType(ListPtr);
2020 if (Alignment > PtrAlign) {
2024 auto ListTmp = MIRBuilder.
buildPtrAdd(PtrTy,
List, AlignMinus1.getReg(0));
2029 LLT ValTy =
MRI.getType(Dst);
2034 ValTy, std::max(Alignment, PtrAlign)));
2045 MI.eraseFromParent();
2049bool AArch64LegalizerInfo::legalizeBitfieldExtract(
2083 LLT Ty =
MRI.getType(Val);
2087 "Expected src and dst to have the same type!");
2095 auto Add = MIRBuilder.
buildAdd(s64, CTPOP1, CTPOP2);
2098 MI.eraseFromParent();
2102 if (!ST->hasNEON() ||
2103 MI.getMF()->getFunction().hasFnAttribute(Attribute::NoImplicitFloat)) {
2115 assert((
Size == 32 ||
Size == 64 ||
Size == 128) &&
"Expected only 32, 64, or 128 bit scalars!");
2137 Sum = MIRBuilder.
buildInstr(AArch64::G_UADDLP, {Ty}, {UDOT});
2139 Sum = MIRBuilder.
buildInstr(AArch64::G_UDOT, {Dt}, {Zeros, Ones,
CTPOP});
2141 Sum = MIRBuilder.
buildInstr(AArch64::G_UDOT, {Dt}, {Zeros, Ones,
CTPOP});
2147 MI.eraseFromParent();
2155 Opc = Intrinsic::aarch64_neon_uaddlv;
2158 Opc = Intrinsic::aarch64_neon_uaddlp;
2161 Opc = Intrinsic::aarch64_neon_uaddlp;
2165 Opc = Intrinsic::aarch64_neon_uaddlp;
2170 Opc = Intrinsic::aarch64_neon_uaddlp;
2173 Opc = Intrinsic::aarch64_neon_uaddlp;
2179 for (
LLT HTy : HAddTys) {
2189 MI.eraseFromParent();
2193bool AArch64LegalizerInfo::legalizeAtomicCmpxchg128(
2197 auto Addr =
MI.getOperand(1).getReg();
2198 auto DesiredI = MIRBuilder.
buildUnmerge({s64, s64},
MI.getOperand(2));
2199 auto NewI = MIRBuilder.
buildUnmerge({s64, s64},
MI.getOperand(3));
2200 auto DstLo =
MRI.createGenericVirtualRegister(s64);
2201 auto DstHi =
MRI.createGenericVirtualRegister(s64);
2214 auto Ordering = (*
MI.memoperands_begin())->getMergedOrdering();
2218 Opcode = AArch64::CASPAX;
2221 Opcode = AArch64::CASPLX;
2225 Opcode = AArch64::CASPALX;
2228 Opcode = AArch64::CASPX;
2233 auto CASDst =
MRI.createGenericVirtualRegister(s128);
2234 auto CASDesired =
MRI.createGenericVirtualRegister(s128);
2235 auto CASNew =
MRI.createGenericVirtualRegister(s128);
2236 MIRBuilder.
buildInstr(TargetOpcode::REG_SEQUENCE, {CASDesired}, {})
2237 .addUse(DesiredI->getOperand(0).getReg())
2239 .
addUse(DesiredI->getOperand(1).getReg())
2240 .
addImm(AArch64::subo64);
2241 MIRBuilder.
buildInstr(TargetOpcode::REG_SEQUENCE, {CASNew}, {})
2245 .
addImm(AArch64::subo64);
2247 CAS = MIRBuilder.
buildInstr(Opcode, {CASDst}, {CASDesired, CASNew,
Addr});
2255 auto Ordering = (*
MI.memoperands_begin())->getMergedOrdering();
2259 Opcode = AArch64::CMP_SWAP_128_ACQUIRE;
2262 Opcode = AArch64::CMP_SWAP_128_RELEASE;
2266 Opcode = AArch64::CMP_SWAP_128;
2269 Opcode = AArch64::CMP_SWAP_128_MONOTONIC;
2273 auto Scratch =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2274 CAS = MIRBuilder.
buildInstr(Opcode, {DstLo, DstHi, Scratch},
2275 {
Addr, DesiredI->getOperand(0),
2276 DesiredI->getOperand(1), NewI->
getOperand(0),
2282 *
MRI.getTargetRegisterInfo(),
2286 MI.eraseFromParent();
2294 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
2296 MIRBuilder.
buildCTLZ(
MI.getOperand(0).getReg(), BitReverse);
2297 MI.eraseFromParent();
2306 if (
MI.getOpcode() == TargetOpcode::G_MEMSET) {
2309 auto &
Value =
MI.getOperand(1);
2312 Value.setReg(ExtValueReg);
2319bool AArch64LegalizerInfo::legalizeExtractVectorElt(
2333bool AArch64LegalizerInfo::legalizeDynStackAlloc(
2349 Register AllocSize =
MI.getOperand(1).getReg();
2353 "Unexpected type for dynamic alloca");
2355 "Unexpected type for dynamic alloca");
2357 LLT PtrTy =
MRI.getType(Dst);
2363 MIRBuilder.
buildInstr(AArch64::PROBED_STACKALLOC_DYN, {}, {SPTmp});
2364 MRI.setRegClass(NewMI.getReg(0), &AArch64::GPR64commonRegClass);
2365 MIRBuilder.
setInsertPt(*NewMI->getParent(), NewMI);
2368 MI.eraseFromParent();
2375 auto &AddrVal =
MI.getOperand(0);
2377 int64_t IsWrite =
MI.getOperand(1).getImm();
2378 int64_t Locality =
MI.getOperand(2).getImm();
2379 int64_t
IsData =
MI.getOperand(3).getImm();
2381 bool IsStream = Locality == 0;
2382 if (Locality != 0) {
2383 assert(Locality <= 3 &&
"Prefetch locality out-of-range");
2387 Locality = 3 - Locality;
2390 unsigned PrfOp = (IsWrite << 4) | (!IsData << 3) | (Locality << 1) | IsStream;
2393 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.
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)
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.
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.
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.
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 & 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...
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.
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,...
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)
This is an optimization pass for GlobalISel generic memory operations.
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...
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.
constexpr unsigned BitWidth
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.
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,...