• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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