1 //===- TransOCLMD.cpp - Transform OCL metadata to SPIR-V metadata - 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 OCL metadata to SPIR-V metadata.
36 //
37 //===----------------------------------------------------------------------===//
38 #define DEBUG_TYPE "clmdtospv"
39
40 #include "SPIRVInternal.h"
41 #include "OCLUtil.h"
42 #include "SPIRVMDBuilder.h"
43 #include "SPIRVMDWalker.h"
44
45 #include "llvm/ADT/StringSwitch.h"
46 #include "llvm/ADT/Triple.h"
47 #include "llvm/IR/InstVisitor.h"
48 #include "llvm/IR/Instructions.h"
49 #include "llvm/IR/IRBuilder.h"
50 #include "llvm/IR/Verifier.h"
51 #include "llvm/Pass.h"
52 #include "llvm/PassSupport.h"
53 #include "llvm/Support/CommandLine.h"
54 #include "llvm/Support/Debug.h"
55 #include "llvm/Support/raw_ostream.h"
56
57 #include <set>
58
59 using namespace llvm;
60 using namespace SPIRV;
61 using namespace OCLUtil;
62
63 namespace SPIRV {
64
65 cl::opt<bool> EraseOCLMD("spirv-erase-cl-md", cl::init(true),
66 cl::desc("Erase OpenCL metadata"));
67
68 class TransOCLMD: public ModulePass {
69 public:
TransOCLMD()70 TransOCLMD():ModulePass(ID), M(nullptr), Ctx(nullptr), CLVer(0) {
71 initializeTransOCLMDPass(*PassRegistry::getPassRegistry());
72 }
73
74 virtual bool runOnModule(Module &M);
75 void visit(Module *M);
76
77 static char ID;
78 private:
79 Module *M;
80 LLVMContext *Ctx;
81 unsigned CLVer; /// OpenCL version as major*10+minor
82 };
83
84 char TransOCLMD::ID = 0;
85
86 bool
runOnModule(Module & Module)87 TransOCLMD::runOnModule(Module& Module) {
88 M = &Module;
89 Ctx = &M->getContext();
90 CLVer = getOCLVersion(M, true);
91 if (CLVer == 0)
92 return false;
93
94 DEBUG(dbgs() << "Enter TransOCLMD:\n");
95 visit(M);
96
97 DEBUG(dbgs() << "After TransOCLMD:\n" << *M);
98 std::string Err;
99 raw_string_ostream ErrorOS(Err);
100 if (verifyModule(*M, &ErrorOS)){
101 DEBUG(errs() << "Fails to verify module: " << ErrorOS.str());
102 }
103 return true;
104 }
105
106 void
visit(Module * M)107 TransOCLMD::visit(Module *M) {
108 SPIRVMDBuilder B(*M);
109 SPIRVMDWalker W(*M);
110 B.addNamedMD(kSPIRVMD::Source)
111 .addOp()
112 .add(CLVer < kOCLVer::CL21 ? spv::SourceLanguageOpenCL_C
113 : spv::SourceLanguageOpenCL_CPP)
114 .add(CLVer)
115 .done();
116 if (EraseOCLMD)
117 B.eraseNamedMD(kSPIR2MD::OCLVer)
118 .eraseNamedMD(kSPIR2MD::SPIRVer);
119
120 Triple TT(M->getTargetTriple());
121 auto Arch = TT.getArch();
122 assert((Arch == Triple::spir || Arch == Triple::spir64) && "Invalid triple");
123 B.addNamedMD(kSPIRVMD::MemoryModel)
124 .addOp()
125 .add(Arch == Triple::spir ? spv::AddressingModelPhysical32 :
126 AddressingModelPhysical64)
127 .add(spv::MemoryModelOpenCL)
128 .done();
129
130 // Add extensions
131 auto Exts = getNamedMDAsStringSet(M, kSPIR2MD::Extensions);
132 if (!Exts.empty()) {
133 auto N = B.addNamedMD(kSPIRVMD::Extension);
134 for (auto &I:Exts)
135 N.addOp()
136 .add(I)
137 .done();
138 }
139 if (EraseOCLMD)
140 B.eraseNamedMD(kSPIR2MD::Extensions)
141 .eraseNamedMD(kSPIR2MD::OptFeatures);
142
143 bool HasFPContract = W.getNamedMD(kSPIR2MD::FPContract);
144 if (EraseOCLMD)
145 B.eraseNamedMD(kSPIR2MD::FPContract);
146
147 // Add entry points
148 auto EP = B.addNamedMD(kSPIRVMD::EntryPoint);
149 auto EM = B.addNamedMD(kSPIRVMD::ExecutionMode);
150
151 // Add execution mode
152 NamedMDNode *KernelMDs = M->getNamedMetadata(SPIR_MD_KERNELS);
153 if (!KernelMDs)
154 return;
155
156 for (unsigned I = 0, E = KernelMDs->getNumOperands(); I < E; ++I) {
157 MDNode *KernelMD = KernelMDs->getOperand(I);
158 if (KernelMD->getNumOperands() == 0)
159 continue;
160 Function *Kernel = mdconst::dyn_extract<Function>(KernelMD->getOperand(0));
161
162 // Workaround for OCL 2.0 producer not using SPIR_KERNEL calling convention
163 #if SPCV_RELAX_KERNEL_CALLING_CONV
164 Kernel->setCallingConv(CallingConv::SPIR_KERNEL);
165 #endif
166
167 MDNode *EPNode;
168 EP.addOp()
169 .add(spv::ExecutionModelKernel)
170 .add(Kernel)
171 .add(Kernel->getName())
172 .done(&EPNode);
173
174 if (!HasFPContract)
175 EM.addOp()
176 .add(Kernel)
177 .add(spv::ExecutionModeContractionOff)
178 .done();
179
180 for (unsigned MI = 1, ME = KernelMD->getNumOperands(); MI < ME; ++MI) {
181 MDNode *MD = dyn_cast<MDNode>(KernelMD->getOperand(MI));
182 if (!MD)
183 continue;
184 MDString *NameMD = dyn_cast<MDString>(MD->getOperand(0));
185 if (!NameMD)
186 continue;
187 StringRef Name = NameMD->getString();
188 if (Name == kSPIR2MD::WGSizeHint) {
189 unsigned X, Y, Z;
190 decodeMDNode(MD, X, Y, Z);
191 EM.addOp()
192 .add(Kernel)
193 .add(spv::ExecutionModeLocalSizeHint)
194 .add(X).add(Y).add(Z)
195 .done();
196 } else if (Name == kSPIR2MD::WGSize) {
197 unsigned X, Y, Z;
198 decodeMDNode(MD, X, Y, Z);
199 EM.addOp()
200 .add(Kernel)
201 .add(spv::ExecutionModeLocalSize)
202 .add(X).add(Y).add(Z)
203 .done();
204 } else if (Name == kSPIR2MD::VecTyHint) {
205 EM.addOp()
206 .add(Kernel)
207 .add(spv::ExecutionModeVecTypeHint)
208 .add(transVecTypeHint(MD))
209 .done();
210 }
211 }
212 }
213 }
214
215 }
216
217 INITIALIZE_PASS(TransOCLMD, "clmdtospv", "Transform OCL metadata to SPIR-V",
218 false, false)
219
createTransOCLMD()220 ModulePass *llvm::createTransOCLMD() {
221 return new TransOCLMD();
222 }
223