• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- llvm-spirv.cpp - The LLVM/SPIR-V translator utility -----*- C++ -*-===//
2 //
3 //
4 //                     The LLVM/SPIRV Translator
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a
10 // copy of this software and associated documentation files (the "Software"),
11 // to deal with the Software without restriction, including without limitation
12 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 // and/or sell copies of the Software, and to permit persons to whom the
14 // Software is furnished to do so, subject to the following conditions:
15 //
16 // Redistributions of source code must retain the above copyright notice,
17 // this list of conditions and the following disclaimers.
18 // Redistributions in binary form must reproduce the above copyright notice,
19 // this list of conditions and the following disclaimers in the documentation
20 // and/or other materials provided with the distribution.
21 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
22 // contributors may be used to endorse or promote products derived from this
23 // Software without specific prior written permission.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
30 // THE SOFTWARE.
31 //
32 //===----------------------------------------------------------------------===//
33 /// \file
34 ///
35 ///  Common Usage:
36 ///  llvm-spirv          - Read LLVM bitcode from stdin, write SPIRV to stdout
37 ///  llvm-spirv x.bc     - Read LLVM bitcode from the x.bc file, write SPIR-V
38 ///                        to x.bil file
39 ///  llvm-spirv -r       - Read SPIRV from stdin, write LLVM bitcode to stdout
40 ///  llvm-spirv -r x.bil - Read SPIRV from the x.bil file, write SPIR-V to
41 ///                        the x.bc file
42 ///
43 ///  Options:
44 ///      --help   - Output command line options
45 ///
46 //===----------------------------------------------------------------------===//
47 
48 #include "llvm/Bitcode/ReaderWriter.h"
49 #include "llvm/IR/LLVMContext.h"
50 #include "llvm/IR/Module.h"
51 #include "llvm/IR/Verifier.h"
52 #include "llvm/Support/CommandLine.h"
53 #include "llvm/Support/DataStream.h"
54 #include "llvm/Support/Debug.h"
55 #include "llvm/Support/FileSystem.h"
56 #include "llvm/Support/PrettyStackTrace.h"
57 #include "llvm/Support/raw_ostream.h"
58 #include "llvm/Support/Signals.h"
59 #include "llvm/Support/ToolOutputFile.h"
60 
61 #ifndef _SPIRV_SUPPORT_TEXT_FMT
62 #define _SPIRV_SUPPORT_TEXT_FMT
63 #endif
64 
65 #include "llvm/Support/SPIRV.h"
66 
67 #include <memory>
68 #include <fstream>
69 #include <iostream>
70 
71 #define DEBUG_TYPE "spirv"
72 
73 namespace kExt {
74   const char SpirvBinary[] = ".spv";
75   const char SpirvText[] = ".spt";
76   const char LLVMBinary[] = ".bc";
77 }
78 
79 using namespace llvm;
80 
81 static cl::opt<std::string>
82 InputFile(cl::Positional, cl::desc("<input file>"), cl::init("-"));
83 
84 static cl::opt<std::string>
85 OutputFile("o", cl::desc("Override output filename"),
86                cl::value_desc("filename"));
87 
88 static cl::opt<bool>
89 IsReverse("r", cl::desc("Reverse translation (SPIR-V to LLVM)"));
90 
91 static cl::opt<bool>
92 IsRegularization("s", cl::desc(
93     "Regularize LLVM to be representable by SPIR-V"));
94 
95 #ifdef _SPIRV_SUPPORT_TEXT_FMT
96 namespace SPIRV {
97 // Use textual format for SPIRV.
98 extern bool SPIRVUseTextFormat;
99 }
100 
101 static cl::opt<bool>
102 ToText("to-text", cl::desc("Convert input SPIR-V binary to internal textual format"));
103 
104 static cl::opt<bool>
105 ToBinary("to-binary",
106     cl::desc("Convert input SPIR-V in internal textual format to binary"));
107 #endif
108 
109 static std::string
removeExt(const std::string & FileName)110 removeExt(const std::string& FileName) {
111   size_t Pos = FileName.find_last_of(".");
112   if (Pos != std::string::npos)
113     return FileName.substr(0, Pos);
114   return FileName;
115 }
116 
117 static int
convertLLVMToSPIRV()118 convertLLVMToSPIRV() {
119   LLVMContext Context;
120 
121   std::string Err;
122   auto DS = getDataFileStreamer(InputFile, &Err);
123   if (!DS) {
124     errs() << "Fails to open input file: " << Err;
125     return -1;
126   }
127 
128   ErrorOr<std::unique_ptr<Module>> MOrErr =
129       getStreamedBitcodeModule(InputFile, std::move(DS), Context);
130 
131   if (std::error_code EC = MOrErr.getError()) {
132     errs() << "Fails to load bitcode: " << EC.message();
133     return -1;
134   }
135 
136   std::unique_ptr<Module> M = std::move(*MOrErr);
137 
138   if (std::error_code EC = M->materializeAll()){
139     errs() << "Fails to materialize: " << EC.message();
140     return -1;
141   }
142 
143   if (OutputFile.empty()) {
144     if (InputFile == "-")
145       OutputFile = "-";
146     else
147       OutputFile = removeExt(InputFile) +
148                    (SPIRV::SPIRVUseTextFormat ? kExt::SpirvText : kExt::SpirvBinary);
149   }
150 
151   llvm::StringRef outFile(OutputFile);
152   std::error_code EC;
153   llvm::raw_fd_ostream OFS(outFile, EC, llvm::sys::fs::F_None);
154   if (!WriteSPIRV(M.get(), OFS, Err)) {
155     errs() << "Fails to save LLVM as SPIRV: " << Err << '\n';
156     return -1;
157   }
158   return 0;
159 }
160 
161 static int
convertSPIRVToLLVM()162 convertSPIRVToLLVM() {
163   LLVMContext Context;
164   std::ifstream IFS(InputFile, std::ios::binary);
165   Module *M;
166   std::string Err;
167 
168   if (!ReadSPIRV(Context, IFS, M, Err)) {
169     errs() << "Fails to load SPIRV as LLVM Module: " << Err << '\n';
170     return -1;
171   }
172 
173   DEBUG(dbgs() << "Converted LLVM module:\n" << *M);
174 
175 
176   raw_string_ostream ErrorOS(Err);
177   if (verifyModule(*M, &ErrorOS)){
178     errs() << "Fails to verify module: " << ErrorOS.str();
179     return -1;
180   }
181 
182   if (OutputFile.empty()) {
183     if (InputFile == "-")
184       OutputFile = "-";
185     else
186       OutputFile = removeExt(InputFile) + kExt::LLVMBinary;
187   }
188 
189   std::error_code EC;
190   tool_output_file Out(OutputFile.c_str(), EC, sys::fs::F_None);
191   if (EC) {
192     errs() << "Fails to open output file: " << EC.message();
193     return -1;
194   }
195 
196   WriteBitcodeToFile(M, Out.os());
197   Out.keep();
198   delete M;
199   return 0;
200 }
201 
202 #ifdef _SPIRV_SUPPORT_TEXT_FMT
203 static int
convertSPIRV()204 convertSPIRV() {
205   if (ToBinary == ToText) {
206     errs() << "Invalid arguments\n";
207     return -1;
208   }
209   std::ifstream IFS(InputFile, std::ios::binary);
210 
211   if (OutputFile.empty()) {
212     if (InputFile == "-")
213       OutputFile = "-";
214     else {
215       OutputFile = removeExt(InputFile)
216                  + (ToBinary?kExt::SpirvBinary:kExt::SpirvText);
217     }
218   }
219 
220   auto Action = [&](llvm::raw_ostream &OFS) {
221     std::string Err;
222       if (!SPIRV::ConvertSPIRV(IFS, OFS, Err, ToBinary, ToText)) {
223       errs() << "Fails to convert SPIR-V : " << Err << '\n';
224       return -1;
225     }
226     return 0;
227   };
228   if (OutputFile != "-") {
229     std::error_code EC;
230     llvm::raw_fd_ostream OFS(llvm::StringRef(OutputFile), EC, llvm::sys::fs::F_None);
231     return Action(OFS);
232   } else
233     return Action(outs());
234 }
235 #endif
236 
237 static int
regularizeLLVM()238 regularizeLLVM() {
239   LLVMContext Context;
240 
241   std::string Err;
242   auto DS = getDataFileStreamer(InputFile, &Err);
243   if (!DS) {
244     errs() << "Fails to open input file: " << Err;
245     return -1;
246   }
247 
248   ErrorOr<std::unique_ptr<Module>> MOrErr =
249       getStreamedBitcodeModule(InputFile, std::move(DS), Context);
250 
251   if (std::error_code EC = MOrErr.getError()) {
252     errs() << "Fails to load bitcode: " << EC.message();
253     return -1;
254   }
255 
256   std::unique_ptr<Module> M = std::move(*MOrErr);
257 
258   if (std::error_code EC = M->materializeAll()){
259     errs() << "Fails to materialize: " << EC.message();
260     return -1;
261   }
262 
263   if (OutputFile.empty()) {
264     if (InputFile == "-")
265       OutputFile = "-";
266     else
267       OutputFile = removeExt(InputFile) + ".regularized.bc";
268   }
269 
270   if (!RegularizeLLVMForSPIRV(M.get(), Err)) {
271     errs() << "Fails to save LLVM as SPIRV: " << Err << '\n';
272     return -1;
273   }
274 
275   std::error_code EC;
276   tool_output_file Out(OutputFile.c_str(), EC, sys::fs::F_None);
277   if (EC) {
278     errs() << "Fails to open output file: " << EC.message();
279     return -1;
280   }
281 
282   WriteBitcodeToFile(M.get(), Out.os());
283   Out.keep();
284   return 0;
285 }
286 
287 
288 int
main(int ac,char ** av)289 main(int ac, char** av) {
290   EnablePrettyStackTrace();
291   sys::PrintStackTraceOnErrorSignal(av[0]);
292   PrettyStackTraceProgram X(ac, av);
293 
294   cl::ParseCommandLineOptions(ac, av, "LLVM/SPIR-V translator");
295 
296 #ifdef _SPIRV_SUPPORT_TEXT_FMT
297   if (ToText && (ToBinary || IsReverse || IsRegularization)) {
298     errs() << "Cannot use -to-text with -to-binary, -r, -s\n";
299     return -1;
300   }
301 
302   if (ToBinary && (ToText || IsReverse || IsRegularization)) {
303     errs() << "Cannot use -to-binary with -to-text, -r, -s\n";
304     return -1;
305   }
306 
307   if (ToBinary || ToText)
308     return convertSPIRV();
309 #endif
310 
311   if (!IsReverse && !IsRegularization)
312     return convertLLVMToSPIRV();
313 
314   if (IsReverse && IsRegularization) {
315     errs() << "Cannot have both -r and -s options\n";
316     return -1;
317   }
318   if (IsReverse)
319     return convertSPIRVToLLVM();
320 
321   if (IsRegularization)
322     return regularizeLLVM();
323 
324   return 0;
325 }
326