diff --git a/include/LLVMSPIRVOpts.h b/include/LLVMSPIRVOpts.h index 33cf162098..4b96679b7a 100644 --- a/include/LLVMSPIRVOpts.h +++ b/include/LLVMSPIRVOpts.h @@ -193,6 +193,14 @@ class TranslatorOpts { ReplaceLLVMFmulAddWithOpenCLMad = Value; } + void setUseOpenCLExtInstructionsForLLVMIntrinsic(bool Value) noexcept { + UseOpenCLExtInstructionsForLLVMIntrinsic = Value; + } + + bool shouldUseOpenCLExtInstructionsForLLVMIntrinsic() const noexcept { + return UseOpenCLExtInstructionsForLLVMIntrinsic; + } + bool shouldPreserveOCLKernelArgTypeMetadataThroughString() const noexcept { return PreserveOCLKernelArgTypeMetadataThroughString; } @@ -243,6 +251,11 @@ class TranslatorOpts { // extended instruction set or with a simple fmul + fadd bool ReplaceLLVMFmulAddWithOpenCLMad = true; + // Controls whether llvm math intrinsics should be replaced with instructions + // from OpenCL extended instruction set or emulated by native SPIR-V + // instructions + bool UseOpenCLExtInstructionsForLLVMIntrinsic = true; + // Add a workaround to preserve OpenCL kernel_arg_type and // kernel_arg_type_qual metadata through OpString bool PreserveOCLKernelArgTypeMetadataThroughString = false; diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 90b8c4e2c4..a75c5e3ea8 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -3860,21 +3860,127 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II, case Intrinsic::usub_sat: case Intrinsic::sadd_sat: case Intrinsic::ssub_sat: { - SPIRVWord ExtOp; - if (IID == Intrinsic::uadd_sat) - ExtOp = OpenCLLIB::UAdd_sat; - else if (IID == Intrinsic::usub_sat) - ExtOp = OpenCLLIB::USub_sat; - else if (IID == Intrinsic::sadd_sat) - ExtOp = OpenCLLIB::SAdd_sat; - else - ExtOp = OpenCLLIB::SSub_sat; + if (BM->shouldUseOpenCLExtInstructionsForLLVMIntrinsic()) { + SPIRVWord ExtOp; + if (IID == Intrinsic::uadd_sat) + ExtOp = OpenCLLIB::UAdd_sat; + else if (IID == Intrinsic::usub_sat) + ExtOp = OpenCLLIB::USub_sat; + else if (IID == Intrinsic::sadd_sat) + ExtOp = OpenCLLIB::SAdd_sat; + else + ExtOp = OpenCLLIB::SSub_sat; - SPIRVType *Ty = transType(II->getType()); - std::vector Operands = {transValue(II->getArgOperand(0), BB), - transValue(II->getArgOperand(1), BB)}; - return BM->addExtInst(Ty, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, - std::move(Operands), BB); + SPIRVType *Ty = transType(II->getType()); + std::vector Operands = { + transValue(II->getArgOperand(0), BB), + transValue(II->getArgOperand(1), BB)}; + return BM->addExtInst(Ty, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, + std::move(Operands), BB); + } + Type *LLVMTy = II->getType(); + SPIRVType *Ty = transType(LLVMTy); + Type *BoolTy = IntegerType::getInt1Ty(M->getContext()); + if (auto *VecTy = dyn_cast(LLVMTy)) + BoolTy = VectorType::get(BoolTy, VecTy->getElementCount()); + SPIRVType *SPVBoolTy = transType(BoolTy); + SPIRVValue *FirstArgVal = transValue(II->getArgOperand(0), BB); + SPIRVValue *SecondArgVal = transValue(II->getArgOperand(1), BB); + if (IID == Intrinsic::uadd_sat) { + // uadd.sat(a, b) -> res = a + b, (res > a) ? res : MAX + SPIRVValue *Max = + transValue(Constant::getAllOnesValue(II->getType()), BB); + SPIRVValue *Add = + BM->addBinaryInst(OpIAdd, Ty, FirstArgVal, SecondArgVal, BB); + SPIRVValue *Cmp = BM->addCmpInst(OpUGreaterThan, SPVBoolTy, + Add, FirstArgVal, BB); + return BM->addSelectInst(Cmp, Add, Max, BB); + } + if (IID == Intrinsic::usub_sat) { + // usub.sat(a, b) -> (a > b) ? a - b : 0 + SPIRVValue *Sub = + BM->addBinaryInst(OpISub, Ty, FirstArgVal, SecondArgVal, BB); + SPIRVValue *Cmp = BM->addCmpInst(OpUGreaterThan, SPVBoolTy, + FirstArgVal, SecondArgVal, BB); + SPIRVValue *Zero = transValue(Constant::getNullValue(II->getType()), BB); + return BM->addSelectInst(Cmp, Sub, Zero, BB); + } + + uint64_t NumBits = LLVMTy->getScalarSizeInBits(); + SPIRVValue *Zero = transValue(Constant::getNullValue(II->getType()), BB); + SPIRVValue *Max = + transValue(Constant::getIntegerValue( + LLVMTy, APInt::getSignedMaxValue(NumBits)), BB); + SPIRVValue *Min = + transValue(Constant::getIntegerValue( + LLVMTy, APInt::getSignedMinValue(NumBits)), BB); + SPIRVValue *IsPositive = + BM->addCmpInst(OpSGreaterThan, SPVBoolTy, SecondArgVal, Zero, BB); + SPIRVValue *IsNegative = + BM->addCmpInst(OpSLessThan, SPVBoolTy, SecondArgVal, Zero, BB); + if (IID == Intrinsic::sadd_sat) { + // sadd.sat(a, b) -> if (b > 0) && a > MAX - b => overflow -> MAX + // -> else if (b < 0) && a < MIN - b => overflow -> MIN + // -> else a + b + // There two ways to represent such sequence in IR: + // 1. Via 2 branch instructions plus 'phi' instruction; + // 2. Via set of select instructions. + // The later was chosed because of the following consideration: + // speculative branch prediction will most likely consider 'if' statements + // here as always false falling through to 'a + b', and reversing it will + // case performance degradation. + SPIRVValue *Add = + BM->addBinaryInst(OpIAdd, Ty, FirstArgVal, SecondArgVal, BB); + + // check if (b > 0) && a > MAX - b condition + SPIRVValue *MaxSubB = + BM->addBinaryInst(OpISub, Ty, Max, SecondArgVal, BB); + SPIRVValue *CanPosOverflow = BM->addCmpInst(OpSGreaterThan, SPVBoolTy, + FirstArgVal, MaxSubB, BB); + SPIRVValue *PosOverflow = BM->addInstTemplate( + OpLogicalAnd, {CanPosOverflow->getId(), IsPositive->getId()}, + BB, SPVBoolTy); + + // check if (b < 0) && MIN - b > a condition + SPIRVValue *MinSubB = + BM->addBinaryInst(OpISub, Ty, Min, SecondArgVal, BB); + SPIRVValue *CanNegOverflow = BM->addCmpInst(OpSGreaterThan, SPVBoolTy, + MinSubB, FirstArgVal, BB); + SPIRVValue *NegOverflow = BM->addInstTemplate( + OpLogicalAnd, {CanNegOverflow->getId(), IsNegative->getId()}, + BB, SPVBoolTy); + + // do selects + SPIRVValue *FirstSelect = BM->addSelectInst(PosOverflow, Max, Add, BB); + return BM->addSelectInst(NegOverflow, Min, FirstSelect, BB); + } + // ssub.sat(a, b) -> if (b > 0) && a < MIN + b => overflow -> MIN + // -> else if (b < 0) && a > MAX + b => overflow -> MAX + // -> else a - b + // still represent via 2 selects + assert(IID == Intrinsic::ssub_sat && "Expected llvm.ssub_sat"); + SPIRVValue *Sub = + BM->addBinaryInst(OpISub, Ty, FirstArgVal, SecondArgVal, BB); + + // check if (b > 0) && MIN + b > a + SPIRVValue *MinAddB = BM->addBinaryInst(OpIAdd, Ty, Min, SecondArgVal, BB); + SPIRVValue *CanNegOverflow = BM->addCmpInst(OpSGreaterThan, SPVBoolTy, + MinAddB, FirstArgVal, BB); + SPIRVValue *NegOverflow = BM->addInstTemplate( + OpLogicalAnd, {CanNegOverflow->getId(), IsPositive->getId()}, + BB, SPVBoolTy); + + // check if (b < 0) && a > MAX + b + SPIRVValue *MaxAddB = BM->addBinaryInst(OpIAdd, Ty, Max, SecondArgVal, BB); + SPIRVValue *CanPosOverflow = BM->addCmpInst(OpSGreaterThan, SPVBoolTy, + FirstArgVal, MaxAddB, BB); + SPIRVValue *PosOverflow = BM->addInstTemplate( + OpLogicalAnd, {CanPosOverflow->getId(), IsNegative->getId()}, + BB, SPVBoolTy); + + // do selects + SPIRVValue *FirstSelect = BM->addSelectInst(PosOverflow, Max, Sub, BB); + return BM->addSelectInst(NegOverflow, Min, FirstSelect, BB); } case Intrinsic::memset: { // Generally there is no direct mapping of memset to SPIR-V. But it turns diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.h b/lib/SPIRV/libSPIRV/SPIRVModule.h index ce60776293..abaa5726bd 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.h +++ b/lib/SPIRV/libSPIRV/SPIRVModule.h @@ -534,6 +534,10 @@ class SPIRVModule { return TranslationOpts.shouldReplaceLLVMFmulAddWithOpenCLMad(); } + bool shouldUseOpenCLExtInstructionsForLLVMIntrinsic() const noexcept { + return TranslationOpts.shouldUseOpenCLExtInstructionsForLLVMIntrinsic(); + } + bool shouldPreserveOCLKernelArgTypeMetadataThroughString() const noexcept { return TranslationOpts .shouldPreserveOCLKernelArgTypeMetadataThroughString(); diff --git a/test/llvm-intrinsics/add_sub.sat.ll b/test/llvm-intrinsics/add_sub.sat.ll index 4b17e5e92a..585e0b3476 100644 --- a/test/llvm-intrinsics/add_sub.sat.ll +++ b/test/llvm-intrinsics/add_sub.sat.ll @@ -1,6 +1,16 @@ ; RUN: llvm-as < %s -o %t.bc ; RUN: llvm-spirv %t.bc -o %t.spv -; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s --check-prefixes=COMMON,OPENCL +; RUN: spirv-val %t.spv + +; RUN: llvm-as < %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-use-ocl-math-for-llvm-intrinsic=true -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s --check-prefixes=COMMON,OPENCL +; RUN: spirv-val %t.spv + +; RUN: llvm-as < %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-use-ocl-math-for-llvm-intrinsic=false -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s --check-prefixes=COMMON,EMULATION ; RUN: spirv-val %t.spv ; Test checks that saturation addition and substraction llvm intrinsics @@ -9,17 +19,25 @@ target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" target triple = "spir64-unknown-unknown" -; CHECK: ExtInstImport [[ext:[0-9]+]] "OpenCL.std" +; COMMON: ExtInstImport [[ext:[0-9]+]] "OpenCL.std" + +; COMMON: Name [[test_uadd:[0-9]+]] "test_uadd" +; COMMON: Name [[test_usub:[0-9]+]] "test_usub" +; COMMON: Name [[test_sadd:[0-9]+]] "test_sadd" +; COMMON: Name [[test_ssub:[0-9]+]] "test_ssub" +; COMMON: Name [[test_vectors:[0-9]+]] "test_vectors" -; CHECK: Name [[test_uadd:[0-9]+]] "test_uadd" -; CHECK: Name [[test_usub:[0-9]+]] "test_usub" -; CHECK: Name [[test_sadd:[0-9]+]] "test_sadd" -; CHECK: Name [[test_ssub:[0-9]+]] "test_ssub" -; CHECK: Name [[test_vectors:[0-9]+]] "test_vectors" +; COMMON-DAG: TypeInt [[int:[0-9]+]] 32 0 +; COMMON-DAG: TypeVoid [[void:[0-9]+]] +; COMMON-DAG: TypeVector [[vector:[0-9]+]] [[int]] 4 -; CHECK-DAG: TypeInt [[int:[0-9]+]] 32 0 -; CHECK-DAG: TypeVoid [[void:[0-9]+]] -; CHECK: TypeVector [[vector:[0-9]+]] [[int]] 4 +; EMULATION-DAG: TypeBool [[bool:[0-9]+]] +; EMULATION-DAG: TypeVector [[vector_bool:[0-9]+]] [[bool]] 4 +; EMULATION-DAG: Constant [[int]] [[uint_max:[0-9]+]] 4294967295 +; EMULATION-DAG: Constant [[int]] [[zero:[0-9]+]] 0 +; EMULATION-DAG: Constant [[int]] [[int_max:[0-9]+]] 2147483647 +; EMULATION-DAG: Constant [[int]] [[int_min:[0-9]+]] 2147483648 +; EMULATION-DAG: ConstantComposite [[vector]] [[vector_uint_max:[0-9]+]] [[uint_max]] [[uint_max]] [[uint_max]] [[uint_max]] define spir_func void @test_uadd(i32 %a, i32 %b) { entry: @@ -27,13 +45,16 @@ entry: ret void } -; CHECK: Function [[void]] [[test_uadd]] -; CHECK-NEXT: FunctionParameter [[int]] [[lhs:[0-9]+]] -; CHECK-NEXT: FunctionParameter [[int]] [[rhs:[0-9]+]] -; CHECK-EMPTY: -; CHECK-NEXT: Label -; CHECK-NEXT: ExtInst [[int]] {{[0-9]+}} [[ext]] u_add_sat [[lhs]] [[rhs]] -; CHECK-NEXT: Return +; COMMON: Function [[void]] [[test_uadd]] +; COMMON-NEXT: FunctionParameter [[int]] [[lhs:[0-9]+]] +; COMMON-NEXT: FunctionParameter [[int]] [[rhs:[0-9]+]] +; COMMON-EMPTY: +; COMMON-NEXT: Label +; OPENCL-NEXT: ExtInst [[int]] {{[0-9]+}} [[ext]] u_add_sat [[lhs]] [[rhs]] +; EMULATION-NEXT: IAdd [[int]] [[add:[0-9]+]] [[lhs]] [[rhs]] +; EMULATION-NEXT: UGreaterThan [[bool]] [[greater:[0-9]+]] [[add]] [[lhs]] +; EMULATION-NEXT: Select [[int]] {{[0-9]+}} [[greater]] [[add]] [[uint_max]] +; COMMON-NEXT: Return define spir_func void @test_usub(i32 %a, i32 %b) { entry: @@ -41,13 +62,16 @@ entry: ret void } -; CHECK: Function [[void]] [[test_usub]] -; CHECK-NEXT: FunctionParameter [[int]] [[lhs:[0-9]+]] -; CHECK-NEXT: FunctionParameter [[int]] [[rhs:[0-9]+]] -; CHECK-EMPTY: -; CHECK-NEXT: Label -; CHECK-NEXT: ExtInst [[int]] {{[0-9]+}} [[ext]] u_sub_sat [[lhs]] [[rhs]] -; CHECK-NEXT: Return +; COMMON: Function [[void]] [[test_usub]] +; COMMON-NEXT: FunctionParameter [[int]] [[lhs:[0-9]+]] +; COMMON-NEXT: FunctionParameter [[int]] [[rhs:[0-9]+]] +; COMMON-EMPTY: +; COMMON-NEXT: Label +; OPENCL-NEXT: ExtInst [[int]] {{[0-9]+}} [[ext]] u_sub_sat [[lhs]] [[rhs]] +; EMULATION-NEXT: ISub [[int]] [[sub:[0-9]+]] [[lhs]] [[rhs]] +; EMULATION-NEXT: UGreaterThan [[bool]] [[greater:[0-9]+]] [[lhs]] [[rhs]] +; EMULATION-NEXT: Select [[int]] {{[0-9]+}} [[greater]] [[sub]] [[zero]] +; COMMON-NEXT: Return define spir_func void @test_sadd(i32 %a, i32 %b) { entry: @@ -55,13 +79,24 @@ entry: ret void } -; CHECK: Function [[void]] [[test_sadd]] -; CHECK-NEXT: FunctionParameter [[int]] [[lhs:[0-9]+]] -; CHECK-NEXT: FunctionParameter [[int]] [[rhs:[0-9]+]] -; CHECK-EMPTY: -; CHECK-NEXT: Label -; CHECK-NEXT: ExtInst [[int]] {{[0-9]+}} [[ext]] s_add_sat [[lhs]] [[rhs]] -; CHECK-NEXT: Return +; COMMON: Function [[void]] [[test_sadd]] +; COMMON-NEXT: FunctionParameter [[int]] [[lhs:[0-9]+]] +; COMMON-NEXT: FunctionParameter [[int]] [[rhs:[0-9]+]] +; COMMON-EMPTY: +; COMMON-NEXT: Label +; OPENCL-NEXT: ExtInst [[int]] {{[0-9]+}} [[ext]] s_add_sat [[lhs]] [[rhs]] +; EMULATION-NEXT: SGreaterThan [[bool]] [[greater1:[0-9]+]] [[rhs]] [[zero]] +; EMULATION-NEXT: SLessThan [[bool]] [[less:[0-9]+]] [[rhs]] [[zero]] +; EMULATION-NEXT: IAdd [[int]] [[add:[0-9]+]] [[lhs]] [[rhs]] +; EMULATION-NEXT: ISub [[int]] [[sub1:[0-9]+]] [[int_max]] [[rhs]] +; EMULATION-NEXT: SGreaterThan [[bool]] [[greater2:[0-9]+]] [[lhs]] [[sub1]] +; EMULATION-NEXT: LogicalAnd [[bool]] [[and1:[0-9]+]] [[greater2]] [[greater1]] +; EMULATION-NEXT: ISub [[int]] [[sub2:[0-9]+]] [[int_min]] [[rhs]] +; EMULATION-NEXT: SGreaterThan [[bool]] [[greater3:[0-9]+]] [[sub2]] [[lhs]] +; EMULATION-NEXT: LogicalAnd [[bool]] [[and2:[0-9]+]] [[greater3]] [[less]] +; EMULATION-NEXT: Select [[int]] [[select:[0-9]+]] [[and1]] [[int_max]] [[add]] +; EMULATION-NEXT: Select [[int]] {{[0-9]+}} [[and2]] [[int_min]] [[select]] +; COMMON-NEXT: Return define spir_func void @test_ssub(i32 %a, i32 %b) { entry: @@ -69,13 +104,24 @@ entry: ret void } -; CHECK: Function [[void]] [[test_ssub]] -; CHECK-NEXT: FunctionParameter [[int]] [[lhs:[0-9]+]] -; CHECK-NEXT: FunctionParameter [[int]] [[rhs:[0-9]+]] -; CHECK-EMPTY: -; CHECK-NEXT: Label -; CHECK-NEXT: ExtInst [[int]] {{[0-9]+}} [[ext]] s_sub_sat [[lhs]] [[rhs]] -; CHECK-NEXT: Return +; COMMON: Function [[void]] [[test_ssub]] +; COMMON-NEXT: FunctionParameter [[int]] [[lhs:[0-9]+]] +; COMMON-NEXT: FunctionParameter [[int]] [[rhs:[0-9]+]] +; COMMON-EMPTY: +; COMMON-NEXT: Label +; OPENCL-NEXT: ExtInst [[int]] {{[0-9]+}} [[ext]] s_sub_sat [[lhs]] [[rhs]] +; EMULATION-NEXT: SGreaterThan [[bool]] [[greater1:[0-9]+]] [[rhs]] [[zero]] +; EMULATION-NEXT: SLessThan [[bool]] [[less:[0-9]+]] [[rhs]] [[zero]] +; EMULATION-NEXT: ISub [[int]] [[sub1:[0-9]+]] [[lhs]] [[rhs]] +; EMULATION-NEXT: IAdd [[int]] [[add1:[0-9]+]] [[int_min]] [[rhs]] +; EMULATION-NEXT: SGreaterThan [[bool]] [[greater2:[0-9]+]] [[add1]] [[lhs]] +; EMULATION-NEXT: LogicalAnd [[bool]] [[and1:[0-9]+]] [[greater2]] [[greater1]] +; EMULATION-NEXT: IAdd [[int]] [[add2:[0-9]+]] [[int_max]] [[rhs]] +; EMULATION-NEXT: SGreaterThan [[bool]] [[greater3:[0-9]+]] [[lhs]] [[add2]] +; EMULATION-NEXT: LogicalAnd [[bool]] [[and2:[0-9]+]] [[greater3]] [[less]] +; EMULATION-NEXT: Select [[int]] [[select:[0-9]+]] [[and2]] [[int_max]] [[sub1]] +; EMULATION-NEXT: Select [[int]] {{[0-9]+}} [[and1]] [[int_min]] [[select]] +; COMMON-NEXT: Return define spir_func void @test_vectors(<4 x i32> %a, <4 x i32> %b) { entry: @@ -83,13 +129,16 @@ entry: ret void } -; CHECK: Function [[void]] [[test_vectors]] -; CHECK-NEXT: FunctionParameter [[vector]] [[lhs:[0-9]+]] -; CHECK-NEXT: FunctionParameter [[vector]] [[rhs:[0-9]+]] -; CHECK-EMPTY: -; CHECK-NEXT: Label -; CHECK-NEXT: ExtInst [[vector]] {{[0-9]+}} [[ext]] u_add_sat [[lhs]] [[rhs]] -; CHECK-NEXT: Return +; COMMON: Function [[void]] [[test_vectors]] +; COMMON-NEXT: FunctionParameter [[vector]] [[lhs:[0-9]+]] +; COMMON-NEXT: FunctionParameter [[vector]] [[rhs:[0-9]+]] +; COMMON-EMPTY: +; COMMON-NEXT: Label +; OPENCL-NEXT: ExtInst [[vector]] {{[0-9]+}} [[ext]] u_add_sat [[lhs]] [[rhs]] +; EMULATION-NEXT: IAdd [[vector]] [[add:[0-9]+]] [[lhs]] [[rhs]] +; EMULATION-NEXT: UGreaterThan [[vector_bool]] [[greater:[0-9]+]] [[add]] [[lhs]] +; EMULATION-NEXT: Select [[vector]] {{[0-9]+}} [[greater]] [[add]] [[vector_uint_max]] +; COMMON-NEXT: Return declare i32 @llvm.uadd.sat.i32(i32, i32); declare i32 @llvm.usub.sat.i32(i32, i32); diff --git a/tools/llvm-spirv/llvm-spirv.cpp b/tools/llvm-spirv/llvm-spirv.cpp index cecf8333de..5c89bbcfeb 100644 --- a/tools/llvm-spirv/llvm-spirv.cpp +++ b/tools/llvm-spirv/llvm-spirv.cpp @@ -258,6 +258,12 @@ static cl::opt SPIRVBuiltinFormat( clEnumValN(SPIRV::BuiltinFormat::Global, "global", "Use globals to represent SPIR-V builtin variables"))); +static cl::opt SPIRVUseOpenCLExtInstructionsForLLVMIntrinsic( + "spirv-use-ocl-math-for-llvm-intrinsic", cl::init(true), + cl::desc("Allow to use OpenCL.ExtendedInstructionSet.100 to translate " + "LLVM math intrinsics. Otherwise use emulation for these " + "intrinsics)")); + static std::string removeExt(const std::string &FileName) { size_t Pos = FileName.find_last_of("."); if (Pos != std::string::npos) @@ -757,6 +763,16 @@ int main(int Ac, char **Av) { } } + if (SPIRVUseOpenCLExtInstructionsForLLVMIntrinsic.getNumOccurrences() != 0) { + if (IsReverse) { + errs() << "Note: --spirv-use-ocl-math-for-llvm-intrinsic option ignored " + "as it only affects translation from LLVM IR to SPIR-V"; + } else { + Opts.setUseOpenCLExtInstructionsForLLVMIntrinsic( + SPIRVUseOpenCLExtInstructionsForLLVMIntrinsic); + } + } + if (SPIRVAllowExtraDIExpressions.getNumOccurrences() != 0) { Opts.setAllowExtraDIExpressionsEnabled(SPIRVAllowExtraDIExpressions); }