26using namespace TargetOpcode;
27using namespace LegalizeActions;
28using namespace LegalityPredicates;
34 bool Is64Bit = Subtarget.is64Bit();
36 bool HasSSE1 = Subtarget.
hasSSE1();
37 bool HasSSE2 = Subtarget.
hasSSE2();
38 bool HasSSE41 = Subtarget.
hasSSE41();
39 bool HasAVX = Subtarget.
hasAVX();
40 bool HasAVX2 = Subtarget.
hasAVX2();
42 bool HasVLX = Subtarget.hasVLX();
43 bool HasDQI = Subtarget.
hasAVX512() && Subtarget.hasDQI();
44 bool HasBWI = Subtarget.
hasAVX512() && Subtarget.hasBWI();
45 bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
55 const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
77 const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
78 const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
79 const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
80 const LLT s64MaxVector = HasAVX512 ? v8s64 : HasAVX ? v4s64 : v2s64;
90 return typeInSet(0, {p0, s1, s8, s16, s32, s64})(Query) ||
96 return typeInSet(0, {p0, s8, s16, s32})(Query) ||
99 .widenScalarToNextPow2(0, 8)
107 for (
unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
108 unsigned BigTyIdx =
Op == G_MERGE_VALUES ? 0 : 1;
109 unsigned LitTyIdx =
Op == G_MERGE_VALUES ? 1 : 0;
116 switch (Q.
Types[BigTyIdx].getSizeInBits()) {
127 switch (Q.
Types[LitTyIdx].getSizeInBits()) {
146 if (Is64Bit &&
typeInSet(0, {s64})(Query))
148 if (HasSSE2 &&
typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
150 if (HasAVX2 &&
typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
152 if (HasAVX512 &&
typeInSet(0, {v16s32, v8s64})(Query))
154 if (HasBWI &&
typeInSet(0, {v64s8, v32s16})(Query))
158 .clampMinNumElements(0, s8, 16)
172 return typePairInSet(0, 1, {{s8, s1}, {s16, s1}, {s32, s1}})(Query) ||
175 .widenScalarToNextPow2(0, 32)
185 if (Is64Bit &&
typeInSet(0, {s64})(Query))
187 if (HasSSE2 &&
typeInSet(0, {v8s16})(Query))
189 if (HasSSE41 &&
typeInSet(0, {v4s32})(Query))
191 if (HasAVX2 &&
typeInSet(0, {v16s16, v8s32})(Query))
193 if (HasAVX512 &&
typeInSet(0, {v16s32})(Query))
195 if (HasDQI &&
typeInSet(0, {v8s64})(Query))
197 if (HasDQI && HasVLX &&
typeInSet(0, {v2s64, v4s64})(Query))
199 if (HasBWI &&
typeInSet(0, {v32s16})(Query))
203 .clampMinNumElements(0, s16, 8)
215 return typeInSet(0, {s8, s16, s32})(Query) ||
218 .widenScalarToNextPow2(0, 32)
225 return typeInSet(0, {s8, s16, s32})(Query) ||
229 .clampScalar(0, s8, sMaxScalar);
234 return typePairInSet(0, 1, {{s8, s8}, {s16, s8}, {s32, s8}})(Query) ||
237 .clampScalar(0, s8, sMaxScalar)
245 if (Is64Bit &&
typeInSet(0, {s64})(Query))
247 if (HasSSE2 &&
typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
249 if (HasAVX &&
typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
251 if (HasAVX512 &&
typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query))
255 .clampMinNumElements(0, s8, 16)
268 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
269 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
273 .clampScalar(0, s8, s8)
279 return Query.
Types[0] == s32 ||
280 (Subtarget.is64Bit() && Query.
Types[0] == s64);
282 .widenScalarToNextPow2(0, 32)
288 return Subtarget.hasPOPCNT() &&
292 .widenScalarToNextPow2(1, 16)
299 return Subtarget.hasLZCNT() &&
303 .widenScalarToNextPow2(1, 16)
310 return (Query.
Opcode == G_CTTZ_ZERO_UNDEF || Subtarget.hasBMI()) &&
314 .widenScalarToNextPow2(1, 16)
321 return typeInSet(0, {s8, s16, s32, p0})(Query) ||
322 (UseX87 &&
typeIs(0, s80)(Query)) ||
323 (Is64Bit &&
typeIs(0, s64)(Query)) ||
324 (HasSSE1 &&
typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) ||
325 (HasAVX &&
typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) ||
327 typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query));
329 .clampMinNumElements(0, s8, 16)
334 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
335 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
336 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
337 .widenScalarToNextPow2(0, 32)
344 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
345 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
349 .maxScalar(0, sMaxScalar)
361 .widenScalarToNextPow2(1, 32)
367 for (
unsigned Op : {G_LOAD, G_STORE}) {
369 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
378 {v4s8, p0, v4s8, 1}});
380 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
384 {v2s32, p0, v2s32, 1}});
386 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
388 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
389 {v8s16, p0, v8s16, 1},
390 {v2s64, p0, v2s64, 1},
391 {v2p0, p0, v2p0, 1}});
393 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
394 {v16s16, p0, v16s16, 1},
395 {v8s32, p0, v8s32, 1},
396 {v4s64, p0, v4s64, 1},
397 {v4p0, p0, v4p0, 1}});
399 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
400 {v32s16, p0, v32s16, 1},
401 {v16s32, p0, v16s32, 1},
402 {v8s64, p0, v8s64, 1}});
403 Action.widenScalarToNextPow2(0, 8)
404 .clampScalar(0, s8, sMaxScalar)
408 for (
unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
410 Action.legalForTypesWithMemDesc({{s16, p0, s8, 1},
414 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
423 return typeInSet(0, {s8, s16, s32})(Query) ||
424 (Query.
Opcode == G_ANYEXT && Query.
Types[0] == s128) ||
425 (Is64Bit && Query.
Types[0] == s64);
427 .widenScalarToNextPow2(0, 8)
438 return (
typeInSet(0, {s32, s64})(Query)) ||
445 return (
typeInSet(0, {s32, s64})(Query)) ||
446 (HasSSE1 &&
typeInSet(0, {v4s32})(Query)) ||
447 (HasSSE2 &&
typeInSet(0, {v2s64})(Query)) ||
448 (HasAVX &&
typeInSet(0, {v8s32, v4s64})(Query)) ||
449 (HasAVX512 &&
typeInSet(0, {v16s32, v8s64})(Query)) ||
456 return (HasSSE1 &&
typePairInSet(0, 1, {{s8, s32}})(Query)) ||
459 .clampScalar(0, s8, s8)
465 return (HasSSE2 &&
typePairInSet(0, 1, {{s64, s32}})(Query)) ||
472 return (HasSSE2 &&
typePairInSet(0, 1, {{s32, s64}})(Query)) ||
486 .clampScalar(1, s32, sMaxScalar)
500 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
514 return HasAVX512 &&
typeInSet(0, {s32, s64})(Query) &&
519 ((HasSSE1 &&
typeIs(0, s32)(Query)) ||
520 (HasSSE2 &&
typeIs(0, s64)(Query))) &&
526 ((HasSSE1 &&
typeIs(0, s32)(Query)) ||
527 (HasSSE2 &&
typeIs(0, s64)(Query))) &&
528 (Is64Bit &&
typeIs(1, s64)(Query));
530 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
537 return HasAVX512 &&
typeInSet(0, {s32, s64})(Query) &&
542 ((HasSSE1 &&
typeIs(1, s32)(Query)) ||
543 (HasSSE2 &&
typeIs(1, s64)(Query))) &&
552 ((HasSSE1 &&
typeIs(1, s32)(Query)) ||
553 (HasSSE2 &&
typeIs(1, s64)(Query))) &&
554 (Is64Bit &&
typeIs(0, s64)(Query));
556 .clampScalar(0, s32, sMaxScalar)
564 return (HasSSE1 &&
typeInSet(0, {v4s32})(Query)) ||
565 (HasSSE2 &&
typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
566 (HasAVX &&
typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
567 (HasAVX512 &&
typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
569 .clampNumElements(0, v16s8, s8MaxVector)
577 unsigned SubIdx = Query.
Opcode == G_EXTRACT ? 0 : 1;
578 unsigned FullIdx = Query.
Opcode == G_EXTRACT ? 1 : 0;
583 {v2s64, v4s64}})(Query)) ||
592 {v4s64, v8s64}})(Query));
602 {v2s64, v4s64}})(Query)) ||
611 {v4s64, v8s64}})(Query));
616 .
legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
617 .widenScalarToNextPow2(0, 8)
626 G_STACKRESTORE}).lower();
635 .legalFor({s8, s16, s32, s64, p0})
636 .widenScalarToNextPow2(0, 8)
647 switch (
MI.getOpcode()) {
651 case TargetOpcode::G_BUILD_VECTOR:
652 return legalizeBuildVector(
MI,
MRI, Helper);
653 case TargetOpcode::G_FPTOUI:
654 return legalizeFPTOUI(
MI,
MRI, Helper);
655 case TargetOpcode::G_UITOFP:
656 return legalizeUITOFP(
MI,
MRI, Helper);
665 const auto &BuildVector = cast<GBuildVector>(
MI);
666 Register Dst = BuildVector.getReg(0);
667 LLT DstTy =
MRI.getType(Dst);
673 for (
unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
674 Register Source = BuildVector.getSourceReg(i);
678 CstIdxs.
emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
684 CstIdxs.
emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
688 if (getOpcodeDef<GImplicitDef>(Source,
MRI)) {
698 unsigned AddrSpace =
DL.getDefaultGlobalsAddressSpace();
708 MI.eraseFromParent();
716 auto [Dst, DstTy, Src, SrcTy] =
MI.getFirst2RegLLTs();
717 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
722 if (DstSizeInBits <= 32) {
723 auto Casted = MIRBuilder.
buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
725 MI.eraseFromParent();
736 auto [Dst, DstTy, Src, SrcTy] =
MI.getFirst2RegLLTs();
741 if (SrcTy.getSizeInBits() <= 32) {
742 auto Ext = MIRBuilder.
buildZExt(SrcTy == s32 ? s64 : s32, Src);
744 MI.eraseFromParent();
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
This file declares the targeting of the Machinelegalizer class for X86.
static Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
constexpr unsigned getScalarSizeInBits() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
This is an important class for using LLVM in a threaded context.
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 & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx)
Change the type TypeIdx to have the same scalar size as type SameSizeIdx.
LegalizeRuleSet & libcall()
The instruction is emitted as a library call.
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 & moreElementsToNextPow2(unsigned TypeIdx)
Add more elements to the vector to reach the next power of two.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
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 & 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 & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
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
unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
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.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
Helper class to build MachineInstr.
MachineInstrBuilder buildFPTOSI(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_FPTOSI Src0.
MachineInstrBuilder buildConstantPool(const DstOp &Res, unsigned Idx)
Build and insert Res = G_CONSTANT_POOL Idx.
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildSITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_SITOFP Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
MachineRegisterInfo * getMRI()
Getter for MRI.
const DataLayout & getDataLayout() const
Representation of each machine instruction.
A description of a memory reference used in the backend.
@ MOLoad
The memory access reads data.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Type * getType() const
All values are typed, get the type of this value.
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
X86LegalizerInfo(const X86Subtarget &STI, const X86TargetMachine &TM)
const X86InstrInfo * getInstrInfo() const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
LegalityPredicate typePairInSet(unsigned TypeIdx0, unsigned TypeIdx1, std::initializer_list< std::pair< LLT, LLT > > TypesInit)
True iff the given types for the given pair of type indexes is one of the specified type pairs.
LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
LegalityPredicate scalarNarrowerThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar that's narrower than the given size.
This is an optimization pass for GlobalISel generic memory operations.
std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
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...
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...
static MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.