28 return [IsExtendedInts, TypeIdx](
const LegalityQuery &Query) {
29 const LLT Ty = Query.Types[TypeIdx];
30 return IsExtendedInts && Ty.isValid() && Ty.isScalar();
76 const unsigned PSize = ST.getPointerSize();
92 auto allPtrsScalarsAndVectors = {
93 p0, p1, p2, p3, p4, p5, p6, p7, p8,
94 p10, p11, p12, s1, s8, s16, s32, s64, v2s1,
95 v2s8, v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32, v3s64,
96 v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16, v8s32,
97 v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
99 auto allVectors = {v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8,
100 v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32,
101 v4s64, v8s1, v8s8, v8s16, v8s32, v8s64, v16s1,
102 v16s8, v16s16, v16s32, v16s64};
104 auto allScalarsAndVectors = {
105 s1, s8, s16, s32, s64, v2s1, v2s8, v2s16, v2s32, v2s64,
106 v3s1, v3s8, v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32, v4s64,
107 v8s1, v8s8, v8s16, v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
109 auto allIntScalarsAndVectors = {s8, s16, s32, s64, v2s8, v2s16,
110 v2s32, v2s64, v3s8, v3s16, v3s32, v3s64,
111 v4s8, v4s16, v4s32, v4s64, v8s8, v8s16,
112 v8s32, v8s64, v16s8, v16s16, v16s32, v16s64};
114 auto allBoolScalarsAndVectors = {s1, v2s1, v3s1, v4s1, v8s1, v16s1};
116 auto allIntScalars = {s8, s16, s32, s64};
118 auto allFloatScalars = {s16, s32, s64};
120 auto allFloatScalarsAndVectors = {
121 s16, s32, s64, v2s16, v2s32, v2s64, v3s16, v3s32, v3s64,
122 v4s16, v4s32, v4s64, v8s16, v8s32, v8s64, v16s16, v16s32, v16s64};
124 auto allFloatAndIntScalarsAndPtrs = {s8, s16, s32, s64, p0, p1, p2, p3,
125 p4, p5, p6, p7, p8, p10, p11, p12};
127 auto allPtrs = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p10, p11, p12};
129 bool IsExtendedInts =
131 SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers) ||
132 ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
133 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
134 auto extendedScalarsAndVectors =
136 const LLT Ty = Query.Types[0];
137 return IsExtendedInts && Ty.isValid() && !Ty.isPointerOrPointerVector();
139 auto extendedScalarsAndVectorsProduct = [IsExtendedInts](
141 const LLT Ty1 = Query.Types[0], Ty2 = Query.Types[1];
142 return IsExtendedInts && Ty1.
isValid() && Ty2.isValid() &&
145 auto extendedPtrsScalarsAndVectors =
147 const LLT Ty = Query.Types[0];
148 return IsExtendedInts && Ty.isValid();
158 {G_BUILD_VECTOR, G_SHUFFLE_VECTOR, G_SPLAT_VECTOR})
163 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX,
164 G_VECREDUCE_ADD, G_VECREDUCE_MUL, G_VECREDUCE_FMUL, G_VECREDUCE_FMIN,
165 G_VECREDUCE_FMAX, G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM,
166 G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
167 .legalFor(allVectors)
191 G_BITREVERSE, G_SADDSAT, G_UADDSAT, G_SSUBSAT,
192 G_USUBSAT, G_SCMP, G_UCMP})
193 .legalFor(allIntScalarsAndVectors)
194 .
legalIf(extendedScalarsAndVectors);
197 .legalFor(allFloatScalarsAndVectors);
203 .legalForCartesianProduct(allIntScalarsAndVectors,
204 allFloatScalarsAndVectors);
207 .legalForCartesianProduct(allIntScalarsAndVectors,
208 allFloatScalarsAndVectors);
211 .legalForCartesianProduct(allFloatScalarsAndVectors,
212 allScalarsAndVectors);
216 .
legalIf(extendedScalarsAndVectorsProduct);
220 .legalForCartesianProduct(allScalarsAndVectors)
221 .
legalIf(extendedScalarsAndVectorsProduct);
225 .
legalIf(extendedPtrsScalarsAndVectors);
229 typeInSet(1, allPtrsScalarsAndVectors)));
252 typeInSet(1, allPtrsScalarsAndVectors)));
256 typeInSet(1, allFloatScalarsAndVectors)));
259 G_ATOMICRMW_MAX, G_ATOMICRMW_MIN,
260 G_ATOMICRMW_SUB, G_ATOMICRMW_XOR,
261 G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
262 .legalForCartesianProduct(allIntScalars, allPtrs);
265 {G_ATOMICRMW_FADD, G_ATOMICRMW_FSUB, G_ATOMICRMW_FMIN, G_ATOMICRMW_FMAX})
266 .legalForCartesianProduct(allFloatScalars, allPtrs);
276 {G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_UMULO, G_SMULO})
280 .legalForCartesianProduct(allFloatScalarsAndVectors,
281 allIntScalarsAndVectors);
285 .legalForCartesianProduct(allFloatScalarsAndVectors);
294 allFloatScalarsAndVectors, {s32, v2s32, v3s32, v4s32, v8s32, v16s32});
329 G_INTRINSIC_ROUNDEVEN})
330 .legalFor(allFloatScalarsAndVectors);
334 allFloatScalarsAndVectors);
337 allFloatScalarsAndVectors, allIntScalarsAndVectors);
339 if (ST.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
341 {G_CTTZ, G_CTTZ_ZERO_UNDEF, G_CTLZ, G_CTLZ_ZERO_UNDEF})
342 .legalForCartesianProduct(allIntScalarsAndVectors,
343 allIntScalarsAndVectors);
352 verify(*ST.getInstrInfo());
359 Register ConvReg =
MRI.createGenericVirtualRegister(ConvTy);
372 switch (
MI.getOpcode()) {
376 case TargetOpcode::G_IS_FPCLASS:
377 return legalizeIsFPClass(Helper,
MI, LocObserver);
378 case TargetOpcode::G_ICMP: {
379 assert(GR->getSPIRVTypeForVReg(
MI.getOperand(0).getReg()));
380 auto &Op0 =
MI.getOperand(2);
381 auto &Op1 =
MI.getOperand(3);
386 if ((!ST->canDirectlyComparePointers() ||
388 MRI.getType(Reg0).isPointer() &&
MRI.getType(Reg1).isPointer()) {
391 ST->getPointerSize());
392 SPIRVType *SpirvTy = GR->getOrCreateSPIRVType(
393 LLVMTy, Helper.
MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
405bool SPIRVLegalizerInfo::legalizeIsFPClass(
408 auto [DstReg, DstTy, SrcReg, SrcTy] =
MI.getFirst2RegLLTs();
412 auto &MF = MIRBuilder.
getMF();
417 if (DstTy.isVector())
420 LLVMDstTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
423 unsigned BitSize = SrcTy.getScalarSizeInBits();
428 if (SrcTy.isVector()) {
429 IntTy =
LLT::vector(SrcTy.getElementCount(), IntTy);
433 LLVMIntTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
437 LLT DstTyCopy = DstTy;
442 LLT MITy =
MRI.getType(
MI.getReg(0));
443 assert((MITy == IntTy || MITy == DstTyCopy) &&
444 "Unexpected LLT type while lowering G_IS_FPCLASS");
445 auto *SPVTy = MITy == IntTy ? SPIRVIntTy : SPIRVDstTy;
451 const auto buildSPIRVConstant = [&](LLT Ty,
auto &&
C) -> MachineInstrBuilder {
453 return assignSPIRVTy(MIRBuilder.buildConstant(Ty,
C));
455 assert((Ty == IntTy || Ty == DstTyCopy) &&
456 "Unexpected LLT type while lowering constant for G_IS_FPCLASS");
457 SPIRVType *VecEltTy = GR->getOrCreateSPIRVType(
458 (Ty == IntTy ? LLVMIntTy : LLVMDstTy)->getScalarType(), MIRBuilder,
459 SPIRV::AccessQualifier::ReadWrite,
461 GR->assignSPIRVTypeToVReg(VecEltTy, ScalarC.getReg(0), MF);
462 return assignSPIRVTy(MIRBuilder.buildSplatBuildVector(Ty, ScalarC));
466 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 0));
467 MI.eraseFromParent();
471 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 1));
472 MI.eraseFromParent();
480 Register ResVReg =
MRI.createGenericVirtualRegister(IntTy);
481 MRI.setRegClass(ResVReg, GR->getRegClass(SPIRVIntTy));
482 GR->assignSPIRVTypeToVReg(SPIRVIntTy, ResVReg, Helper.
MIRBuilder.
getMF());
483 auto AsInt = MIRBuilder.buildInstr(SPIRV::OpBitcast)
485 .addUse(GR->getSPIRVTypeID(SPIRVIntTy))
487 AsInt = assignSPIRVTy(std::move(AsInt));
499 auto SignBitC = buildSPIRVConstant(IntTy, SignBit);
500 auto ValueMaskC = buildSPIRVConstant(IntTy, ValueMask);
501 auto InfC = buildSPIRVConstant(IntTy, Inf);
502 auto ExpMaskC = buildSPIRVConstant(IntTy, ExpMask);
503 auto ZeroC = buildSPIRVConstant(IntTy, 0);
505 auto Abs = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC));
506 auto Sign = assignSPIRVTy(
509 auto Res = buildSPIRVConstant(DstTy, 0);
511 const auto appendToRes = [&](MachineInstrBuilder &&ToAppend) {
513 MIRBuilder.buildOr(DstTyCopy, Res, assignSPIRVTy(std::move(ToAppend))));
526 Mask &= ~fcPosFinite;
530 DstTy, Abs, ExpMaskC));
531 appendToRes(MIRBuilder.buildAnd(DstTy, Cmp, Sign));
532 Mask &= ~fcNegFinite;
540 auto ExpBits = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC));
543 Mask &= ~PartialCheck;
552 else if (PartialCheck ==
fcZero)
564 auto OneC = buildSPIRVConstant(IntTy, 1);
565 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
566 auto SubnormalRes = assignSPIRVTy(
568 buildSPIRVConstant(IntTy, AllOneMantissa)));
570 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
571 appendToRes(std::move(SubnormalRes));
578 else if (PartialCheck ==
fcInf)
583 auto NegInfC = buildSPIRVConstant(IntTy, NegInf);
590 auto InfWithQnanBitC =
591 buildSPIRVConstant(IntTy, std::move(Inf) | QNaNBitMask);
592 if (PartialCheck ==
fcNan) {
596 }
else if (PartialCheck ==
fcQNan) {
603 auto IsNan = assignSPIRVTy(
605 auto IsNotQnan = assignSPIRVTy(MIRBuilder.buildICmp(
607 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
614 APInt ExpLSB = ExpMask & ~(ExpMask.
shl(1));
615 auto ExpMinusOne = assignSPIRVTy(
616 MIRBuilder.buildSub(IntTy, Abs, buildSPIRVConstant(IntTy, ExpLSB)));
617 APInt MaxExpMinusOne = std::move(ExpMask) - ExpLSB;
618 auto NormalRes = assignSPIRVTy(
620 buildSPIRVConstant(IntTy, MaxExpMinusOne)));
622 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
624 auto PosSign = assignSPIRVTy(MIRBuilder.buildXor(
625 DstTy, Sign, buildSPIRVConstant(DstTy, InversionMask)));
626 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
628 appendToRes(std::move(NormalRes));
631 MIRBuilder.buildCopy(DstReg, Res);
632 MI.eraseFromParent();
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Replace)
This file declares the MachineIRBuilder class.
Promote Memory to Register
const SmallVectorImpl< MachineOperand > & Cond
static Register convertPtrToInt(Register Reg, LLT ConvTy, SPIRVType *SpvType, LegalizerHelper &Helper, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)
LegalityPredicate typeOfExtendedScalars(unsigned TypeIdx, bool IsExtendedInts)
APInt bitcastToAPInt() const
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
unsigned getActiveBits() const
Compute the number of active bits in the value.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
APInt shl(unsigned shiftAmt) const
Left-shift function.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_ULT
unsigned less than
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
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.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
constexpr LLT getScalarType() const
LLVM_ABI void computeTables()
Compute any ancillary tables needed to quickly decide how an operation should be handled.
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & custom()
Unconditionally custom lower.
LegalizeRuleSet & alwaysLegal()
LegalizeRuleSet & customIf(LegalityPredicate Predicate)
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
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, const MachineFunction &MF)
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
const TargetRegisterClass * getRegClass(SPIRVType *SpvType) const
SPIRVLegalizerInfo(const SPIRVSubtarget &ST)
bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override
Called for instructions with the Custom LegalizationAction.
SPIRVGlobalRegistry * getSPIRVGlobalRegistry() const
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
LLVM_ABI LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
Predicate all(Predicate P0, Predicate P1)
True iff P0 and P1 are true.
Invariant opcodes: All instruction sets have these as their low opcodes.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
std::function< bool(const LegalityQuery &)> LegalityPredicate
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
const MachineInstr SPIRVType
const std::set< unsigned > & getTypeFoldingSupportedOpcodes()
The LegalityQuery object bundles together all the information that's needed to decide whether a given...