From 9d8d0329fe41d7fd1b859d1988b8c89d7cce0a7e Mon Sep 17 00:00:00 2001 From: Mochalova Anastasiya Date: Tue, 9 Feb 2021 12:17:22 +0300 Subject: [PATCH] [Backport] Add support for some llvm FP intrinsic in llvm-spirv (#902) Signed-off-by: gejin --- lib/SPIRV/SPIRVUtil.cpp | 52 +++ lib/SPIRV/SPIRVWriter.cpp | 150 ++++++++ test/fp-intrinsics.ll | 333 ++++++++++++++++++ ...lvm.fma.ll => llvm-unhandled-intrinsic.ll} | 10 +- test/transcoding/AllowIntrinsics.ll | 15 +- 5 files changed, 546 insertions(+), 14 deletions(-) create mode 100644 test/fp-intrinsics.ll rename test/negative/{llvm.fma.ll => llvm-unhandled-intrinsic.ll} (75%) diff --git a/lib/SPIRV/SPIRVUtil.cpp b/lib/SPIRV/SPIRVUtil.cpp index 1d1be61c6a..133ab1c679 100644 --- a/lib/SPIRV/SPIRVUtil.cpp +++ b/lib/SPIRV/SPIRVUtil.cpp @@ -1536,6 +1536,58 @@ bool hasLoopMetadata(const Module *M) { return false; } +// Returns true if type(s) and number of elements (if vector) is valid +bool checkTypeForSPIRVExtendedInstLowering(IntrinsicInst *II, SPIRVModule *BM) { + switch (II->getIntrinsicID()) { + case Intrinsic::ceil: + case Intrinsic::copysign: + case Intrinsic::cos: + case Intrinsic::exp: + case Intrinsic::exp2: + case Intrinsic::fabs: + case Intrinsic::floor: + case Intrinsic::fma: + case Intrinsic::log: + case Intrinsic::log10: + case Intrinsic::log2: + case Intrinsic::maximum: + case Intrinsic::maxnum: + case Intrinsic::minimum: + case Intrinsic::minnum: + case Intrinsic::nearbyint: + case Intrinsic::pow: + case Intrinsic::powi: + case Intrinsic::rint: + case Intrinsic::round: + case Intrinsic::sin: + case Intrinsic::sqrt: + case Intrinsic::trunc: { + // Although some of the intrinsics above take multiple arguments, it is + // sufficient to check arg 0 because the LLVM Verifier will have checked + // that all floating point operands have the same type and the second + // argument of powi is i32. + Type *Ty = II->getType(); + if (II->getArgOperand(0)->getType() != Ty) + return false; + int NumElems = 1; + if (auto *VecTy = dyn_cast(Ty)) { + NumElems = VecTy->getNumElements(); + Ty = VecTy->getElementType(); + } + if ((!Ty->isFloatTy() && !Ty->isDoubleTy() && !Ty->isHalfTy()) || + ((NumElems > 4) && (NumElems != 8) && (NumElems != 16))) { + BM->getErrorLog().checkError(false, SPIRVEC_InvalidFunctionCall, + II->getCalledOperand()->getName().str(), "", + __FILE__, __LINE__); + return false; + } + break; + } + default: + break; + } + return true; +} } // namespace SPIRV namespace { diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 3395f08748..19cdc289e6 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -1690,8 +1690,32 @@ void addIntelFPGADecorationsForStructMember( bool LLVMToSPIRV::isKnownIntrinsic(Intrinsic::ID Id) { // Known intrinsics usually do not need translation of their declaration switch (Id) { + case Intrinsic::assume: case Intrinsic::bitreverse: + case Intrinsic::ceil: + case Intrinsic::copysign: + case Intrinsic::cos: + case Intrinsic::exp: + case Intrinsic::exp2: + case Intrinsic::fabs: + case Intrinsic::floor: + case Intrinsic::fma: + case Intrinsic::log: + case Intrinsic::log10: + case Intrinsic::log2: + case Intrinsic::maximum: + case Intrinsic::maxnum: + case Intrinsic::minimum: + case Intrinsic::minnum: + case Intrinsic::nearbyint: + case Intrinsic::pow: + case Intrinsic::powi: + case Intrinsic::rint: + case Intrinsic::round: + case Intrinsic::sin: case Intrinsic::sqrt: + case Intrinsic::trunc: + case Intrinsic::ctpop: case Intrinsic::ctlz: case Intrinsic::cttz: case Intrinsic::fmuladd: @@ -1714,6 +1738,67 @@ bool LLVMToSPIRV::isKnownIntrinsic(Intrinsic::ID Id) { } } +static SPIRVWord getBuiltinIdForIntrinsic(Intrinsic::ID IID) { + switch (IID) { + // Note: In some cases the semantics of the OpenCL builtin are not identical + // to the semantics of the corresponding LLVM IR intrinsic. The LLVM + // intrinsics handled here assume the default floating point environment + // (no unmasked exceptions, round-to-nearest-ties-even rounding mode) + // and assume that the operations have no side effects (FP status flags + // aren't maintained), so the OpenCL builtin behavior should be + // acceptable. + case Intrinsic::ceil: + return OpenCLLIB::Ceil; + case Intrinsic::copysign: + return OpenCLLIB::Copysign; + case Intrinsic::cos: + return OpenCLLIB::Cos; + case Intrinsic::exp: + return OpenCLLIB::Exp; + case Intrinsic::exp2: + return OpenCLLIB::Exp2; + case Intrinsic::fabs: + return OpenCLLIB::Fabs; + case Intrinsic::floor: + return OpenCLLIB::Floor; + case Intrinsic::fma: + return OpenCLLIB::Fma; + case Intrinsic::log: + return OpenCLLIB::Log; + case Intrinsic::log10: + return OpenCLLIB::Log10; + case Intrinsic::log2: + return OpenCLLIB::Log2; + case Intrinsic::maximum: + return OpenCLLIB::Fmax; + case Intrinsic::maxnum: + return OpenCLLIB::Fmax; + case Intrinsic::minimum: + return OpenCLLIB::Fmin; + case Intrinsic::minnum: + return OpenCLLIB::Fmin; + case Intrinsic::nearbyint: + return OpenCLLIB::Rint; + case Intrinsic::pow: + return OpenCLLIB::Pow; + case Intrinsic::powi: + return OpenCLLIB::Pown; + case Intrinsic::rint: + return OpenCLLIB::Rint; + case Intrinsic::round: + return OpenCLLIB::Round; + case Intrinsic::sin: + return OpenCLLIB::Sin; + case Intrinsic::sqrt: + return OpenCLLIB::Sqrt; + case Intrinsic::trunc: + return OpenCLLIB::Trunc; + default: + assert(false && "Builtin ID requested for Unhandled intrinsic!"); + return 0; + } +} + SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, SPIRVBasicBlock *BB) { auto GetMemoryAccess = [](MemIntrinsic *MI) -> std::vector { @@ -1756,6 +1841,57 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, SPIRVValue *Op = transValue(II->getArgOperand(0), BB); return BM->addUnaryInst(OpBitReverse, Ty, Op, BB); } + + // Unary FP intrinsic + case Intrinsic::ceil: + case Intrinsic::cos: + case Intrinsic::exp: + case Intrinsic::exp2: + case Intrinsic::fabs: + case Intrinsic::floor: + case Intrinsic::log: + case Intrinsic::log10: + case Intrinsic::log2: + case Intrinsic::nearbyint: + case Intrinsic::rint: + case Intrinsic::round: + case Intrinsic::sin: + case Intrinsic::sqrt: + case Intrinsic::trunc: { + SPIRVWord ExtOp = getBuiltinIdForIntrinsic(II->getIntrinsicID()); + SPIRVType *STy = transType(II->getType()); + std::vector Ops(1, transValue(II->getArgOperand(0), BB)); + return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops, + BB); + } + // Binary FP intrinsics + case Intrinsic::copysign: + case Intrinsic::pow: + case Intrinsic::powi: + case Intrinsic::maximum: + case Intrinsic::maxnum: + case Intrinsic::minimum: + case Intrinsic::minnum: { + SPIRVWord ExtOp = getBuiltinIdForIntrinsic(II->getIntrinsicID()); + SPIRVType *STy = transType(II->getType()); + std::vector Ops{transValue(II->getArgOperand(0), BB), + transValue(II->getArgOperand(1), BB)}; + return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops, + BB); + } + case Intrinsic::fma: { + SPIRVWord ExtOp = OpenCLLIB::Fma; + SPIRVType *STy = transType(II->getType()); + std::vector Ops{transValue(II->getArgOperand(0), BB), + transValue(II->getArgOperand(1), BB), + transValue(II->getArgOperand(2), BB)}; + return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops, + BB); + } + case Intrinsic::ctpop: { + return BM->addUnaryInst(OpBitCount, transType(II->getType()), + transValue(II->getArgOperand(0), BB), BB); + } case Intrinsic::ctlz: case Intrinsic::cttz: { SPIRVWord ExtOp = II->getIntrinsicID() == Intrinsic::ctlz ? OpenCLLIB::Clz @@ -1802,6 +1938,20 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, return BM->addBinaryInst(OpFAdd, Ty, Mul, transValue(II->getArgOperand(2), BB), BB); } + case Intrinsic::usub_sat: { + // usub.sat(a, b) -> (a > b) ? a - b : 0 + SPIRVType *Ty = transType(II->getType()); + Type *BoolTy = IntegerType::getInt1Ty(M->getContext()); + SPIRVValue *FirstArgVal = transValue(II->getArgOperand(0), BB); + SPIRVValue *SecondArgVal = transValue(II->getArgOperand(1), BB); + + SPIRVValue *Sub = + BM->addBinaryInst(OpISub, Ty, FirstArgVal, SecondArgVal, BB); + SPIRVValue *Cmp = BM->addCmpInst(OpUGreaterThan, transType(BoolTy), + FirstArgVal, SecondArgVal, BB); + SPIRVValue *Zero = transValue(Constant::getNullValue(II->getType()), BB); + return BM->addSelectInst(Cmp, Sub, Zero, BB); + } case Intrinsic::memset: { // Generally memset can't be translated with current version of SPIRV spec. // But in most cases it turns out that memset is emited by Clang to do diff --git a/test/fp-intrinsics.ll b/test/fp-intrinsics.ll new file mode 100644 index 0000000000..35205fa1f9 --- /dev/null +++ b/test/fp-intrinsics.ll @@ -0,0 +1,333 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: spirv-val %t.spv + +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 [[extinst_id:[0-9]+]] "OpenCL.std" + +; CHECK: 3 TypeFloat [[var0:[0-9]+]] 16 +; CHECK: 3 TypeFloat [[var1:[0-9]+]] 32 +; CHECK: 3 TypeFloat [[var2:[0-9]+]] 64 +; CHECK: 4 TypeVector [[var3:[0-9]+]] [[var1]] 4 + +; CHECK: Function +; CHECK: ExtInst [[var0]] {{[0-9]+}} [[extinst_id]] fabs +; CHECK: FunctionEnd + +define spir_func half @TestFabs16(half %x) local_unnamed_addr { +entry: + %t = tail call half @llvm.fabs.f16(half %x) + ret half %t +} + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] fabs +; CHECK: FunctionEnd + +define spir_func float @TestFabs32(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.fabs.f32(float %x) + ret float %t +} + +; CHECK: Function +; CHECK: ExtInst [[var2]] {{[0-9]+}} [[extinst_id]] fabs +; CHECK: FunctionEnd + +define spir_func double @TestFabs64(double %x) local_unnamed_addr { +entry: + %t = tail call double @llvm.fabs.f64(double %x) + ret double %t +} + +; CHECK: Function +; CHECK: ExtInst [[var3]] {{[0-9]+}} [[extinst_id]] fabs +; CHECK: FunctionEnd + +; Function Attrs: nounwind readnone +define spir_func <4 x float> @TestFabsVec(<4 x float> %x) local_unnamed_addr { +entry: + %t = tail call <4 x float> @llvm.fabs.v4f32(<4 x float> %x) + ret <4 x float> %t +} + +declare half @llvm.fabs.f16(half) +declare float @llvm.fabs.f32(float) +declare double @llvm.fabs.f64(double) +declare <4 x float> @llvm.fabs.v4f32(<4 x float>) + +; We checked several types with fabs, but the type check works the same for +; all intrinsics being translated, so for the rest we'll just test one type. + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] ceil +; CHECK: FunctionEnd + +define spir_func float @TestCeil(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.ceil.f32(float %x) + ret float %t +} + +declare float @llvm.ceil.f32(float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[n:[0-9]+]] +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] pown [[x]] [[n]] +; CHECK: FunctionEnd + +define spir_func float @TestPowi(float %x, i32 %n) local_unnamed_addr { +entry: + %t = tail call float @llvm.powi.f32(float %x, i32 %n) + ret float %t +} + +declare float @llvm.powi.f32(float, i32) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] sin +; CHECK: FunctionEnd + +define spir_func float @TestSin(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.sin.f32(float %x) + ret float %t +} + +declare float @llvm.sin.f32(float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] cos +; CHECK: FunctionEnd + +define spir_func float @TestCos(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.cos.f32(float %x) + ret float %t +} + +declare float @llvm.cos.f32(float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[y:[0-9]+]] +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] pow [[x]] [[y]] +; CHECK: FunctionEnd + +define spir_func float @TestPow(float %x, float %y) local_unnamed_addr { +entry: + %t = tail call float @llvm.pow.f32(float %x, float %y) + ret float %t +} + +declare float @llvm.pow.f32(float, float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] exp +; CHECK: FunctionEnd + +define spir_func float @TestExp(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.exp.f32(float %x) + ret float %t +} + +declare float @llvm.exp.f32(float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] exp2 +; CHECK: FunctionEnd + +define spir_func float @TestExp2(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.exp2.f32(float %x) + ret float %t +} + +declare float @llvm.exp2.f32(float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] log +; CHECK: FunctionEnd + +define spir_func float @TestLog(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.log.f32(float %x) + ret float %t +} + +declare float @llvm.log.f32(float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] log10 +; CHECK: FunctionEnd + +define spir_func float @TestLog10(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.log10.f32(float %x) + ret float %t +} + +declare float @llvm.log10.f32(float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] log2 +; CHECK: FunctionEnd + +define spir_func float @TestLog2(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.log2.f32(float %x) + ret float %t +} + +declare float @llvm.log2.f32(float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[y:[0-9]+]] +; CHECK: ExtInst {{[0-9]+}} [[res:[0-9]+]] {{[0-9]+}} fmin [[x]] [[y]] +; CHECK: ReturnValue [[res]] + +define spir_func float @TestMinNum(float %x, float %y) { +entry: + %t = call float @llvm.minnum.f32(float %x, float %y) + ret float %t +} + +declare float @llvm.minnum.f32(float, float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[y:[0-9]+]] +; CHECK: ExtInst {{[0-9]+}} [[res:[0-9]+]] {{[0-9]+}} fmax [[x]] [[y]] +; CHECK: ReturnValue [[res]] + +define spir_func float @TestMaxNum(float %x, float %y) { +entry: + %t = call float @llvm.maxnum.f32(float %x, float %y) + ret float %t +} + +declare float @llvm.maxnum.f32(float, float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[y:[0-9]+]] +; CHECK: ExtInst {{[0-9]+}} [[res:[0-9]+]] {{[0-9]+}} fmin [[x]] [[y]] +; CHECK: ReturnValue [[res]] + +define spir_func float @TestMinimum(float %x, float %y) { +entry: + %t = call float @llvm.minimum.f32(float %x, float %y) + ret float %t +} + +declare float @llvm.minimum.f32(float, float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[y:[0-9]+]] +; CHECK: ExtInst {{[0-9]+}} [[res:[0-9]+]] {{[0-9]+}} fmax [[x]] [[y]] +; CHECK: ReturnValue [[res]] + +define spir_func float @TestMaximum(float %x, float %y) { +entry: + %t = call float @llvm.maximum.f32(float %x, float %y) + ret float %t +} + +declare float @llvm.maximum.f32(float, float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[y:[0-9]+]] +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] copysign [[x]] [[y]] +; CHECK: FunctionEnd + +define spir_func float @TestCopysign(float %x, float %y) local_unnamed_addr { +entry: + %t = tail call float @llvm.copysign.f32(float %x, float %y) + ret float %t +} + +declare float @llvm.copysign.f32(float, float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] floor +; CHECK: FunctionEnd + +define spir_func float @TestFloor(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.floor.f32(float %x) + ret float %t +} + +declare float @llvm.floor.f32(float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] trunc +; CHECK: FunctionEnd + +define spir_func float @TestTrunc(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.trunc.f32(float %x) + ret float %t +} + +declare float @llvm.trunc.f32(float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] rint +; CHECK: FunctionEnd + +define spir_func float @TestRint(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.rint.f32(float %x) + ret float %t +} + +declare float @llvm.rint.f32(float) + +; It is intentional that nearbyint translates to rint. +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] rint +; CHECK: FunctionEnd + +define spir_func float @TestNearbyint(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.nearbyint.f32(float %x) + ret float %t +} + +declare float @llvm.nearbyint.f32(float) + +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] round +; CHECK: FunctionEnd + +define spir_func float @TestRound(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.round.f32(float %x) + ret float %t +} + +declare float @llvm.round.f32(float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[y:[0-9]+]] +; CHECK: FunctionParameter {{[0-9]+}} [[z:[0-9]+]] +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] fma [[x]] [[y]] [[z]] +; CHECK: FunctionEnd + +define spir_func float @TestFma(float %x, float %y, float %z) { +entry: + %t = tail call float @llvm.fma.f32(float %x, float %y, float %z) + ret float %t +} + +declare float @llvm.fma.f32(float, float, float) diff --git a/test/negative/llvm.fma.ll b/test/negative/llvm-unhandled-intrinsic.ll similarity index 75% rename from test/negative/llvm.fma.ll rename to test/negative/llvm-unhandled-intrinsic.ll index a155994864..09110ea5c3 100644 --- a/test/negative/llvm.fma.ll +++ b/test/negative/llvm-unhandled-intrinsic.ll @@ -4,23 +4,21 @@ ; RUN: llvm-as %s -o %t.bc ; RUN: not --crash llvm-spirv %t.bc 2>&1 | FileCheck %s -; CHECK: InvalidFunctionCall: Unexpected llvm intrinsic: llvm.fma.f32 +; CHECK: InvalidFunctionCall: Unexpected llvm intrinsic: target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" target triple = "spir64" ; Function Attrs: nounwind -define spir_func void @foo(float %a, float %b, float %c) #0 { +define spir_func void @foo() #0 { entry: - %0 = call float @llvm.fma.f32(float %a, float %b, float %c) + %0 = call i64 @llvm.readcyclecounter() ret void } -; Function Attrs: nounwind readnone -declare float @llvm.fma.f32(float, float, float) #1 +declare i64 @llvm.readcyclecounter() attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind readnone } !opencl.enable.FP_CONTRACT = !{} !opencl.spir.version = !{!0} diff --git a/test/transcoding/AllowIntrinsics.ll b/test/transcoding/AllowIntrinsics.ll index 98c6f9f209..2e6a52aaf8 100644 --- a/test/transcoding/AllowIntrinsics.ll +++ b/test/transcoding/AllowIntrinsics.ll @@ -7,25 +7,24 @@ ; RUN: llvm-spirv -r %t.spv -o %t.rev.bc ; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM -; CHECK-LLVM: declare float @llvm.fma.f32(float, float, float) -; CHECK-SPIRV: LinkageAttributes "llvm.fma.f32" Import +; Note: This test used to call llvm.fma, but that is now traslated correctly. + +; CHECK-LLVM: declare i64 @llvm.readcyclecounter() +; CHECK-SPIRV: LinkageAttributes "llvm.readcyclecounter" Import target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" target triple = "spir64" ; Function Attrs: nounwind -define spir_func void @foo(float %a, float %b, float %c) #0 { +define spir_func void @foo() #0 { entry: - %0 = call float @llvm.fma.f32(float %a, float %b, float %c) + %0 = call i64 @llvm.readcyclecounter() ret void } -; Function Attrs: nounwind readnone -declare float @llvm.fma.f32(float, float, float) #1 +declare i64 @llvm.readcyclecounter() attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind readnone } -!opencl.enable.FP_CONTRACT = !{} !opencl.spir.version = !{!0} !opencl.ocl.version = !{!1} !opencl.used.extensions = !{!2}