[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