From f4ef94a7b66f0b142ae9fca7987947cc49497060 Mon Sep 17 00:00:00 2001 From: sumesh-s-mcw Date: Tue, 4 Mar 2025 13:05:32 +0530 Subject: [PATCH 1/2] Added support for isFpClass --- .../Target/SPIRV/SPIRVInstructionSelector.cpp | 314 ++++++++++++++ llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 2 + .../CodeGen/SPIRV/llvm-intrinsics/fpclass.ll | 390 ++++++++++++++++++ 3 files changed, 706 insertions(+) create mode 100644 llvm/test/CodeGen/SPIRV/llvm-intrinsics/fpclass.ll diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index c52b67e72a88c..4e2beb29d9276 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -305,6 +305,8 @@ class SPIRVInstructionSelector : public InstructionSelector { bool selectImageWriteIntrinsic(MachineInstr &I) const; bool selectResourceGetPointer(Register &ResVReg, const SPIRVType *ResType, MachineInstr &I) const; + bool selectIsFpclass(Register ResVReg, const SPIRVType *ResType, + MachineInstr &I) const; // Utilities std::pair @@ -893,6 +895,8 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg, case TargetOpcode::G_UBSANTRAP: case TargetOpcode::DBG_LABEL: return true; + case TargetOpcode::G_IS_FPCLASS: + return selectIsFpclass(ResVReg,ResType,I); default: return false; @@ -4021,6 +4025,316 @@ bool SPIRVInstructionSelector::loadHandleBeforePosition( .constrainAllUses(TII, TRI, RBI); } +llvm::Type* getLLVMType(LLT srcLLTType, llvm::LLVMContext &context) { + if (srcLLTType.isScalar()) { + switch (srcLLTType.getSizeInBits()) { + case 32: return llvm::Type::getFloatTy(context); // float + case 64: return llvm::Type::getDoubleTy(context); // double + default: + llvm_unreachable("Unsupported scalar floating-point type!"); + } + } else if (srcLLTType.isVector()) { + unsigned numElements = srcLLTType.getNumElements(); + LLT elemType = srcLLTType.getElementType(); + + if (elemType.isScalar()) { + llvm::Type* baseType = nullptr; + switch (elemType.getSizeInBits()) { + case 32: baseType = llvm::Type::getFloatTy(context); break; + case 64: baseType = llvm::Type::getDoubleTy(context); break; + case 16: baseType = llvm::Type::getHalfTy(context); break; + default: + llvm_unreachable("Unsupported vector element type!"); + } + return llvm::VectorType::get(baseType, llvm::ElementCount::getFixed(numElements)); + } + } + + llvm_unreachable("Unsupported LLT type conversion!"); +} + +int getBitWidth(LLT srcLLTType){ + int bitWidth; + if(srcLLTType.isScalar()){ + bitWidth = srcLLTType.getSizeInBits(); + }else if(srcLLTType.isVector()){ + bitWidth = srcLLTType.getElementType().getSizeInBits(); + } + return bitWidth; +} + +bool SPIRVInstructionSelector::selectIsFpclass(Register ResVReg, const SPIRVType *ResType, MachineInstr &I) const { + MachineIRBuilder MIRBuilder(I); + //spivType creation for Creating Intermediate Registers + std::vector ResultVec; + Register srcReg = I.getOperand(1).getReg(); + SPIRVType* srcSPIRVType = GR.getSPIRVTypeForVReg(srcReg); + LLT srcLLTType = GR.getRegType(srcSPIRVType); + Register ResReg = MRI->createGenericVirtualRegister(srcLLTType); + DstOp Res(ResReg); + Type* srcLLVMType = getLLVMType(srcLLTType, GR.CurMF->getFunction().getContext()); + int bitWidth = getBitWidth(srcLLTType); + + Type *IntOpLLVMTy = IntegerType::getIntNTy(GR.CurMF->getFunction().getContext(), bitWidth); + if (srcLLVMType->isVectorTy()) + IntOpLLVMTy = FixedVectorType::get(IntOpLLVMTy, cast(srcLLVMType)->getNumElements()); + + + SPIRVType *boolType = GR.getOrCreateSPIRVBoolType(I, TII); + SPIRVType *intType = GR.getOrCreateSPIRVIntegerType(bitWidth,I,TII); + SPIRVType *ScalarInt = GR.getOrCreateSPIRVIntegerType(bitWidth,I,TII); + unsigned N = GR.getScalarOrVectorComponentCount(ResType); + if (N > 1){ + boolType = GR.getOrCreateSPIRVVectorType(boolType, N, I, TII); + intType = GR.getOrCreateSPIRVVectorType(intType, N, I, TII); + } + + //function to create constant + auto createConstant = [&](int64_t val) -> Register { + Register constant = MRI->createVirtualRegister(GR.getRegClass(ScalarInt)); + MIRBuilder.buildInstr(SPIRV::OpConstantI) + .addDef(constant) + .addUse(GR.getSPIRVTypeID(ScalarInt)) + .addImm(val); + if (srcLLVMType->isVectorTy()) { + Register compositeConstant = MRI->createVirtualRegister(GR.getRegClass(intType)); + auto MIB = MIRBuilder.buildInstr(SPIRV::OpConstantComposite) + .addDef(compositeConstant) + .addUse(GR.getSPIRVTypeID(intType)); + unsigned numElements = srcLLTType.getNumElements(); + for (unsigned i = 0; i < numElements; ++i) { + MIB.addUse(constant); + } + return compositeConstant; + } + return constant; + }; + //Type* srcLLVMType; + //checking src type to create llvm Type Creation + //srcLLVMType = (bitWidth == 32) ? Type::getFloatTy(GR.CurMF->getFunction().getContext()) : Type::getDoubleTy(GR.CurMF->getFunction().getContext()); + // llvm::FPClassTest FPClass = static_cast(I.getOperand(2).getImm()); + llvm::FPClassTest FPClass = static_cast(I.getOperand(2).getImm()); + //edge cases + if (FPClass == 0){ + // Register trueVector = createConstant(1); + // MIRBuilder.buildCopy(ResVReg, trueVector); + return true; + } + if (FPClass == fcAllFlags){ + // Register trueVector = createConstant(1); + // MIRBuilder.buildCopy(ResVReg, trueVector); + return true; + } + + + //Instruction Template + auto instructionTemplate = [&](unsigned Opcode, SPIRVType* DestType, SPIRVType* ReturnType, auto&&... args) -> Register { + Register result = MRI->createVirtualRegister(GR.getRegClass(DestType)); + auto &Instr = MIRBuilder.buildInstr(Opcode) + .addDef(result) + .addUse(GR.getSPIRVTypeID(DestType)); + + ([&](auto&& arg) __attribute__((optimize("O0"))) { + if(std::is_integral_v>) { + Instr.addImm(arg); + }else{ + Instr.addUse(arg); + } + }(args), ...); + return result; + }; + //function to check if the sign bit is set or not + //1 sign is set if 0 sign is not set + //inf && sign == 1 then -ve infinity + // inf && sign == 0 then not -ve infinity + //--------positive cases -------------// + // inf && ~sign - positive Infinity + // inf && ~sign - not positive Infinity + //sign bit test logic + Register SignBitTest = Register(0); + Register NoSignTest = Register(0); + auto GetNegPosInstTest = [&](Register TestInst, + bool IsNegative) -> Register { + Register result = MRI->createVirtualRegister(GR.getRegClass(boolType)); + if(!SignBitTest.isValid()){ + SignBitTest = MRI->createVirtualRegister(GR.getRegClass(boolType)); + MIRBuilder.buildInstr(SPIRV::OpSignBitSet) + .addDef(SignBitTest) + .addUse(GR.getSPIRVTypeID(boolType)) + .addUse(srcReg); + } + + if (IsNegative) { + MIRBuilder.buildInstr(SPIRV::OpLogicalAnd) + .addDef(result) + .addUse(GR.getSPIRVTypeID(boolType)) + .addUse(SignBitTest) + .addUse(TestInst); + return result; + } + if(!NoSignTest.isValid()){ + NoSignTest = MRI->createVirtualRegister(GR.getRegClass(boolType)); + MIRBuilder.buildInstr(SPIRV::OpLogicalNot) + .addDef(NoSignTest) + .addUse(GR.getSPIRVTypeID(boolType)) + .addUse(SignBitTest); + } + + MIRBuilder.buildInstr(SPIRV::OpLogicalAnd) + .addDef(result) + .addUse(GR.getSPIRVTypeID(boolType)) + .addUse(NoSignTest) + .addUse(TestInst); + return result; + }; + + // if (srcLLVMType->isVectorTy()) + // llvm::errs() << "is Vector Type" << "\n"; + // IntOpLLVMTy = FixedVectorType::get( + // IntOpLLVMTy, cast(srcLLVMType)->getNumElements()); + + const llvm::fltSemantics &Semantics =srcLLVMType->getScalarType()->getFltSemantics(); + APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); + APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf; + + //Mask Inversion Logic + auto GetInvertedFPClassTest = + [](const llvm::FPClassTest Test) -> llvm::FPClassTest { + llvm::FPClassTest InvertedTest = ~Test & fcAllFlags; + switch (InvertedTest) { + case fcNan: + case fcSNan: + case fcQNan: + case fcInf: + case fcPosInf: + case fcNegInf: + case fcNormal: + case fcPosNormal: + case fcNegNormal: + case fcSubnormal: + case fcPosSubnormal: + case fcNegSubnormal: + case fcZero: + case fcPosZero: + case fcNegZero: + case fcFinite: + case fcPosFinite: + case fcNegFinite: + return InvertedTest; + } + return fcNone; + }; + + //if is possible to invert then invert the test + bool IsInverted = false; + if (llvm::FPClassTest InvertedCheck = GetInvertedFPClassTest(FPClass)) { + IsInverted = true; + FPClass = InvertedCheck; + } + + auto GetInvertedTestIfNeeded = [&](Register src){ + if (!IsInverted) + return src; + Register des = MRI->createVirtualRegister(MRI->getRegClass(src)); + MIRBuilder.buildInstr(SPIRV::OpLogicalNot).addDef(des).addUse(GR.getSPIRVTypeID(boolType)).addUse(src); + return des; + }; + + //checking for IsNan + if (FPClass & fcNan) { + if (FPClass & fcSNan && FPClass & fcQNan) { + ResultVec.push_back(instructionTemplate(SPIRV::OpIsNan,boolType,boolType,srcReg)); + } else { + // isquiet(V) ==> abs(V) >= (unsigned(Inf) | quiet_bit) + APInt QNaNBitMask = APInt::getOneBitSet(bitWidth, AllOneMantissa.getActiveBits() - 1); + APInt InfWithQnanBit = Inf | QNaNBitMask; + int64_t InfWithQnanBitVal = InfWithQnanBit.getZExtValue(); + Register constInfwithQuanBit = createConstant(InfWithQnanBitVal); + Register constIntsrc = instructionTemplate(SPIRV::OpBitcast, intType, intType, srcReg); + Register TestQnan = instructionTemplate(SPIRV::OpUGreaterThanEqual, boolType, boolType, constIntsrc, constInfwithQuanBit); + if(FPClass & fcSNan){ + //fcSNan = isNan && !isQNan + Register notQnan = instructionTemplate(SPIRV::OpLogicalNot, boolType, boolType, TestQnan); + Register IsNan = instructionTemplate(SPIRV::OpIsNan, boolType, boolType, srcReg); + ResultVec.push_back(instructionTemplate(SPIRV::OpLogicalAnd, boolType, boolType, IsNan, notQnan)); + }else{ + ResultVec.push_back(TestQnan); + } + } + } + //checking for isInf + if (FPClass & fcInf) { + Register IsInf = instructionTemplate(SPIRV::OpIsInf, boolType, boolType, srcReg); + if(!((FPClass & fcPosInf)&&(FPClass & fcNegInf))){ + ResultVec.push_back(GetNegPosInstTest(IsInf, FPClass & fcNegInf)); + }else{ + ResultVec.push_back(IsInf); + } + } + //for handling is Normal + if (FPClass & fcNormal) { + Register isNormal = instructionTemplate(SPIRV::OpIsNormal, boolType, boolType, srcReg); + if(!((FPClass & fcNegNormal)&&(FPClass & fcPosNormal))){ + ResultVec.push_back(GetNegPosInstTest(isNormal, FPClass & fcNegNormal)); + }else{ + ResultVec.push_back(isNormal); + } + } + //for handling subnormal + if (FPClass & fcSubnormal) { + // issubnormal(V) ==> unsigned(abs(V) - 1) < (all mantissa bits set) + //APInt zeros = APInt::getZero(bitWidth); + int64_t AllOneMantissa_int = AllOneMantissa.getZExtValue(); + Register constAllOneMantisa = createConstant(AllOneMantissa_int); + Register constantOne = createConstant(1); + Register bitCastedsrc = instructionTemplate(SPIRV::OpBitcast, intType, intType, srcReg); + Register bitCastedSrcMinusOne = instructionTemplate(SPIRV::OpISubS, intType, intType, bitCastedsrc, constantOne); + Register testIsSubNormal = instructionTemplate(SPIRV::OpULessThan, boolType, boolType, bitCastedSrcMinusOne, constAllOneMantisa); + if(!((FPClass & fcNegSubnormal)&&(FPClass & fcPosSubnormal))){ + ResultVec.push_back(GetNegPosInstTest(testIsSubNormal, FPClass & fcNegSubnormal)); + }else{ + ResultVec.push_back(testIsSubNormal); + } + } + //check if the number is Zero + if(FPClass & fcZero){ + auto SetUpCMPToZero = [&](Register BitCastToInt, + bool IsPositive) -> Register { + APInt ZeroInt = APInt::getZero(bitWidth); + Register constantZero; + if (!IsPositive) { + ZeroInt.setSignBit(); + } + constantZero = createConstant(ZeroInt.getZExtValue()); + Register isEqual = instructionTemplate(SPIRV::OpIEqual, boolType, boolType, constantZero,BitCastToInt); + return isEqual; + }; + + Register bitCastedsrc = instructionTemplate(SPIRV::OpBitcast, intType, intType , srcReg); + if (FPClass & fcPosZero && FPClass & fcNegZero) { + APInt ZeroInt = APInt::getZero(bitWidth); + APInt MaskToClearSignBit = APInt::getSignedMaxValue(bitWidth); + Register MaskToClearSignBitConst = createConstant(MaskToClearSignBit.getZExtValue()); + Register zeroConst = createConstant(ZeroInt.getZExtValue()); + Register bitwiseAndRes = instructionTemplate(SPIRV::OpBitwiseAndS, intType, intType , MaskToClearSignBitConst, bitCastedsrc); + ResultVec.push_back(instructionTemplate(SPIRV::OpIEqual, boolType, boolType, bitwiseAndRes, zeroConst)); + }else if (FPClass & fcPosZero) { + ResultVec.push_back(SetUpCMPToZero(bitCastedsrc, true)); + } else { + ResultVec.push_back(SetUpCMPToZero(bitCastedsrc, false)); + } + } + Register Result = ResultVec[0]; + if(ResultVec.size() > 1){ + for (size_t I = 1; I < ResultVec.size(); I++) { + Result = instructionTemplate(SPIRV::OpLogicalOr, boolType, boolType, Result , ResultVec[I]); + } + } + MIRBuilder.buildCopy(ResVReg, Result); + return true; +} + + namespace llvm { InstructionSelector * createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp index daa8ea52ffe03..b3a77032d2b10 100644 --- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp @@ -354,6 +354,8 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) { getActionDefinitionsBuilder(G_FCOPYSIGN) .legalForCartesianProduct(allFloatScalarsAndVectors, allFloatScalarsAndVectors); + getActionDefinitionsBuilder(G_IS_FPCLASS) + .legalForCartesianProduct(allBoolScalarsAndVectors, allFloatScalarsAndVectors); getActionDefinitionsBuilder(G_FPOWI).legalForCartesianProduct( allFloatScalarsAndVectors, allIntScalarsAndVectors); diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fpclass.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fpclass.ll new file mode 100644 index 0000000000000..12315bf693e90 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fpclass.ll @@ -0,0 +1,390 @@ +; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV + +; CHECK-SPIRV-DAG: %[[#Int32Ty:]] = OpTypeInt 32 0 +; CHECK-SPIRV-DAG: %[[#Int64Ty:]] = OpTypeInt 64 0 +; CHECK-SPIRV-DAG: %[[#Int16Ty:]] = OpTypeInt 16 0 +; CHECK-SPIRV-DAG: %[[#BoolTy:]] = OpTypeBool +; CHECK-SPIRV-DAG: %[[#VecBoolTy:]] = OpTypeVector %[[#BoolTy]] 2 +; CHECK-SPIRV-DAG: %[[#Int32VecTy:]] = OpTypeVector %[[#Int32Ty]] 2 +; CHECK-SPIRV-DAG: %[[#Int16VecTy:]] = OpTypeVector %[[#Int16Ty]] 2 +; CHECK-SPIRV-DAG: %[[#DoubleTy:]] = OpTypeFloat 64 +; CHECK-SPIRV-DAG: %[[#QNanBitConst:]] = OpConstant %[[#Int32Ty]] 2143289344 +; CHECK-SPIRV-DAG: %[[#MantissaConst:]] = OpConstant %[[#Int32Ty]] 8388607 +; CHECK-SPIRV-DAG: %[[#ZeroConst:]] = OpConstant %[[#Int32Ty]] 0 +; CHECK-SPIRV-DAG: %[[#MaskToClearSignBit:]] = OpConstant %[[#Int32Ty]] 2147483647 +; CHECK-SPIRV-DAG: %[[#NegatedZeroConst:]] = OpConstant %[[#Int32Ty]] 2147483648 +; CHECK-SPIRV-DAG: %[[#MantissaConst16:]] = OpConstant %[[#Int16Ty]] 1023 +; CHECK-SPIRV-DAG: %[[#ZeroConst64:]] = OpConstant %[[#Int64Ty]] 0 +; CHECK-SPIRV-DAG: %[[#OneConst16:]] = OpConstant %[[#Int16Ty]] 1 +; CHECK-SPIRV-DAG: %[[#OneConstant:]] = OpConstant %[[#Int64Ty]] 1 +; CHECK-SPIRV-DAG: %[[#OneConstVec16:]] = OpConstantComposite %[[#Int16VecTy]] %[[#OneConst16]] %[[#OneConst16]] +; CHECK-SPIRV-DAG: %[[#QNanBitConst64:]] = OpConstant %[[#Int64Ty]] 9221120237041090560 +; CHECK-SPIRV-DAG: %[[#MantissaConst64:]] = OpConstant %[[#Int64Ty]] 4503599627370495 +; CHECK-SPIRV-DAG: %[[#QNanBitConst16:]] = OpConstant %[[#Int16Ty]] 32256 +; CHECK-SPIRV-DAG: %[[#QNanBitConstVec16:]] = OpConstantComposite %[[#Int16VecTy:]] %[[#QNanBitConst16]] %[[#QNanBitConst16]] +; CHECK-SPIRV-DAG: %[[#MantissaConstVec16:]] = OpConstantComposite %[[#Int16VecTy:]] %[[#MantissaConst16]] %[[#MantissaConst16]] +; CHECK-SPIRV-DAG: %[[#ZeroConst16:]] = OpConstant %[[#Int16Ty]] 0 +; CHECK-SPIRV-DAG: %[[#zeroConst16Vec2:]] = OpConstantComposite %[[#Int16VecTy]] %[[#ZeroConst16]] %[[#ZeroConst16]] + + +; ConstantTrue [[#BoolTy]] [[#True:]] +; ConstantFalse [[#BoolTy]] [[#False:]] + +; CHECK-SPIRV-DAG: OpName %[[#NanFunc:]] "test_class_isnan_f32" +; CHECK-SPIRV-DAG: OpName %[[#VecNanFunc:]] "test_class_isnan_v2f32" +; CHECK-SPIRV-DAG: OpName %[[#SNanFunc:]] "test_class_issnan_f32" +; CHECK-SPIRV-DAG: OpName %[[#QNanFunc:]] "test_class_isqnan_f32" +; CHECK-SPIRV-DAG: OpName %[[#InfFunc:]] "test_class_is_inf_f32" +; CHECK-SPIRV-DAG: OpName %[[#InfVecFunc:]] "test_class_is_inf_v2f32" +; CHECK-SPIRV-DAG: OpName %[[#PosInfFunc:]] "test_class_is_pinf_f32" +; CHECK-SPIRV-DAG: OpName %[[#PosInfVecFunc:]] "test_class_is_pinf_v2f32" +; CHECK-SPIRV-DAG: OpName %[[#NegInfFunc:]] "test_class_is_ninf_f32" +; CHECK-SPIRV-DAG: OpName %[[#NegInfVecFunc:]] "test_class_is_ninf_v2f32" +; CHECK-SPIRV-DAG: OpName %[[#NormFunc:]] "test_class_is_normal" +; CHECK-SPIRV-DAG: OpName %[[#PosNormFunc:]] "test_constant_class_pnormal" +; CHECK-SPIRV-DAG: OpName %[[#NegNormFunc:]] "test_constant_class_nnormal" +; CHECK-SPIRV-DAG: OpName %[[#SubnormFunc:]] "test_class_subnormal" +; CHECK-SPIRV-DAG: OpName %[[#PosSubnormFunc:]] "test_class_possubnormal" +; CHECK-SPIRV-DAG: OpName %[[#NegSubnormFunc:]] "test_class_negsubnormal" +; CHECK-SPIRV-DAG: OpName %[[#ZeroFunc:]] "test_class_zero" +; CHECK-SPIRV-DAG: OpName %[[#PosZeroFunc:]] "test_class_poszero" +; CHECK-SPIRV-DAG: OpName %[[#NegZeroFunc:]] "test_class_negzero" +; CHECK-SPIRV-DAG: OpName %[[#NegInfOrNanFunc:]] "test_class_is_ninf_or_nan_f32" +; CHECK-SPIRV-DAG: OpName %[[#ComplexFunc1:]] "test_class_neginf_posnormal_negsubnormal_poszero_snan_f64" +; CHECK-SPIRV-DAG: OpName %[[#ComplexFunc2:]] "test_class_neginf_posnormal_negsubnormal_poszero_snan_v2f16" + + +; ModuleID = 'fpclass.bc' +source_filename = "fpclass.ll" +target triple = "spir64-unknown-unknown" + + + +; check for nan +define i1 @test_class_isnan_f32(float %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: %[[#]] = OpLabel +; CHECK-SPIRV-NEXT: %[[#IsNan:]] = OpIsNan %[[#BoolTy]] %[[#val]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#IsNan]] + %val = call i1 @llvm.is.fpclass.f32(float %x, i32 3) + ret i1 %val +} + +define <2 x i1> @test_class_isnan_v2f32(<2 x float> %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsNan:]] = OpIsNan %[[#VecBoolTy]] %[[#val]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#IsNan]] + %val = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 3) + ret <2 x i1> %val +} + +; check for snan +define i1 @test_class_issnan_f32(float %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#BitCast:]] = OpBitcast %[[#Int32Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#GECheck:]] = OpUGreaterThanEqual %[[#]] %[[#BitCast]] %[[#QNanBitConst]] +; CHECK-SPIRV-NEXT: %[[#Not:]] = OpLogicalNot %[[#]] %[[#GECheck]] +; CHECK-SPIRV-NEXT: %[[#IsNan:]] = OpIsNan %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#]] %[[#IsNan]] %[[#Not]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call i1 @llvm.is.fpclass.f32(float %x, i32 1) + ret i1 %val +} + +; check for qnan +define i1 @test_class_isqnan_f32(float %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#BitCast:]] = OpBitcast %[[#Int32Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#GECheck:]] = OpUGreaterThanEqual %[[#]] %[[#BitCast]] %[[#QNanBitConst]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#GECheck]] + %val = call i1 @llvm.is.fpclass.f32(float %x, i32 2) + ret i1 %val +} + +; check for inf +define i1 @test_class_is_inf_f32(float %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#IsInf]] + %val = call i1 @llvm.is.fpclass.f32(float %x, i32 516) + ret i1 %val +} + +define <2 x i1> @test_class_is_inf_v2f32(<2 x float> %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#VecBoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#IsInf]] + %val = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 516) + ret <2 x i1> %val +} + +; check for pos inf +define i1 @test_class_is_pinf_f32(float %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Not:]] = OpLogicalNot %[[#BoolTy]] %[[#Sign]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#BoolTy]] %[[#Not]] %[[#IsInf]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call i1 @llvm.is.fpclass.f32(float %x, i32 512) + ret i1 %val +} + +define <2 x i1> @test_class_is_pinf_v2f32(<2 x float> %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#VecBoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#VecBoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Not:]] = OpLogicalNot %[[#VecBoolTy]] %[[#Sign]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#VecBoolTy]] %[[#Not]] %[[#IsInf]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 512) + ret <2 x i1> %val +} + +; check for neg inf +define i1 @test_class_is_ninf_f32(float %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#BoolTy]] %[[#Sign]] %[[#IsInf]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call i1 @llvm.is.fpclass.f32(float %x, i32 4) + ret i1 %val +} + +define <2 x i1> @test_class_is_ninf_v2f32(<2 x float> %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#VecBoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#VecBoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#VecBoolTy]] %[[#Sign]] %[[#IsInf]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 4) + ret <2 x i1> %val +} + +; check for normal +define i1 @test_class_is_normal(float %x) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsNormal:]] = OpIsNormal %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#IsNormal]] + %val = call i1 @llvm.is.fpclass.f32(float %x, i32 264) + ret i1 %val +} + +; check for pos normal +define i1 @test_constant_class_pnormal() { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsNormal:]] = OpIsNormal %[[#BoolTy]] %[[#]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#BoolTy]] %[[#]] +; CHECK-SPIRV-NEXT: %[[#Not:]] = OpLogicalNot %[[#BoolTy]] %[[#Sign]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#BoolTy]] %[[#Not]] %[[#IsNormal]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call i1 @llvm.is.fpclass.f64(double 1.000000e+00, i32 256) + ret i1 %val +} +; check for neg normal +define i1 @test_constant_class_nnormal() { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#IsNormal:]] = OpIsNormal %[[#BoolTy]] %[[#]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#BoolTy]] %[[#]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#BoolTy]] %[[#Sign]] %[[#IsNormal]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call i1 @llvm.is.fpclass.f64(double 1.000000e+00, i32 8) + ret i1 %val +} + +; check for subnormal +define i1 @test_class_subnormal(float %arg) { +; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#BitCast:]] = OpBitcast %[[#Int32Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sub:]] = OpISub %[[#Int32Ty]] %[[#BitCast]] %[[#OneConstant:]] +; CHECK-SPIRV-NEXT: %[[#Less:]] = OpULessThan %[[#BoolTy]] %[[#Sub]] %[[#MantissaConst:]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#Less]] + %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 144) + ret i1 %val +} + +; check for pos subnormal +define i1 @test_class_possubnormal(float %arg) { +;; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#BitCast:]] = OpBitcast %[[#Int32Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sub:]] = OpISub %[[#Int32Ty]] %[[#BitCast]] %[[#OneConstant:]] +; CHECK-SPIRV-NEXT: %[[#Less:]] = OpULessThan %[[#BoolTy]] %[[#Sub]] %[[#MantissaConst:]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Not:]] = OpLogicalNot %[[#BoolTy]] %[[#Sign]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#BoolTy]] %[[#Not]] %[[#Less]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 128) + ret i1 %val +} + +; check for neg subnormal +define i1 @test_class_negsubnormal(float %arg) { +;; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel +; CHECK-SPIRV-NEXT: %[[#BitCast:]] = OpBitcast %[[#Int32Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sub:]] = OpISub %[[#Int32Ty]] %[[#BitCast]] %[[#OneConstant:]] +; CHECK-SPIRV-NEXT: %[[#Less:]] = OpULessThan %[[#BoolTy]] %[[#Sub]] %[[#MantissaConst:]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#BoolTy]] %[[#Sign]] %[[#Less]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#And]] + %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 16) + ret i1 %val +} + +; check for zero +define i1 @test_class_zero(float %arg) { +;; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel + +; CHECK-SPIRV-NEXT: %[[#BitCast:]] = OpBitcast %[[#Int32Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#BitwiseAndRes:]] = OpBitwiseAnd %[[#Int32Ty]] %[[#MaskToClearSignBit]] %[[#BitCast]] +; CHECK-SPIRV-NEXT: %[[#EqualPos:]] = OpIEqual %[[#BoolTy]] %[[#BitwiseAndRes]] %[[#ZeroConst]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#EqualPos]] + %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 96) + ret i1 %val +} + +; check for pos zero +define i1 @test_class_poszero(float %arg) { +;; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel + +; CHECK-SPIRV-NEXT: %[[#BitCast:]] = OpBitcast %[[#Int32Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Equal:]] = OpIEqual %[[#BoolTy]] %[[#ZeroConst]] %[[#BitCast]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#Equal]] + %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 64) + ret i1 %val +} + +; check for neg zero +define i1 @test_class_negzero(float %arg) { +;; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel + +; CHECK-SPIRV-NEXT: %[[#BitCast:]] = OpBitcast %[[#Int32Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Equal:]] = OpIEqual %[[#BoolTy]] %[[#NegatedZeroConst]] %[[#BitCast]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#Equal]] + %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 32) + ret i1 %val +} + +; check for neg inf or nan +define i1 @test_class_is_ninf_or_nan_f32(float %x) { +;; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel + +; CHECK-SPIRV-NEXT: %[[#IsNan:]] = OpIsNan %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And:]] = OpLogicalAnd %[[#BoolTy]] %[[#Sign]] %[[#IsInf]] +; CHECK-SPIRV-NEXT: %[[#Or:]] = OpLogicalOr %[[#BoolTy]] %[[#IsNan]] %[[#And]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#Or]] + %val = call i1 @llvm.is.fpclass.f32(float %x, i32 7) + ret i1 %val +} + +; check for neg inf, pos normal, neg subnormal pos zero and snan scalar +define i1 @test_class_neginf_posnormal_negsubnormal_poszero_snan_f64(double %arg) { +;; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel + +; CHECK-SPIRV-NEXT: %[[#BitCast1:]] = OpBitcast %[[#Int64Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#GECheck:]] = OpUGreaterThanEqual %[[#BoolTy]] %[[#BitCast1]] %[[#QNanBitConst64]] +; CHECK-SPIRV-NEXT: %[[#Not1:]] = OpLogicalNot %[[#BoolTy]] %[[#GECheck]] +; CHECK-SPIRV-NEXT: %[[#IsNan:]] = OpIsNan %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And1:]] = OpLogicalAnd %[[#BoolTy]] %[[#IsNan]] %[[#Not1]] +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And2:]] = OpLogicalAnd %[[#BoolTy]] %[[#Sign]] %[[#IsInf]] +; CHECK-SPIRV-NEXT: %[[#IsNormal:]] = OpIsNormal %[[#BoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Not2:]] = OpLogicalNot %[[#BoolTy]] %[[#Sign]] +; CHECK-SPIRV-NEXT: %[[#And3:]] = OpLogicalAnd %[[#BoolTy]] %[[#Not2]] %[[#IsNormal]] +; CHECK-SPIRV-NEXT: %[[#BitCast2:]] = OpBitcast %[[#Int64Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sub:]] = OpISub %[[#Int64Ty]] %[[#BitCast2]] %[[#]] +; CHECK-SPIRV-NEXT: %[[#Less:]] = OpULessThan %[[#BoolTy]] %[[#Sub]] %[[#MantissaConst64]] +; CHECK-SPIRV-NEXT: %[[#And4:]] = OpLogicalAnd %[[#BoolTy]] %[[#Sign]] %[[#Less]] +; CHECK-SPIRV-NEXT: %[[#BitCast3:]] = OpBitcast %[[#Int64Ty]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Equal:]] = OpIEqual %[[#BoolTy]] %[[#ZeroConst64]] %[[#BitCast3]] +; CHECK-SPIRV-NEXT: %[[#Or1:]] = OpLogicalOr %[[#BoolTy]] %[[#And1]] %[[#And2]] + +; CHECK-SPIRV-NEXT: %[[#Or2:]] = OpLogicalOr %[[#BoolTy]] %[[#Or1]] %[[#And3]] +; CHECK-SPIRV-NEXT: %[[#Or3:]] = OpLogicalOr %[[#BoolTy]] %[[#Or2]] %[[#And4]] +; CHECK-SPIRV-NEXT: %[[#Or4:]] = OpLogicalOr %[[#BoolTy]] %[[#Or3]] %[[#Equal]] +; CHECK-SPIRV-NEXT: ReturnValue %[[#Or4]] + %val = call i1 @llvm.is.fpclass.f64(double %arg, i32 341) + ret i1 %val +} + +; check for neg inf, pos normal, neg subnormal pos zero and snan vector +define <2 x i1> @test_class_neginf_posnormal_negsubnormal_poszero_snan_v2f16(<2 x half> %arg) { +;; CHECK-SPIRV: %[[#]] = OpFunction %[[#]] None %[[#]] +; CHECK-SPIRV-NEXT: %[[#Val:]] = OpFunctionParameter %[[#]] +; CHECK-SPIRV-NEXT: OpLabel + +; CHECK-SPIRV-NEXT: %[[#BitCast1:]] = OpBitcast %[[#Int16VecTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#GECheck:]] = OpUGreaterThanEqual %[[#VecBoolTy]] %[[#BitCast1]] %[[#QNanBitConstVec16]] +; CHECK-SPIRV-NEXT: %[[#Not1:]] = OpLogicalNot %[[#VecBoolTy]] %[[#GECheck]] +; CHECK-SPIRV-NEXT: %[[#IsNan:]] = OpIsNan %[[#VecBoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And1:]] = OpLogicalAnd %[[#VecBoolTy]] %[[#IsNan]] %[[#Not1]] +; CHECK-SPIRV-NEXT: %[[#IsInf:]] = OpIsInf %[[#VecBoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sign:]] = OpSignBitSet %[[#VecBoolTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#And2:]] = OpLogicalAnd %[[#VecBoolTy]] %[[#Sign]] %[[#IsInf]] +; CHECK-SPIRV-NEXT: %[[#IsNormal:]] = OpIsNormal %[[#VecBoolTy]] %[[#Val]] + +; CHECK-SPIRV-NEXT: %[[#Not2:]] = OpLogicalNot %[[#VecBoolTy]] %[[#Sign]] +; CHECK-SPIRV-NEXT: %[[#And3:]] = OpLogicalAnd %[[#VecBoolTy]] %[[#Not2]] %[[#IsNormal]] +; CHECK-SPIRV-NEXT: %[[#BitCast2:]] = OpBitcast %[[#Int16VecTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Sub:]] = OpISub %[[#Int16VecTy]] %[[#BitCast2]] %[[#OneConstVec16]] +; CHECK-SPIRV-NEXT: %[[#Less:]] = OpULessThan %[[#VecBoolTy]] %[[#Sub]] %[[#MantissaConstVec16]] +; CHECK-SPIRV-NEXT: %[[#And4:]] = OpLogicalAnd %[[#VecBoolTy]] %[[#Sign]] %[[#Less]] +; CHECK-SPIRV-NEXT: %[[#BitCast3:]] = OpBitcast %[[#Int16VecTy]] %[[#Val]] +; CHECK-SPIRV-NEXT: %[[#Equal:]] = OpIEqual %[[#VecBoolTy]] %[[#]] %[[#BitCast3]] +; CHECK-SPIRV-NEXT: %[[#Or1:]] = OpLogicalOr %[[#VecBoolTy]] %[[#And1]] %[[#And2]] +; CHECK-SPIRV-NEXT: %[[#Or2:]] = OpLogicalOr %[[#VecBoolTy]] %[[#Or1]] %[[#And3]] +; CHECK-SPIRV-NEXT: %[[#Or3:]] = OpLogicalOr %[[#VecBoolTy]] %[[#Or2]] %[[#And4]] +; CHECK-SPIRV-NEXT: %[[#Or4:]] = OpLogicalOr %[[#VecBoolTy]] %[[#Or3]] %[[#Equal]] +; CHECK-SPIRV-NEXT: OpReturnValue %[[#Or4]] + %val = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> %arg, i32 341) + ret <2 x i1> %val +} + + + +declare i1 @llvm.is.fpclass.f32(float, i32 immarg) +declare i1 @llvm.is.fpclass.f64(double, i32 immarg) +declare <2 x i1> @llvm.is.fpclass.v2f32(<2 x float>, i32 immarg) +declare <2 x i1> @llvm.is.fpclass.v2f16(<2 x half>, i32 immarg) From 6ec845bdb31a52561e7d55bcfdb33439cef190f4 Mon Sep 17 00:00:00 2001 From: sumesh-s-mcw Date: Tue, 4 Mar 2025 17:57:50 +0530 Subject: [PATCH 2/2] patch --- .../Target/SPIRV/SPIRVInstructionSelector.cpp | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 4e2beb29d9276..adff57ca77c9a 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -34,8 +34,15 @@ #include "llvm/IR/IntrinsicsSPIRV.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" - #define DEBUG_TYPE "spirv-isel" +#ifdef _MSC_VER + #define NO_OPTIMIZE __pragma(optimize("", off)) +#elif defined(__GNUC__) || defined(__clang__) + #define NO_OPTIMIZE __attribute__((optimize("O0"))) +#else + #define NO_OPTIMIZE +#endif + using namespace llvm; namespace CL = SPIRV::OpenCLExtInst; @@ -4127,22 +4134,25 @@ bool SPIRVInstructionSelector::selectIsFpclass(Register ResVReg, const SPIRVType } - //Instruction Template + // Instruction Template auto instructionTemplate = [&](unsigned Opcode, SPIRVType* DestType, SPIRVType* ReturnType, auto&&... args) -> Register { Register result = MRI->createVirtualRegister(GR.getRegClass(DestType)); auto &Instr = MIRBuilder.buildInstr(Opcode) .addDef(result) .addUse(GR.getSPIRVTypeID(DestType)); - - ([&](auto&& arg) __attribute__((optimize("O0"))) { - if(std::is_integral_v>) { - Instr.addImm(arg); - }else{ - Instr.addUse(arg); - } - }(args), ...); + + (void)std::initializer_list{ + ([&](auto&& arg) NO_OPTIMIZE { + if constexpr (std::is_integral_v>) { + Instr.addImm(arg); + } else { + Instr.addUse(arg); + } + }(args), 0)... + }; return result; }; + //function to check if the sign bit is set or not //1 sign is set if 0 sign is not set //inf && sign == 1 then -ve infinity @@ -4298,7 +4308,7 @@ bool SPIRVInstructionSelector::selectIsFpclass(Register ResVReg, const SPIRVType } //check if the number is Zero if(FPClass & fcZero){ - auto SetUpCMPToZero = [&](Register BitCastToInt, + auto SetUpCMPToZero = [&, bitWidth](Register BitCastToInt, bool IsPositive) -> Register { APInt ZeroInt = APInt::getZero(bitWidth); Register constantZero;