Skip to content
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
28 changes: 26 additions & 2 deletions lib/SPIRV/SPIRVUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1529,10 +1529,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
167 changes: 132 additions & 35 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2050,12 +2050,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 @@ -2078,7 +2099,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 @@ -2115,6 +2135,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 @@ -2157,35 +2240,66 @@ 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 @@ -2340,16 +2454,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 @@ -2422,13 +2526,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