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 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 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 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 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 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 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