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