Skip to content

Commit

Permalink
Add emulation of {s/u)_(add/sub)_sat intrinsics if needed
Browse files Browse the repository at this point in the history
While the translator was built around OpenCL - other targets that
support SPIR-V and don't support OpenCL might use it.

This patch adds --spirv-use-ocl-math-for-llvm-intrinsic option to
control whether we should translate them as math intrinsics to OpenCL ext math
instructions or emulate. Default is true aka translate as math
instructions.

I don't really want to end up implementing Quake's sqrt algorithm, but
it's a possible scenario as well.

Plans are:
1. merge existing --spirv-replace-fmuladd-with-ocl-mad with the new
   option;
2. optionally introduce InstCombine pass in reverse translation.

Signed-off-by: Sidorov, Dmitry <dmitry.sidorov@intel.com>
  • Loading branch information
MrSidims committed Aug 25, 2023
1 parent f5ab11d commit 84d448e
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 59 deletions.
13 changes: 13 additions & 0 deletions include/LLVMSPIRVOpts.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
134 changes: 120 additions & 14 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<SPIRVValue *> 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<SPIRVValue *> 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<VectorType>(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
Expand Down
4 changes: 4 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,10 @@ class SPIRVModule {
return TranslationOpts.shouldReplaceLLVMFmulAddWithOpenCLMad();
}

bool shouldUseOpenCLExtInstructionsForLLVMIntrinsic() const noexcept {
return TranslationOpts.shouldUseOpenCLExtInstructionsForLLVMIntrinsic();
}

bool shouldPreserveOCLKernelArgTypeMetadataThroughString() const noexcept {
return TranslationOpts
.shouldPreserveOCLKernelArgTypeMetadataThroughString();
Expand Down
139 changes: 94 additions & 45 deletions test/llvm-intrinsics/add_sub.sat.ll
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -9,87 +19,126 @@
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:
%0 = call i32 @llvm.uadd.sat.i32(i32 %a, i32 %b)
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:
%0 = call i32 @llvm.usub.sat.i32(i32 %a, i32 %b)
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:
%0 = call i32 @llvm.sadd.sat.i32(i32 %a, i32 %b)
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:
%0 = call i32 @llvm.ssub.sat.i32(i32 %a, i32 %b)
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:
%0 = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %a, <4 x i32> %b)
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);
Expand Down
16 changes: 16 additions & 0 deletions tools/llvm-spirv/llvm-spirv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@ static cl::opt<SPIRV::BuiltinFormat> SPIRVBuiltinFormat(
clEnumValN(SPIRV::BuiltinFormat::Global, "global",
"Use globals to represent SPIR-V builtin variables")));

static cl::opt<bool> 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)
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 84d448e

Please sign in to comment.