Skip to content

[SYCL]Support LLVM FP intrinsic in llvm-spirv and enable the corresponding … #2880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 0 additions & 24 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
69 changes: 51 additions & 18 deletions clang/test/SemaSYCL/unsupported_math.cpp
Original file line number Diff line number Diff line change
@@ -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 logf(float);
extern "C" float sinf(float);
extern "C" float cosf(float);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should move "supported" function out of "unsupported-math.cpp" test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the "supported" math builtin/function into a new case "supported_math.cpp".

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 <typename name, typename Func>
__attribute__((sycl_kernel)) void kernel(const Func &kernelFunc) {
kernelFunc();
Expand All @@ -14,21 +26,42 @@ int main() {
kernel<class kernel_function>([=]() {
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;
}
28 changes: 26 additions & 2 deletions llvm-spirv/lib/SPIRV/SPIRVUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
166 changes: 131 additions & 35 deletions llvm-spirv/lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -2097,6 +2117,69 @@ 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<SPIRVWord> {
Expand Down Expand Up @@ -2139,35 +2222,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<SPIRVValue *> 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<SPIRVValue *> Ops(1, transValue(II->getArgOperand(0), BB));
std::vector<SPIRVValue *> Ops{transValue(II->getArgOperand(0), BB),
transValue(II->getArgOperand(1), BB)};
return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops,
BB);
}
case Intrinsic::ceil: {
case Intrinsic::fma: {
if (!checkTypeForSPIRVExtendedInstLowering(II, BM))
break;
SPIRVWord ExtOp = OpenCLLIB::Ceil;
SPIRVWord ExtOp = OpenCLLIB::Fma;
SPIRVType *STy = transType(II->getType());
std::vector<SPIRVValue *> 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::abs: {
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;
SPIRVType *STy = transType(II->getType());
std::vector<SPIRVValue *> Ops(1, transValue(II->getArgOperand(0), BB));
return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops,
Expand Down Expand Up @@ -2309,16 +2422,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<SPIRVValue *> 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());
Expand Down Expand Up @@ -2391,13 +2494,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.
Expand Down
Loading