Home | History | Annotate | Download | only in SPIRV
      1 //===- OCL21ToSPIRV.cpp - Transform OCL21 to SPIR-V builtins -----*- C++ -*-===//
      2 //
      3 //                     The LLVM/SPIRV Translator
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
      9 //
     10 // Permission is hereby granted, free of charge, to any person obtaining a
     11 // copy of this software and associated documentation files (the "Software"),
     12 // to deal with the Software without restriction, including without limitation
     13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
     14 // and/or sell copies of the Software, and to permit persons to whom the
     15 // Software is furnished to do so, subject to the following conditions:
     16 //
     17 // Redistributions of source code must retain the above copyright notice,
     18 // this list of conditions and the following disclaimers.
     19 // Redistributions in binary form must reproduce the above copyright notice,
     20 // this list of conditions and the following disclaimers in the documentation
     21 // and/or other materials provided with the distribution.
     22 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
     23 // contributors may be used to endorse or promote products derived from this
     24 // Software without specific prior written permission.
     25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     28 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
     31 // THE SOFTWARE.
     32 //
     33 //===----------------------------------------------------------------------===//
     34 //
     35 // This file implements translation of OCL21 builtin functions.
     36 //
     37 //===----------------------------------------------------------------------===//
     38 #define DEBUG_TYPE "cl21tospv"
     39 
     40 #include "SPIRVInternal.h"
     41 #include "OCLUtil.h"
     42 #include "llvm/ADT/StringSwitch.h"
     43 #include "llvm/IR/InstVisitor.h"
     44 #include "llvm/IR/Instructions.h"
     45 #include "llvm/IR/IRBuilder.h"
     46 #include "llvm/IR/Verifier.h"
     47 #include "llvm/Pass.h"
     48 #include "llvm/PassSupport.h"
     49 #include "llvm/Support/Debug.h"
     50 #include "llvm/Support/raw_ostream.h"
     51 
     52 #include <set>
     53 
     54 using namespace llvm;
     55 using namespace SPIRV;
     56 using namespace OCLUtil;
     57 
     58 namespace SPIRV {
     59 
     60 class OCL21ToSPIRV: public ModulePass,
     61   public InstVisitor<OCL21ToSPIRV> {
     62 public:
     63   OCL21ToSPIRV():ModulePass(ID), M(nullptr), Ctx(nullptr), CLVer(0) {
     64     initializeOCL21ToSPIRVPass(*PassRegistry::getPassRegistry());
     65   }
     66   virtual bool runOnModule(Module &M);
     67   virtual void visitCallInst(CallInst &CI);
     68 
     69   /// Transform SPIR-V convert function
     70   //    __spirv{N}Op{ConvertOpName}(src, dummy)
     71   ///   =>
     72   ///   __spirv_{ConvertOpName}_R{TargeTyName}
     73   void visitCallConvert(CallInst *CI, StringRef MangledName, Op OC);
     74 
     75   /// Transform SPIR-V decoration
     76   ///   x = __spirv_{OpName};
     77   ///   y = __spirv{N}Op{Decorate}(x, type, value, dummy)
     78   ///   =>
     79   ///   y = __spirv_{OpName}{Postfix(type,value)}
     80   void visitCallDecorate(CallInst *CI, StringRef MangledName);
     81 
     82   /// Transform sub_group_barrier to __spirv_ControlBarrier.
     83   /// sub_group_barrier(scope, flag) =>
     84   ///   __spirv_ControlBarrier(subgroup, map(scope), map(flag))
     85   void visitCallSubGroupBarrier(CallInst *CI);
     86 
     87   /// Transform OCL C++ builtin function to SPIR-V builtin function.
     88   /// Assuming there is no argument changes.
     89   /// Should be called at last.
     90   void transBuiltin(CallInst *CI, Op OC);
     91 
     92   static char ID;
     93 private:
     94   ConstantInt *addInt32(int I) {
     95     return getInt32(M, I);
     96   }
     97 
     98   Module *M;
     99   LLVMContext *Ctx;
    100   unsigned CLVer;                   /// OpenCL version as major*10+minor
    101   std::set<Value *> ValuesToDelete;
    102 };
    103 
    104 char OCL21ToSPIRV::ID = 0;
    105 
    106 bool
    107 OCL21ToSPIRV::runOnModule(Module& Module) {
    108   M = &Module;
    109   Ctx = &M->getContext();
    110 
    111   auto Src = getSPIRVSource(&Module);
    112   if (std::get<0>(Src) != spv::SourceLanguageOpenCL_CPP)
    113     return false;
    114 
    115   CLVer = std::get<1>(Src);
    116   if (CLVer < kOCLVer::CL21)
    117     return false;
    118 
    119   DEBUG(dbgs() << "Enter OCL21ToSPIRV:\n");
    120   visit(*M);
    121 
    122   for (auto &I:ValuesToDelete)
    123     if (auto Inst = dyn_cast<Instruction>(I))
    124       Inst->eraseFromParent();
    125   for (auto &I:ValuesToDelete)
    126     if (auto GV = dyn_cast<GlobalValue>(I))
    127       GV->eraseFromParent();
    128 
    129   DEBUG(dbgs() << "After OCL21ToSPIRV:\n" << *M);
    130   std::string Err;
    131   raw_string_ostream ErrorOS(Err);
    132   if (verifyModule(*M, &ErrorOS)){
    133     DEBUG(errs() << "Fails to verify module: " << ErrorOS.str());
    134   }
    135   return true;
    136 }
    137 
    138 // The order of handling OCL builtin functions is important.
    139 // Workgroup functions need to be handled before pipe functions since
    140 // there are functions fall into both categories.
    141 void
    142 OCL21ToSPIRV::visitCallInst(CallInst& CI) {
    143   DEBUG(dbgs() << "[visistCallInst] " << CI << '\n');
    144   auto F = CI.getCalledFunction();
    145   if (!F)
    146     return;
    147 
    148   auto MangledName = F->getName();
    149   std::string DemangledName;
    150 
    151   if (oclIsBuiltin(MangledName, &DemangledName)) {
    152     if (DemangledName == kOCLBuiltinName::SubGroupBarrier) {
    153       visitCallSubGroupBarrier(&CI);
    154       return;
    155     }
    156   }
    157 
    158   if (!oclIsBuiltin(MangledName, &DemangledName, true))
    159     return;
    160   DEBUG(dbgs() << "DemangledName:" << DemangledName << '\n');
    161   StringRef Ref(DemangledName);
    162 
    163   Op OC = OpNop;
    164   if (!OpCodeNameMap::rfind(Ref.str(), &OC))
    165     return;
    166   DEBUG(dbgs() << "maps to opcode " << OC << '\n');
    167 
    168   if (isCvtOpCode(OC)) {
    169     visitCallConvert(&CI, MangledName, OC);
    170     return;
    171   }
    172   if (OC == OpDecorate) {
    173     visitCallDecorate(&CI, MangledName);
    174     return;
    175   }
    176   transBuiltin(&CI, OC);
    177 }
    178 
    179 void OCL21ToSPIRV::visitCallConvert(CallInst* CI,
    180     StringRef MangledName, Op OC) {
    181   AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
    182   mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){
    183     Args.pop_back();
    184     return getSPIRVFuncName(OC, kSPIRVPostfix::Divider +
    185       getPostfixForReturnType(CI,
    186       OC == OpSConvert || OC == OpConvertFToS || OC == OpSatConvertUToS));
    187   }, &Attrs);
    188   ValuesToDelete.insert(CI);
    189   ValuesToDelete.insert(CI->getCalledFunction());
    190 }
    191 
    192 void OCL21ToSPIRV::visitCallDecorate(CallInst* CI,
    193     StringRef MangledName) {
    194   auto Target = cast<CallInst>(CI->getArgOperand(0));
    195   auto F = Target->getCalledFunction();
    196   auto Name = F->getName().str();
    197   std::string DemangledName;
    198   oclIsBuiltin(Name, &DemangledName);
    199   BuiltinFuncMangleInfo Info;
    200   F->setName(mangleBuiltin(DemangledName + kSPIRVPostfix::Divider +
    201       getPostfix(getArgAsDecoration(CI, 1), getArgAsInt(CI, 2)),
    202       getTypes(getArguments(CI)), &Info));
    203   CI->replaceAllUsesWith(Target);
    204   ValuesToDelete.insert(CI);
    205   ValuesToDelete.insert(CI->getCalledFunction());
    206 }
    207 
    208 void
    209 OCL21ToSPIRV::visitCallSubGroupBarrier(CallInst *CI) {
    210   DEBUG(dbgs() << "[visitCallSubGroupBarrier] "<< *CI << '\n');
    211   auto Lit = getBarrierLiterals(CI);
    212   AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
    213   mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){
    214       Args.resize(3);
    215       Args[0] = addInt32(map<Scope>(std::get<2>(Lit)));
    216       Args[1] = addInt32(map<Scope>(std::get<1>(Lit)));
    217       Args[2] = addInt32(mapOCLMemFenceFlagToSPIRV(std::get<0>(Lit)));
    218       return getSPIRVFuncName(OpControlBarrier);
    219     }, &Attrs);
    220 }
    221 
    222 void
    223 OCL21ToSPIRV::transBuiltin(CallInst* CI, Op OC) {
    224   AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
    225   assert(OC != OpExtInst && "not supported");
    226   mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){
    227     return getSPIRVFuncName(OC);
    228   }, &Attrs);
    229   ValuesToDelete.insert(CI);
    230   ValuesToDelete.insert(CI->getCalledFunction());
    231 }
    232 
    233 }
    234 
    235 INITIALIZE_PASS(OCL21ToSPIRV, "cl21tospv", "Transform OCL 2.1 to SPIR-V",
    236     false, false)
    237 
    238 ModulePass *llvm::createOCL21ToSPIRV() {
    239   return new OCL21ToSPIRV();
    240 }
    241