• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
OCL21ToSPIRV()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:
addInt32(int I)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
runOnModule(Module & Module)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
visitCallInst(CallInst & CI)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 
visitCallConvert(CallInst * CI,StringRef MangledName,Op OC)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 
visitCallDecorate(CallInst * CI,StringRef MangledName)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
visitCallSubGroupBarrier(CallInst * CI)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
transBuiltin(CallInst * CI,Op OC)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 
createOCL21ToSPIRV()238 ModulePass *llvm::createOCL21ToSPIRV() {
239   return new OCL21ToSPIRV();
240 }
241