[Beignet] [PATCH 3/3] add llvm intrinsic call translate.
xionghu.luo at intel.com
xionghu.luo at intel.com
Wed Jan 14 21:22:09 PST 2015
From: Luo <xionghu.luo at intel.com>
add sqrt, ceil, ctlz, fma, trunc, copysign intrinsicID to handle llvm
call functions; the copysignf is from libFun.
Signed-off-by: Luo <xionghu.luo at intel.com>
---
backend/src/llvm/llvm_gen_backend.cpp | 160 ++++++++++++++++++++++++++++++++++
backend/src/llvm/llvm_scalarize.cpp | 72 ++++++++++++++-
2 files changed, 228 insertions(+), 4 deletions(-)
diff --git a/backend/src/llvm/llvm_gen_backend.cpp b/backend/src/llvm/llvm_gen_backend.cpp
index a73f9e8..53dec0a 100644
--- a/backend/src/llvm/llvm_gen_backend.cpp
+++ b/backend/src/llvm/llvm_gen_backend.cpp
@@ -151,6 +151,7 @@
#include "llvm/Support/Host.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/llvm_gen_backend.hpp"
#include "ir/context.hpp"
@@ -659,6 +660,8 @@ namespace gbe
ir::ImmediateIndex processSeqConstant(ConstantDataSequential *seq,
int index, ConstTypeId tid);
ir::ImmediateIndex processConstantVector(ConstantVector *cv, int index);
+
+ bool isLibFuncFunc(CallInst* call, LibFunc::Func& Func);
};
char GenWriter::ID = 0;
@@ -2753,6 +2756,27 @@ error:
}
}
+ bool GenWriter::isLibFuncFunc(CallInst* call, LibFunc::Func& Func)
+ {
+ TargetLibraryInfo *LibInfo;
+ Function *F = call->getCalledFunction();
+
+ LibInfo = getAnalysisIfAvailable<TargetLibraryInfo>();
+ if (!F->hasLocalLinkage() && F->hasName() && LibInfo &&
+ LibInfo->getLibFunc(F->getName(), Func) &&
+ LibInfo->hasOptimizedCodeGen(Func)) {
+ // Non-read-only functions are never treated as intrinsics.
+ if (!call->onlyReadsMemory())
+ return false;
+
+ // Conversion happens only for FP calls.
+ if (!call->getArgOperand(0)->getType()->isFloatingPointTy())
+ return false;
+ return true;
+ }
+ return false;
+ }
+
void GenWriter::regAllocateCallInst(CallInst &I) {
Value *dst = &I;
Value *Callee = I.getCalledValue();
@@ -2794,6 +2818,16 @@ error:
case Intrinsic::bswap:
this->newRegister(&I);
break;
+ case Intrinsic::sqrt:
+ case Intrinsic::ceil:
+ case Intrinsic::fma:
+ case Intrinsic::trunc:
+ case Intrinsic::copysign:
+ this->newRegister(&I);
+ break;
+ case Intrinsic::fabs:
+ this->newRegister(&I);
+ break;
default:
GBE_ASSERTM(false, "Unsupported intrinsics");
}
@@ -2801,6 +2835,29 @@ error:
}
}
+ if (Function *F = I.getCalledFunction()) {
+ // Most intrinsics don't become function calls, but some might.
+ // sin, cos, exp and log are always calls.
+ if (F->getIntrinsicID() != Intrinsic::not_intrinsic) {
+ switch (F->getIntrinsicID()) {
+ default:
+ GBE_ASSERTM(false, "Unsupported intrinsics");
+ }
+ }
+ LibFunc::Func Func;
+ if(isLibFuncFunc(&I, Func))
+ {
+ switch (Func) {
+ case LibFunc::copysignf:
+ this->newRegister(&I);
+ break;
+ default:
+ GBE_ASSERTM(false, "Unsupported libFuncs");
+ }
+ return;
+ }
+ }
+
// Get the name of the called function and handle it
const std::string fnName = Callee->getName();
auto genIntrinsicID = intrinsicMap.find(fnName);
@@ -3204,6 +3261,29 @@ error:
}
}
break;
+ case Intrinsic::sqrt:
+ {
+ const ir::Register dst = this->getRegister(&I);
+ const ir::Register src = this->getRegister(I.getOperand(0));
+ ctx.ALU1(ir::OP_SQR, ir::TYPE_FLOAT, dst, src);
+ }
+ break;
+ case Intrinsic::fabs:
+ {
+ ir::Type srcType = getType(ctx, I.getType());
+ const ir::Register dst = this->getRegister(&I);
+ const ir::Register src = this->getRegister(I.getOperand(0));
+ ctx.ALU1(ir::OP_ABS, srcType, dst, src);
+ }
+ break;
+ case Intrinsic::ceil:
+ {
+ ir::Type srcType = getType(ctx, I.getType());
+ const ir::Register dst = this->getRegister(&I);
+ const ir::Register src = this->getRegister(I.getOperand(0));
+ ctx.ALU1(ir::OP_RNDU, srcType, dst, src);
+ }
+ break;
case Intrinsic::ctlz:
{
ir::Type srcType = getType(ctx, I.getType());
@@ -3212,9 +3292,89 @@ error:
ctx.ALU1(ir::OP_LZD, srcType, dst, src);
}
break;
+ case Intrinsic::fma:
+ {
+ ir::Type srcType = getType(ctx, I.getType());
+ const ir::Register dst = this->getRegister(&I);
+ const ir::Register src0 = this->getRegister(I.getOperand(0));
+ const ir::Register src1 = this->getRegister(I.getOperand(1));
+ const ir::Register src2 = this->getRegister(I.getOperand(2));
+ ctx.MAD(srcType, dst, src0, src1, src2);
+ }
+ break;
+ case Intrinsic::trunc:
+ {
+ Type *llvmDstType = I.getType();
+ Type *llvmSrcType = I.getOperand(0)->getType();
+ ir::Type dstType = getType(ctx, llvmDstType);
+ ir::Type srcType = getType(ctx, llvmSrcType);
+ GBE_ASSERT(srcType == dstType);
+
+ const ir::Register tmp = ctx.reg(getFamily(ir::TYPE_S32));
+ const ir::Register dst = this->getRegister(&I);
+ const ir::Register src = this->getRegister(I.getOperand(0));
+ ctx.CVT(ir::TYPE_S32, srcType, tmp, src);
+ ctx.CVT(dstType, ir::TYPE_S32, dst, tmp);
+ }
+ break;
+ case Intrinsic::copysign:
+ {
+ ir::Type srcType = getType(ctx, I.getType());
+ const ir::Register dst = this->getRegister(&I);
+ const ir::Register src0 = this->getRegister(I.getOperand(0));
+ const ir::Register src1 = this->getRegister(I.getOperand(1));
+ const ir::Register cmp = ctx.reg(ir::FAMILY_BOOL);
+
+ const ir::Register tmp1 = ctx.reg(getFamily(srcType));
+ const ir::Register tmp2 = ctx.reg(getFamily(srcType));
+
+ const ir::RegisterFamily family = getFamily(srcType);
+ const ir::ImmediateIndex zero = ctx.newFloatImmediate((float)0.0);
+ const ir::Register zeroReg = ctx.reg(family);
+ ctx.LOADI(srcType, zeroReg, zero);
+
+ ctx.GE(srcType, cmp, src1, zeroReg);
+ ctx.ALU1(ir::OP_ABS, srcType, tmp1, src0);
+ ctx.SUB(srcType, tmp2, zeroReg, tmp1);
+ ctx.SEL(srcType, dst, cmp, tmp1, tmp2);
+ }
+ break;
default: NOT_IMPLEMENTED;
}
} else {
+
+ LibFunc::Func Func;
+ if(isLibFuncFunc(&I, Func))
+ {
+ switch (Func) {
+ case LibFunc::copysignf:
+ {
+ ir::Type srcType = getType(ctx, I.getType());
+ const ir::Register dst = this->getRegister(&I);
+ const ir::Register src0 = this->getRegister(I.getOperand(0));
+ const ir::Register src1 = this->getRegister(I.getOperand(1));
+ const ir::Register cmp = ctx.reg(ir::FAMILY_BOOL);
+
+ const ir::Register tmp1 = ctx.reg(getFamily(srcType));
+ const ir::Register tmp2 = ctx.reg(getFamily(srcType));
+
+ const ir::RegisterFamily family = getFamily(srcType);
+ const ir::ImmediateIndex zero = ctx.newFloatImmediate((float)0.0);
+ const ir::Register zeroReg = ctx.reg(family);
+ ctx.LOADI(srcType, zeroReg, zero);
+
+ ctx.GE(srcType, cmp, src1, zeroReg);
+ ctx.ALU1(ir::OP_ABS, srcType, tmp1, src0);
+ ctx.SUB(srcType, tmp2, zeroReg, tmp1);
+ ctx.SEL(srcType, dst, cmp, tmp1, tmp2);
+ }
+ break;
+ default:
+ GBE_ASSERTM(false, "Unsupported libFuncs");
+ }
+ return;
+ }
+
// Get the name of the called function and handle it
Value *Callee = I.getCalledValue();
const std::string fnName = Callee->getName();
diff --git a/backend/src/llvm/llvm_scalarize.cpp b/backend/src/llvm/llvm_scalarize.cpp
index cf2939d..987e16b 100644
--- a/backend/src/llvm/llvm_scalarize.cpp
+++ b/backend/src/llvm/llvm_scalarize.cpp
@@ -92,6 +92,7 @@
#include "llvm/Support/CFG.h"
#endif
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/llvm_gen_backend.hpp"
#include "sys/map.hpp"
@@ -158,6 +159,7 @@ namespace gbe {
bool scalarizeShuffleVector(ShuffleVectorInst*);
bool scalarizePHI(PHINode*);
void scalarizeArgs(Function& F);
+ bool isLibFuncFunc(CallInst* call, LibFunc::Func& Func);
// ...
// Helpers to make the actual multiple scalar calls, one per
@@ -277,8 +279,18 @@ namespace gbe {
bool Scalarize::IsPerComponentOp(const Instruction* inst)
{
- //if (const IntrinsicInst* intr = dyn_cast<const IntrinsicInst>(inst))
- // return IsPerComponentOp(intr);
+ if (const IntrinsicInst* intr = dyn_cast<const IntrinsicInst>(inst))
+ {
+ const Intrinsic::ID intrinsicID = (Intrinsic::ID) intr->getIntrinsicID();
+ switch (intrinsicID) {
+ default: return false;
+ case Intrinsic::sqrt:
+ case Intrinsic::ceil:
+ case Intrinsic::copysign:
+ case Intrinsic::trunc:
+ return true;
+ }
+ }
if (inst->isTerminator())
return false;
@@ -423,13 +435,17 @@ namespace gbe {
// assumption. This is due to how getDeclaration operates; it only takes
// a list of types that fit overloadable slots.
SmallVector<Type*, 8> tys(1, GetBasicType(inst->getType()));
+
// Call instructions have the decl as a last argument, so skip it
+ SmallVector<Value*, 8> _args;
+
for (ArrayRef<Value*>::iterator i = args.begin(), e = args.end() - 1; i != e; ++i) {
tys.push_back(GetBasicType((*i)->getType()));
+ _args.push_back(*i);
}
Function* f = Intrinsic::getDeclaration(module, intr->getIntrinsicID(), tys);
- return CallInst::Create(f, args);
+ return CallInst::Create(f, _args);
}
NOT_IMPLEMENTED; //gla::UnsupportedFunctionality("Currently unsupported instruction: ", inst->getOpcode(),
@@ -629,11 +645,59 @@ namespace gbe {
return II;
}
+ bool Scalarize::isLibFuncFunc(CallInst* call, LibFunc::Func& Func)
+ {
+ TargetLibraryInfo *LibInfo;
+ Function *F = call->getCalledFunction();
+
+ LibInfo = getAnalysisIfAvailable<TargetLibraryInfo>();
+ if (!F->hasLocalLinkage() && F->hasName() && LibInfo &&
+ LibInfo->getLibFunc(F->getName(), Func) &&
+ LibInfo->hasOptimizedCodeGen(Func)) {
+ // Non-read-only functions are never treated as intrinsics.
+ if (!call->onlyReadsMemory())
+ return false;
+
+ // Conversion happens only for FP calls.
+ if (!call->getArgOperand(0)->getType()->isFloatingPointTy())
+ return false;
+ return true;
+ }
+ return false;
+ }
+
bool Scalarize::scalarizeFuncCall(CallInst* call) {
if (Function *F = call->getCalledFunction()) {
if (F->getIntrinsicID() != 0) { //Intrinsic functions
- NOT_IMPLEMENTED;
+ const Intrinsic::ID intrinsicID = (Intrinsic::ID) F->getIntrinsicID();
+
+ switch (intrinsicID) {
+ default: GBE_ASSERTM(false, "Unsupported Intrinsic");
+ case Intrinsic::sqrt:
+ case Intrinsic::ceil:
+ case Intrinsic::copysign:
+ case Intrinsic::trunc:
+ {
+ scalarizePerComponent(call);
+ }
+ break;
+ }
} else {
+ LibFunc::Func Func;
+ if(isLibFuncFunc(call, Func))
+ {
+ switch (Func) {
+ case LibFunc::copysignf:
+ {
+ scalarizePerComponent(call);
+ }
+ break;
+ default:
+ GBE_ASSERTM(false, "Unsupported libFuncs");
+ }
+ return true;
+ }
+
Value *Callee = call->getCalledValue();
const std::string fnName = Callee->getName();
auto genIntrinsicID = intrinsicMap.find(fnName);
--
1.9.1
More information about the Beignet
mailing list