From: Luo <[email protected]> add sqrt, ceil, ctlz, fma, trunc, copysign intrinsicID to handle llvm call functions; the copysignf is from libFun.
Signed-off-by: Luo <[email protected]> --- 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 _______________________________________________ Beignet mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/beignet
