From b80f10f02d50c9714d894398612a26cf8c1da9d6 Mon Sep 17 00:00:00 2001 From: gejin Date: Wed, 9 Dec 2020 11:42:08 +0800 Subject: [PATCH 1/5] Support LLVM FP intrinsic in llvm-spirv and enable the corresponding builtin in FE Signed-off-by: gejin --- clang/lib/Sema/SemaSYCL.cpp | 24 -- clang/test/SemaSYCL/unsupported_math.cpp | 63 +++- llvm-spirv/lib/SPIRV/SPIRVUtil.cpp | 28 +- llvm-spirv/lib/SPIRV/SPIRVWriter.cpp | 142 +++++-- llvm-spirv/test/fp-intrinsics.ll | 346 ++++++++++++++++++ ...lvm.fma.ll => llvm-unhandled-intrinsic.ll} | 10 +- .../test/transcoding/AllowIntrinsics.ll | 15 +- 7 files changed, 538 insertions(+), 90 deletions(-) create mode 100644 llvm-spirv/test/fp-intrinsics.ll rename llvm-spirv/test/negative/{llvm.fma.ll => llvm-unhandled-intrinsic.ll} (78%) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index c15e58e9d28b1..ff74bda91545f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -165,38 +165,14 @@ static bool IsSyclMathFunc(unsigned BuiltinID) { case Builtin::BI__builtin_truncl: case Builtin::BIlroundl: case Builtin::BI__builtin_lroundl: - case Builtin::BIcopysign: - case Builtin::BI__builtin_copysign: - case Builtin::BIfloor: - case Builtin::BI__builtin_floor: case Builtin::BIfmax: case Builtin::BI__builtin_fmax: case Builtin::BIfmin: case Builtin::BI__builtin_fmin: - case Builtin::BInearbyint: - case Builtin::BI__builtin_nearbyint: - case Builtin::BIrint: - case Builtin::BI__builtin_rint: - case Builtin::BIround: - case Builtin::BI__builtin_round: - case Builtin::BItrunc: - case Builtin::BI__builtin_trunc: - case Builtin::BIcopysignf: - case Builtin::BI__builtin_copysignf: - case Builtin::BIfloorf: - case Builtin::BI__builtin_floorf: case Builtin::BIfmaxf: case Builtin::BI__builtin_fmaxf: case Builtin::BIfminf: case Builtin::BI__builtin_fminf: - case Builtin::BInearbyintf: - case Builtin::BI__builtin_nearbyintf: - case Builtin::BIrintf: - case Builtin::BI__builtin_rintf: - case Builtin::BIroundf: - case Builtin::BI__builtin_roundf: - case Builtin::BItruncf: - case Builtin::BI__builtin_truncf: case Builtin::BIlroundf: case Builtin::BI__builtin_lroundf: case Builtin::BI__builtin_fpclassify: diff --git a/clang/test/SemaSYCL/unsupported_math.cpp b/clang/test/SemaSYCL/unsupported_math.cpp index 3c0de837dcd77..f4f92a54dc1c2 100644 --- a/clang/test/SemaSYCL/unsupported_math.cpp +++ b/clang/test/SemaSYCL/unsupported_math.cpp @@ -1,10 +1,22 @@ // RUN: %clang_cc1 -fsycl -fsycl-is-device -fsyntax-only -Wno-sycl-2017-compat -verify %s extern "C" float sinf(float); extern "C" float cosf(float); +extern "C" float floorf(float); extern "C" float logf(float); +extern "C" float nearbyintf(float); +extern "C" float rintf(float); +extern "C" float roundf(float); +extern "C" float truncf(float); +extern "C" float copysignf(float, float); extern "C" double sin(double); extern "C" double cos(double); +extern "C" double floor(double); extern "C" double log(double); +extern "C" double nearbyint(double); +extern "C" double rint(double); +extern "C" double round(double); +extern "C" double trunc(double); +extern "C" double copysign(double, double); template __attribute__((sycl_kernel)) void kernel(const Func &kernelFunc) { kernelFunc(); @@ -14,21 +26,42 @@ int main() { kernel([=]() { int acc[1] = {5}; acc[0] *= 2; - acc[0] += (int)sinf(1.0f); // expected-no-error - acc[0] += (int)sin(1.0); // expected-no-error - acc[0] += (int)__builtin_sinf(1.0f); // expected-no-error - acc[0] += (int)__builtin_sin(1.0); // expected-no-error - acc[0] += (int)cosf(1.0f); // expected-no-error - acc[0] += (int)cos(1.0); // expected-no-error - acc[0] += (int)__builtin_cosf(1.0f); // expected-no-error - acc[0] += (int)__builtin_cos(1.0); // expected-no-error - acc[0] += (int)logf(1.0f); // expected-no-error - acc[0] += (int)log(1.0); // expected-no-error - acc[0] += (int)__builtin_logf(1.0f); // expected-no-error - acc[0] += (int)__builtin_log(1.0); // expected-no-error - acc[0] += (int)__builtin_fabsl(-1.0); // expected-error{{builtin is not supported on this target}} - acc[0] += (int)__builtin_cosl(-1.0); // expected-error{{builtin is not supported on this target}} - acc[0] += (int)__builtin_powl(-1.0, 10.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)truncf(1.0f); // expected-no-error + acc[0] += (int)trunc(1.0); // expected-no-error + acc[0] += (int)roundf(1.0f); // expected-no-error + acc[0] += (int)round(1.0); // expected-no-error + acc[0] += (int)rintf(1.0f); // expected-no-error + acc[0] += (int)rint(1.0); // expected-no-error + acc[0] += (int)nearbyintf(0.5f); // expected-no-error + acc[0] += (int)nearbyint(0.5); // expected-no-error + acc[0] += (int)floorf(0.5f); // expected-no-error + acc[0] += (int)floor(0.5); // expected-no-error + acc[0] += (int)copysignf(1.0f, -0.5f); // expected-no-error + acc[0] += (int)copysign(1.0, -0.5); // expected-no-error + acc[0] += (int)sinf(1.0f); // expected-no-error + acc[0] += (int)sin(1.0); // expected-no-error + acc[0] += (int)__builtin_sinf(1.0f); // expected-no-error + acc[0] += (int)__builtin_sin(1.0); // expected-no-error + acc[0] += (int)cosf(1.0f); // expected-no-error + acc[0] += (int)cos(1.0); // expected-no-error + acc[0] += (int)__builtin_cosf(1.0f); // expected-no-error + acc[0] += (int)__builtin_cos(1.0); // expected-no-error + acc[0] += (int)logf(1.0f); // expected-no-error + acc[0] += (int)log(1.0); // expected-no-error + acc[0] += (int)__builtin_truncf(1.0f); // expected-no-error + acc[0] += (int)__builtin_trunc(1.0); // expected-no-error + acc[0] += (int)__builtin_rintf(1.0f); // expected-no-error + acc[0] += (int)__builtin_rint(1.0); // expected-no-error + acc[0] += (int)__builtin_nearbyintf(0.5f); // expected-no-error + acc[0] += (int)__builtin_nearbyint(0.5); // expected-no-error + acc[0] += (int)__builtin_floorf(0.5f); // expected-no-error + acc[0] += (int)__builtin_floor(0.5); // expected-no-error + acc[0] += (int)__builtin_copysignf(1.0f, -0.5f); // expected-no-error + acc[0] += (int)__builtin_logf(1.0f); // expected-no-error + acc[0] += (int)__builtin_log(1.0); // expected-no-error + acc[0] += (int)__builtin_fabsl(-1.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)__builtin_cosl(-1.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)__builtin_powl(-1.0, 10.0); // expected-error{{builtin is not supported on this target}} }); return 0; } diff --git a/llvm-spirv/lib/SPIRV/SPIRVUtil.cpp b/llvm-spirv/lib/SPIRV/SPIRVUtil.cpp index 11562e5a35325..808ff56fc001b 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVUtil.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVUtil.cpp @@ -1531,10 +1531,34 @@ bool hasLoopMetadata(const Module *M) { // Returns true if type(s) and number of elements (if vector) is valid bool checkTypeForSPIRVExtendedInstLowering(IntrinsicInst *II, SPIRVModule *BM) { switch (II->getIntrinsicID()) { - case Intrinsic::fabs: 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::nearbyint: { + case Intrinsic::minimum: + case Intrinsic::minnum: + case Intrinsic::nearbyint: + case Intrinsic::pow: + case Intrinsic::powi: + case Intrinsic::rint: + case Intrinsic::round: + case Intrinsic::roundeven: + 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; diff --git a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp index cd9afc301f149..eee8f6f9e84d1 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp @@ -2032,12 +2032,33 @@ void addIntelFPGADecorationsForStructMember(SPIRVEntry *E, bool LLVMToSPIRV::isKnownIntrinsic(Intrinsic::ID Id) { // Known intrinsics usually do not need translation of their declaration switch (Id) { + case Intrinsic::abs: case Intrinsic::assume: case Intrinsic::bitreverse: - case Intrinsic::sqrt: - case Intrinsic::fabs: - case Intrinsic::abs: 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::roundeven: + case Intrinsic::sin: + case Intrinsic::sqrt: + case Intrinsic::trunc: case Intrinsic::ctpop: case Intrinsic::ctlz: case Intrinsic::cttz: @@ -2060,7 +2081,6 @@ bool LLVMToSPIRV::isKnownIntrinsic(Intrinsic::ID Id) { case Intrinsic::fmuladd: case Intrinsic::memset: case Intrinsic::memcpy: - case Intrinsic::nearbyint: case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: case Intrinsic::dbg_declare: @@ -2097,6 +2117,45 @@ LLVMToSPIRV::applyRoundingModeConstraint(Value *V, SPIRVInstruction *I) { return I; } +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::roundeven: return OpenCLLIB::Rint; + 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 { @@ -2139,35 +2198,65 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, SPIRVValue *Op = transValue(II->getArgOperand(0), BB); return BM->addUnaryInst(OpBitReverse, Ty, Op, BB); } - case Intrinsic::sqrt: { - return BM->addExtInst(transType(II->getType()), - BM->getExtInstSetId(SPIRVEIS_OpenCL), OpenCLLIB::Sqrt, - {transValue(II->getOperand(0), BB)}, BB); - } - case Intrinsic::fabs: { + // 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::roundeven: + case Intrinsic::sin: + case Intrinsic::sqrt: + case Intrinsic::trunc: { if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) break; - SPIRVWord ExtOp = OpenCLLIB::Fabs; + 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); } - case Intrinsic::abs: { + // Binary FP intrinsics + case Intrinsic::copysign: + case Intrinsic::pow: + case Intrinsic::powi: + case Intrinsic::maximum: + case Intrinsic::maxnum: + case Intrinsic::minimum: + case Intrinsic::minnum: { if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) break; - // LLVM has only one version of abs and it is only for signed integers. We - // unconditionally choose SAbs here - SPIRVWord ExtOp = OpenCLLIB::SAbs; + SPIRVWord ExtOp = getBuiltinIdForIntrinsic(II->getIntrinsicID()); SPIRVType *STy = transType(II->getType()); - std::vector Ops(1, transValue(II->getArgOperand(0), BB)); + 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: { + if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) + break; + 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::ceil: { + case Intrinsic::abs: { if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) break; - SPIRVWord ExtOp = OpenCLLIB::Ceil; + // LLVM has only one version of abs and it is only for signed integers. We + // unconditionally choose SAbs here + SPIRVWord ExtOp = OpenCLLIB::SAbs; SPIRVType *STy = transType(II->getType()); std::vector Ops(1, transValue(II->getArgOperand(0), BB)); return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops, @@ -2309,16 +2398,6 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, return BM->addBinaryInst(OpFAdd, Ty, Mul, transValue(II->getArgOperand(2), BB), BB); } - case Intrinsic::maxnum: { - if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) - break; - SPIRVWord ExtOp = OpenCLLIB::Fmax; - 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::usub_sat: { // usub.sat(a, b) -> (a > b) ? a - b : 0 SPIRVType *Ty = transType(II->getType()); @@ -2391,13 +2470,6 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, Size = 0; return BM->addLifetimeInst(OC, transValue(II->getOperand(1), BB), Size, BB); } - case Intrinsic::nearbyint: { - if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) - break; - return BM->addExtInst(transType(II->getType()), - BM->getExtInstSetId(SPIRVEIS_OpenCL), OpenCLLIB::Rint, - {transValue(II->getOperand(0), BB)}, BB); - } // We don't want to mix translation of regular code and debug info, because // it creates a mess, therefore translation of debug intrinsics is // postponed until LLVMToSPIRVDbgTran::finalizeDebug...() methods. diff --git a/llvm-spirv/test/fp-intrinsics.ll b/llvm-spirv/test/fp-intrinsics.ll new file mode 100644 index 0000000000000..716dcbbfa8854 --- /dev/null +++ b/llvm-spirv/test/fp-intrinsics.ll @@ -0,0 +1,346 @@ +; 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) + +; It is intentional that roundeven translates to rint. +; CHECK: Function +; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] rint +; CHECK: FunctionEnd + +define spir_func float @TestRoundEven(float %x) local_unnamed_addr { +entry: + %t = tail call float @llvm.roundeven.f32(float %x) + ret float %t +} + +declare float @llvm.roundeven.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/llvm-spirv/test/negative/llvm.fma.ll b/llvm-spirv/test/negative/llvm-unhandled-intrinsic.ll similarity index 78% rename from llvm-spirv/test/negative/llvm.fma.ll rename to llvm-spirv/test/negative/llvm-unhandled-intrinsic.ll index 3103b71011c04..b2ed1476417c5 100644 --- a/llvm-spirv/test/negative/llvm.fma.ll +++ b/llvm-spirv/test/negative/llvm-unhandled-intrinsic.ll @@ -5,23 +5,21 @@ ; RUN: not llvm-spirv %t.bc 2>&1 | FileCheck %s ; CHECK: InvalidFunctionCall: Unexpected llvm intrinsic: -; CHECK-NEXT: llvm.fma.f32 +; CHECK-NEXT: llvm.readcyclecounter 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/llvm-spirv/test/transcoding/AllowIntrinsics.ll b/llvm-spirv/test/transcoding/AllowIntrinsics.ll index 98c6f9f2090c0..2e6a52aaf8406 100644 --- a/llvm-spirv/test/transcoding/AllowIntrinsics.ll +++ b/llvm-spirv/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} From 04f7ecb68ad5ae1b3bd2efdb51c371bc31a9c55c Mon Sep 17 00:00:00 2001 From: gejin Date: Wed, 9 Dec 2020 11:49:31 +0800 Subject: [PATCH 2/5] Fix clang format issue Signed-off-by: gejin --- clang/test/SemaSYCL/unsupported_math.cpp | 90 ++++++++++++------------ llvm-spirv/lib/SPIRV/SPIRVWriter.cpp | 72 ++++++++++++------- 2 files changed, 93 insertions(+), 69 deletions(-) diff --git a/clang/test/SemaSYCL/unsupported_math.cpp b/clang/test/SemaSYCL/unsupported_math.cpp index f4f92a54dc1c2..d69d8ab8573df 100644 --- a/clang/test/SemaSYCL/unsupported_math.cpp +++ b/clang/test/SemaSYCL/unsupported_math.cpp @@ -1,13 +1,13 @@ // RUN: %clang_cc1 -fsycl -fsycl-is-device -fsyntax-only -Wno-sycl-2017-compat -verify %s -extern "C" float sinf(float); -extern "C" float cosf(float); -extern "C" float floorf(float); -extern "C" float logf(float); -extern "C" float nearbyintf(float); -extern "C" float rintf(float); -extern "C" float roundf(float); -extern "C" float truncf(float); -extern "C" float copysignf(float, float); +extern "C" float sinf(float); +extern "C" float cosf(float); +extern "C" float floorf(float); +extern "C" float logf(float); +extern "C" float nearbyintf(float); +extern "C" float rintf(float); +extern "C" float roundf(float); +extern "C" float truncf(float); +extern "C" float copysignf(float, float); extern "C" double sin(double); extern "C" double cos(double); extern "C" double floor(double); @@ -26,42 +26,42 @@ int main() { kernel([=]() { int acc[1] = {5}; acc[0] *= 2; - acc[0] += (int)truncf(1.0f); // expected-no-error - acc[0] += (int)trunc(1.0); // expected-no-error - acc[0] += (int)roundf(1.0f); // expected-no-error - acc[0] += (int)round(1.0); // expected-no-error - acc[0] += (int)rintf(1.0f); // expected-no-error - acc[0] += (int)rint(1.0); // expected-no-error - acc[0] += (int)nearbyintf(0.5f); // expected-no-error - acc[0] += (int)nearbyint(0.5); // expected-no-error - acc[0] += (int)floorf(0.5f); // expected-no-error - acc[0] += (int)floor(0.5); // expected-no-error - acc[0] += (int)copysignf(1.0f, -0.5f); // expected-no-error - acc[0] += (int)copysign(1.0, -0.5); // expected-no-error - acc[0] += (int)sinf(1.0f); // expected-no-error - acc[0] += (int)sin(1.0); // expected-no-error - acc[0] += (int)__builtin_sinf(1.0f); // expected-no-error - acc[0] += (int)__builtin_sin(1.0); // expected-no-error - acc[0] += (int)cosf(1.0f); // expected-no-error - acc[0] += (int)cos(1.0); // expected-no-error - acc[0] += (int)__builtin_cosf(1.0f); // expected-no-error - acc[0] += (int)__builtin_cos(1.0); // expected-no-error - acc[0] += (int)logf(1.0f); // expected-no-error - acc[0] += (int)log(1.0); // expected-no-error - acc[0] += (int)__builtin_truncf(1.0f); // expected-no-error - acc[0] += (int)__builtin_trunc(1.0); // expected-no-error - acc[0] += (int)__builtin_rintf(1.0f); // expected-no-error - acc[0] += (int)__builtin_rint(1.0); // expected-no-error - acc[0] += (int)__builtin_nearbyintf(0.5f); // expected-no-error - acc[0] += (int)__builtin_nearbyint(0.5); // expected-no-error - acc[0] += (int)__builtin_floorf(0.5f); // expected-no-error - acc[0] += (int)__builtin_floor(0.5); // expected-no-error - acc[0] += (int)__builtin_copysignf(1.0f, -0.5f); // expected-no-error - acc[0] += (int)__builtin_logf(1.0f); // expected-no-error - acc[0] += (int)__builtin_log(1.0); // expected-no-error - acc[0] += (int)__builtin_fabsl(-1.0); // expected-error{{builtin is not supported on this target}} - acc[0] += (int)__builtin_cosl(-1.0); // expected-error{{builtin is not supported on this target}} - acc[0] += (int)__builtin_powl(-1.0, 10.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)truncf(1.0f); // expected-no-error + acc[0] += (int)trunc(1.0); // expected-no-error + acc[0] += (int)roundf(1.0f); // expected-no-error + acc[0] += (int)round(1.0); // expected-no-error + acc[0] += (int)rintf(1.0f); // expected-no-error + acc[0] += (int)rint(1.0); // expected-no-error + acc[0] += (int)nearbyintf(0.5f); // expected-no-error + acc[0] += (int)nearbyint(0.5); // expected-no-error + acc[0] += (int)floorf(0.5f); // expected-no-error + acc[0] += (int)floor(0.5); // expected-no-error + acc[0] += (int)copysignf(1.0f, -0.5f); // expected-no-error + acc[0] += (int)copysign(1.0, -0.5); // expected-no-error + acc[0] += (int)sinf(1.0f); // expected-no-error + acc[0] += (int)sin(1.0); // expected-no-error + acc[0] += (int)__builtin_sinf(1.0f); // expected-no-error + acc[0] += (int)__builtin_sin(1.0); // expected-no-error + acc[0] += (int)cosf(1.0f); // expected-no-error + acc[0] += (int)cos(1.0); // expected-no-error + acc[0] += (int)__builtin_cosf(1.0f); // expected-no-error + acc[0] += (int)__builtin_cos(1.0); // expected-no-error + acc[0] += (int)logf(1.0f); // expected-no-error + acc[0] += (int)log(1.0); // expected-no-error + acc[0] += (int)__builtin_truncf(1.0f); // expected-no-error + acc[0] += (int)__builtin_trunc(1.0); // expected-no-error + acc[0] += (int)__builtin_rintf(1.0f); // expected-no-error + acc[0] += (int)__builtin_rint(1.0); // expected-no-error + acc[0] += (int)__builtin_nearbyintf(0.5f); // expected-no-error + acc[0] += (int)__builtin_nearbyint(0.5); // expected-no-error + acc[0] += (int)__builtin_floorf(0.5f); // expected-no-error + acc[0] += (int)__builtin_floor(0.5); // expected-no-error + acc[0] += (int)__builtin_copysignf(1.0f, -0.5f); // expected-no-error + acc[0] += (int)__builtin_logf(1.0f); // expected-no-error + acc[0] += (int)__builtin_log(1.0); // expected-no-error + acc[0] += (int)__builtin_fabsl(-1.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)__builtin_cosl(-1.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)__builtin_powl(-1.0, 10.0); // expected-error{{builtin is not supported on this target}} }); return 0; } diff --git a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp index eee8f6f9e84d1..e0b3be1519b79 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp @@ -2126,30 +2126,54 @@ static SPIRVWord getBuiltinIdForIntrinsic(Intrinsic::ID IID) { // 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::roundeven: return OpenCLLIB::Rint; - case Intrinsic::sin: return OpenCLLIB::Sin; - case Intrinsic::sqrt: return OpenCLLIB::Sqrt; - case Intrinsic::trunc: return OpenCLLIB::Trunc; + 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::roundeven: + return OpenCLLIB::Rint; + 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; From 01ebd61a3c8c856ed9dace9652f9c2699d725572 Mon Sep 17 00:00:00 2001 From: gejin Date: Thu, 10 Dec 2020 22:57:46 +0800 Subject: [PATCH 3/5] Revert llvm-spirv change Signed-off-by: gejin --- llvm-spirv/lib/SPIRV/SPIRVUtil.cpp | 28 +- llvm-spirv/lib/SPIRV/SPIRVWriter.cpp | 166 ++------- llvm-spirv/test/fp-intrinsics.ll | 346 ------------------ ...lvm-unhandled-intrinsic.ll => llvm.fma.ll} | 10 +- .../test/transcoding/AllowIntrinsics.ll | 15 +- 5 files changed, 51 insertions(+), 514 deletions(-) delete mode 100644 llvm-spirv/test/fp-intrinsics.ll rename llvm-spirv/test/negative/{llvm-unhandled-intrinsic.ll => llvm.fma.ll} (78%) diff --git a/llvm-spirv/lib/SPIRV/SPIRVUtil.cpp b/llvm-spirv/lib/SPIRV/SPIRVUtil.cpp index c4d0a03a75592..538e775b6857d 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVUtil.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVUtil.cpp @@ -1531,34 +1531,10 @@ bool hasLoopMetadata(const Module *M) { // 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::ceil: 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::roundeven: - 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. + case Intrinsic::nearbyint: { Type *Ty = II->getType(); if (II->getArgOperand(0)->getType() != Ty) return false; diff --git a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp index 13ac5727a3b3c..4e12da44de95a 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp @@ -2067,33 +2067,12 @@ void addIntelFPGADecorationsForStructMember(SPIRVEntry *E, bool LLVMToSPIRV::isKnownIntrinsic(Intrinsic::ID Id) { // Known intrinsics usually do not need translation of their declaration switch (Id) { - case Intrinsic::abs: 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::roundeven: - case Intrinsic::sin: case Intrinsic::sqrt: - case Intrinsic::trunc: + case Intrinsic::fabs: + case Intrinsic::abs: + case Intrinsic::ceil: case Intrinsic::ctpop: case Intrinsic::ctlz: case Intrinsic::cttz: @@ -2116,6 +2095,7 @@ bool LLVMToSPIRV::isKnownIntrinsic(Intrinsic::ID Id) { case Intrinsic::fmuladd: case Intrinsic::memset: case Intrinsic::memcpy: + case Intrinsic::nearbyint: case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: case Intrinsic::dbg_declare: @@ -2152,69 +2132,6 @@ LLVMToSPIRV::applyRoundingModeConstraint(Value *V, SPIRVInstruction *I) { return I; } -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::roundeven: - return OpenCLLIB::Rint; - 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 { @@ -2257,65 +2174,35 @@ 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::roundeven: - case Intrinsic::sin: - case Intrinsic::sqrt: - case Intrinsic::trunc: { - if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) - break; - 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); + case Intrinsic::sqrt: { + return BM->addExtInst(transType(II->getType()), + BM->getExtInstSetId(SPIRVEIS_OpenCL), OpenCLLIB::Sqrt, + {transValue(II->getOperand(0), BB)}, 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: { + case Intrinsic::fabs: { if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) break; - SPIRVWord ExtOp = getBuiltinIdForIntrinsic(II->getIntrinsicID()); + SPIRVWord ExtOp = OpenCLLIB::Fabs; SPIRVType *STy = transType(II->getType()); - std::vector Ops{transValue(II->getArgOperand(0), BB), - transValue(II->getArgOperand(1), BB)}; + std::vector Ops(1, transValue(II->getArgOperand(0), BB)); return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops, BB); } - case Intrinsic::fma: { + case Intrinsic::abs: { if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) break; - SPIRVWord ExtOp = OpenCLLIB::Fma; + // LLVM has only one version of abs and it is only for signed integers. We + // unconditionally choose SAbs here + SPIRVWord ExtOp = OpenCLLIB::SAbs; SPIRVType *STy = transType(II->getType()); - std::vector Ops{transValue(II->getArgOperand(0), BB), - transValue(II->getArgOperand(1), BB), - transValue(II->getArgOperand(2), BB)}; + std::vector Ops(1, transValue(II->getArgOperand(0), BB)); return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops, BB); } - case Intrinsic::abs: { + case Intrinsic::ceil: { if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) break; - // LLVM has only one version of abs and it is only for signed integers. We - // unconditionally choose SAbs here - SPIRVWord ExtOp = OpenCLLIB::SAbs; + SPIRVWord ExtOp = OpenCLLIB::Ceil; SPIRVType *STy = transType(II->getType()); std::vector Ops(1, transValue(II->getArgOperand(0), BB)); return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops, @@ -2457,6 +2344,16 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, return BM->addBinaryInst(OpFAdd, Ty, Mul, transValue(II->getArgOperand(2), BB), BB); } + case Intrinsic::maxnum: { + if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) + break; + SPIRVWord ExtOp = OpenCLLIB::Fmax; + 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::usub_sat: { // usub.sat(a, b) -> (a > b) ? a - b : 0 SPIRVType *Ty = transType(II->getType()); @@ -2529,6 +2426,13 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, Size = 0; return BM->addLifetimeInst(OC, transValue(II->getOperand(1), BB), Size, BB); } + case Intrinsic::nearbyint: { + if (!checkTypeForSPIRVExtendedInstLowering(II, BM)) + break; + return BM->addExtInst(transType(II->getType()), + BM->getExtInstSetId(SPIRVEIS_OpenCL), OpenCLLIB::Rint, + {transValue(II->getOperand(0), BB)}, BB); + } // We don't want to mix translation of regular code and debug info, because // it creates a mess, therefore translation of debug intrinsics is // postponed until LLVMToSPIRVDbgTran::finalizeDebug...() methods. diff --git a/llvm-spirv/test/fp-intrinsics.ll b/llvm-spirv/test/fp-intrinsics.ll deleted file mode 100644 index 716dcbbfa8854..0000000000000 --- a/llvm-spirv/test/fp-intrinsics.ll +++ /dev/null @@ -1,346 +0,0 @@ -; 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) - -; It is intentional that roundeven translates to rint. -; CHECK: Function -; CHECK: ExtInst [[var1]] {{[0-9]+}} [[extinst_id]] rint -; CHECK: FunctionEnd - -define spir_func float @TestRoundEven(float %x) local_unnamed_addr { -entry: - %t = tail call float @llvm.roundeven.f32(float %x) - ret float %t -} - -declare float @llvm.roundeven.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/llvm-spirv/test/negative/llvm-unhandled-intrinsic.ll b/llvm-spirv/test/negative/llvm.fma.ll similarity index 78% rename from llvm-spirv/test/negative/llvm-unhandled-intrinsic.ll rename to llvm-spirv/test/negative/llvm.fma.ll index b2ed1476417c5..3103b71011c04 100644 --- a/llvm-spirv/test/negative/llvm-unhandled-intrinsic.ll +++ b/llvm-spirv/test/negative/llvm.fma.ll @@ -5,21 +5,23 @@ ; RUN: not llvm-spirv %t.bc 2>&1 | FileCheck %s ; CHECK: InvalidFunctionCall: Unexpected llvm intrinsic: -; CHECK-NEXT: llvm.readcyclecounter +; CHECK-NEXT: llvm.fma.f32 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() #0 { +define spir_func void @foo(float %a, float %b, float %c) #0 { entry: - %0 = call i64 @llvm.readcyclecounter() + %0 = call float @llvm.fma.f32(float %a, float %b, float %c) ret void } -declare i64 @llvm.readcyclecounter() +; Function Attrs: nounwind readnone +declare float @llvm.fma.f32(float, float, float) #1 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/llvm-spirv/test/transcoding/AllowIntrinsics.ll b/llvm-spirv/test/transcoding/AllowIntrinsics.ll index 2e6a52aaf8406..98c6f9f2090c0 100644 --- a/llvm-spirv/test/transcoding/AllowIntrinsics.ll +++ b/llvm-spirv/test/transcoding/AllowIntrinsics.ll @@ -7,24 +7,25 @@ ; RUN: llvm-spirv -r %t.spv -o %t.rev.bc ; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM -; 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 +; CHECK-LLVM: declare float @llvm.fma.f32(float, float, float) +; CHECK-SPIRV: LinkageAttributes "llvm.fma.f32" 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() #0 { +define spir_func void @foo(float %a, float %b, float %c) #0 { entry: - %0 = call i64 @llvm.readcyclecounter() + %0 = call float @llvm.fma.f32(float %a, float %b, float %c) ret void } -declare i64 @llvm.readcyclecounter() +; Function Attrs: nounwind readnone +declare float @llvm.fma.f32(float, float, float) #1 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} From 3d379f9562945e3771635fadd0a08da33041e7ea Mon Sep 17 00:00:00 2001 From: gejin Date: Tue, 15 Dec 2020 11:28:45 +0800 Subject: [PATCH 4/5] Move supported builtin functions out of unsupported_math test Signed-off-by: gejin --- clang/test/SemaSYCL/supported_math.cpp | 64 ++++++++++++++++++++++++ clang/test/SemaSYCL/unsupported_math.cpp | 51 ------------------- 2 files changed, 64 insertions(+), 51 deletions(-) create mode 100644 clang/test/SemaSYCL/supported_math.cpp diff --git a/clang/test/SemaSYCL/supported_math.cpp b/clang/test/SemaSYCL/supported_math.cpp new file mode 100644 index 0000000000000..aada7829ef781 --- /dev/null +++ b/clang/test/SemaSYCL/supported_math.cpp @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -fsycl -fsycl-is-device -fsyntax-only -Wno-sycl-strict -verify %s +extern "C" float sinf(float); +extern "C" float cosf(float); +extern "C" float floorf(float); +extern "C" float logf(float); +extern "C" float nearbyintf(float); +extern "C" float rintf(float); +extern "C" float roundf(float); +extern "C" float truncf(float); +extern "C" float copysignf(float, float); +extern "C" double sin(double); +extern "C" double cos(double); +extern "C" double floor(double); +extern "C" double log(double); +extern "C" double nearbyint(double); +extern "C" double rint(double); +extern "C" double round(double); +extern "C" double trunc(double); +extern "C" double copysign(double, double); +template +__attribute__((sycl_kernel)) void kernel(const Func &kernelFunc) { + kernelFunc(); +} + +int main() { + kernel([=]() { + int acc[1] = {5}; + acc[0] *= 2; + acc[0] += (int)truncf(1.0f); // expected-no-diagnostics + acc[0] += (int)trunc(1.0); // expected-no-diagnostics + acc[0] += (int)roundf(1.0f); // expected-no-diagnostics + acc[0] += (int)round(1.0); // expected-no-diagnostics + acc[0] += (int)rintf(1.0f); // expected-no-diagnostics + acc[0] += (int)rint(1.0); // expected-no-diagnostics + acc[0] += (int)nearbyintf(0.5f); // expected-no-diagnostics + acc[0] += (int)nearbyint(0.5); // expected-no-diagnostics + acc[0] += (int)floorf(0.5f); // expected-no-diagnostics + acc[0] += (int)floor(0.5); // expected-no-diagnostics + acc[0] += (int)copysignf(1.0f, -0.5f); // expected-no-diagnostics + acc[0] += (int)copysign(1.0, -0.5); // expected-no-diagnostics + acc[0] += (int)sinf(1.0f); // expected-no-diagnostics + acc[0] += (int)sin(1.0); // expected-no-diagnostics + acc[0] += (int)__builtin_sinf(1.0f); // expected-no-diagnostics + acc[0] += (int)__builtin_sin(1.0); // expected-no-diagnostics + acc[0] += (int)cosf(1.0f); // expected-no-diagnostics + acc[0] += (int)cos(1.0); // expected-no-diagnostics + acc[0] += (int)__builtin_cosf(1.0f); // expected-no-diagnostics + acc[0] += (int)__builtin_cos(1.0); // expected-no-diagnostics + acc[0] += (int)logf(1.0f); // expected-no-diagnostics + acc[0] += (int)log(1.0); // expected-no-diagnostics + acc[0] += (int)__builtin_truncf(1.0f); // expected-no-diagnostics + acc[0] += (int)__builtin_trunc(1.0); // expected-no-diagnostics + acc[0] += (int)__builtin_rintf(1.0f); // expected-no-diagnostics + acc[0] += (int)__builtin_rint(1.0); // expected-no-diagnostics + acc[0] += (int)__builtin_nearbyintf(0.5f); // expected-no-diagnostics + acc[0] += (int)__builtin_nearbyint(0.5); // expected-no-diagnostics + acc[0] += (int)__builtin_floorf(0.5f); // expected-no-diagnostics + acc[0] += (int)__builtin_floor(0.5); // expected-no-diagnostics + acc[0] += (int)__builtin_copysignf(1.0f, -0.5f); // expected-no-diagnostics + acc[0] += (int)__builtin_logf(1.0f); // expected-no-diagnostics + acc[0] += (int)__builtin_log(1.0); // expected-no-diagnostics + }); + return 0; +} diff --git a/clang/test/SemaSYCL/unsupported_math.cpp b/clang/test/SemaSYCL/unsupported_math.cpp index d69d8ab8573df..914762ea44622 100644 --- a/clang/test/SemaSYCL/unsupported_math.cpp +++ b/clang/test/SemaSYCL/unsupported_math.cpp @@ -1,22 +1,4 @@ // RUN: %clang_cc1 -fsycl -fsycl-is-device -fsyntax-only -Wno-sycl-2017-compat -verify %s -extern "C" float sinf(float); -extern "C" float cosf(float); -extern "C" float floorf(float); -extern "C" float logf(float); -extern "C" float nearbyintf(float); -extern "C" float rintf(float); -extern "C" float roundf(float); -extern "C" float truncf(float); -extern "C" float copysignf(float, float); -extern "C" double sin(double); -extern "C" double cos(double); -extern "C" double floor(double); -extern "C" double log(double); -extern "C" double nearbyint(double); -extern "C" double rint(double); -extern "C" double round(double); -extern "C" double trunc(double); -extern "C" double copysign(double, double); template __attribute__((sycl_kernel)) void kernel(const Func &kernelFunc) { kernelFunc(); @@ -26,39 +8,6 @@ int main() { kernel([=]() { int acc[1] = {5}; acc[0] *= 2; - acc[0] += (int)truncf(1.0f); // expected-no-error - acc[0] += (int)trunc(1.0); // expected-no-error - acc[0] += (int)roundf(1.0f); // expected-no-error - acc[0] += (int)round(1.0); // expected-no-error - acc[0] += (int)rintf(1.0f); // expected-no-error - acc[0] += (int)rint(1.0); // expected-no-error - acc[0] += (int)nearbyintf(0.5f); // expected-no-error - acc[0] += (int)nearbyint(0.5); // expected-no-error - acc[0] += (int)floorf(0.5f); // expected-no-error - acc[0] += (int)floor(0.5); // expected-no-error - acc[0] += (int)copysignf(1.0f, -0.5f); // expected-no-error - acc[0] += (int)copysign(1.0, -0.5); // expected-no-error - acc[0] += (int)sinf(1.0f); // expected-no-error - acc[0] += (int)sin(1.0); // expected-no-error - acc[0] += (int)__builtin_sinf(1.0f); // expected-no-error - acc[0] += (int)__builtin_sin(1.0); // expected-no-error - acc[0] += (int)cosf(1.0f); // expected-no-error - acc[0] += (int)cos(1.0); // expected-no-error - acc[0] += (int)__builtin_cosf(1.0f); // expected-no-error - acc[0] += (int)__builtin_cos(1.0); // expected-no-error - acc[0] += (int)logf(1.0f); // expected-no-error - acc[0] += (int)log(1.0); // expected-no-error - acc[0] += (int)__builtin_truncf(1.0f); // expected-no-error - acc[0] += (int)__builtin_trunc(1.0); // expected-no-error - acc[0] += (int)__builtin_rintf(1.0f); // expected-no-error - acc[0] += (int)__builtin_rint(1.0); // expected-no-error - acc[0] += (int)__builtin_nearbyintf(0.5f); // expected-no-error - acc[0] += (int)__builtin_nearbyint(0.5); // expected-no-error - acc[0] += (int)__builtin_floorf(0.5f); // expected-no-error - acc[0] += (int)__builtin_floor(0.5); // expected-no-error - acc[0] += (int)__builtin_copysignf(1.0f, -0.5f); // expected-no-error - acc[0] += (int)__builtin_logf(1.0f); // expected-no-error - acc[0] += (int)__builtin_log(1.0); // expected-no-error acc[0] += (int)__builtin_fabsl(-1.0); // expected-error{{builtin is not supported on this target}} acc[0] += (int)__builtin_cosl(-1.0); // expected-error{{builtin is not supported on this target}} acc[0] += (int)__builtin_powl(-1.0, 10.0); // expected-error{{builtin is not supported on this target}} From 57bc2124a30504d3a7064cf1d5771071a94a7bce Mon Sep 17 00:00:00 2001 From: gejin Date: Tue, 15 Dec 2020 11:34:29 +0800 Subject: [PATCH 5/5] Fix clang format issue Signed-off-by: gejin --- clang/test/SemaSYCL/unsupported_math.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/SemaSYCL/unsupported_math.cpp b/clang/test/SemaSYCL/unsupported_math.cpp index 914762ea44622..e0663b708785a 100644 --- a/clang/test/SemaSYCL/unsupported_math.cpp +++ b/clang/test/SemaSYCL/unsupported_math.cpp @@ -8,9 +8,9 @@ int main() { kernel([=]() { int acc[1] = {5}; acc[0] *= 2; - acc[0] += (int)__builtin_fabsl(-1.0); // expected-error{{builtin is not supported on this target}} - acc[0] += (int)__builtin_cosl(-1.0); // expected-error{{builtin is not supported on this target}} - acc[0] += (int)__builtin_powl(-1.0, 10.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)__builtin_fabsl(-1.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)__builtin_cosl(-1.0); // expected-error{{builtin is not supported on this target}} + acc[0] += (int)__builtin_powl(-1.0, 10.0); // expected-error{{builtin is not supported on this target}} }); return 0; }