1 /* 2 * Copyright 2016, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "RSSPIRVWriter.h" 18 #include "bcinfo/MetadataExtractor.h" 19 #include "spirit/file_utils.h" 20 21 #include "llvm/Bitcode/ReaderWriter.h" 22 #include "llvm/IR/LegacyPassManager.h" 23 #include "llvm/IR/LLVMContext.h" 24 #include "llvm/IR/Module.h" 25 #include "llvm/Support/CommandLine.h" 26 #include "llvm/Support/DataStream.h" 27 #include "llvm/Support/Debug.h" 28 #include "llvm/Support/FileSystem.h" 29 #include "llvm/Support/PrettyStackTrace.h" 30 #include "llvm/Support/Signals.h" 31 #include "llvm/Support/ToolOutputFile.h" 32 #include "llvm/Support/raw_ostream.h" 33 34 #include "Context.h" 35 #include "GlobalMergePass.h" 36 #include "RSSPIRVWriter.h" 37 38 #define DEBUG_TYPE "rs2spirv" 39 40 namespace kExt { 41 const char SPIRVBinary[] = ".spv"; 42 } // namespace kExt 43 44 using namespace llvm; 45 46 static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"), 47 cl::init("-")); 48 49 static cl::opt<std::string> OutputFile("o", 50 cl::desc("Override output filename"), 51 cl::value_desc("filename")); 52 53 static cl::opt<std::string> OutputBitcodeFile("bc", 54 cl::desc("Override output bitcode filename"), 55 cl::value_desc("bitcode filename")); 56 57 static std::string removeExt(const std::string &FileName) { 58 size_t Pos = FileName.find_last_of("."); 59 if (Pos != std::string::npos) 60 return FileName.substr(0, Pos); 61 return FileName; 62 } 63 64 static bool WriteBitcode(rs2spirv::Context &Ctxt, Module *M, 65 raw_ostream &OS, std::string &ErrMsg) { 66 llvm::legacy::PassManager PassMgr; 67 PassMgr.add(rs2spirv::createGlobalMergePass(true)); 68 PassMgr.run(*M); 69 70 WriteBitcodeToFile(M, OS); 71 72 return true; 73 } 74 75 static int convertLLVMToSPIRV() { 76 LLVMContext Context; 77 78 std::string Err; 79 auto DS = getDataFileStreamer(InputFile, &Err); 80 if (!DS) { 81 errs() << "Fails to open input file: " << Err; 82 return -1; 83 } 84 ErrorOr<std::unique_ptr<Module>> MOrErr = 85 getStreamedBitcodeModule(InputFile, std::move(DS), Context); 86 87 if (std::error_code EC = MOrErr.getError()) { 88 errs() << "Fails to load bitcode: " << EC.message(); 89 return -1; 90 } 91 92 std::unique_ptr<Module> M = std::move(*MOrErr); 93 94 if (std::error_code EC = M->materializeAll()) { 95 errs() << "Fails to materialize: " << EC.message(); 96 return -1; 97 } 98 99 std::error_code EC; 100 101 std::vector<char> bitcode = android::spirit::readFile<char>(InputFile); 102 std::unique_ptr<bcinfo::MetadataExtractor> ME( 103 new bcinfo::MetadataExtractor(bitcode.data(), bitcode.size())); 104 105 rs2spirv::Context &Ctxt = rs2spirv::Context::getInstance(); 106 107 if (!Ctxt.Initialize(std::move(ME))) { 108 return -2; 109 } 110 111 if (!OutputBitcodeFile.empty()) { 112 llvm::StringRef outBCFile(OutputBitcodeFile); 113 llvm::raw_fd_ostream OFS_BC(outBCFile, EC, llvm::sys::fs::F_None); 114 if (!WriteBitcode(Ctxt, M.get(), OFS_BC, Err)) { 115 errs() << "compiler error: " << Err << '\n'; 116 return -3; 117 } 118 return 0; 119 } 120 121 if (OutputFile.empty()) { 122 if (InputFile == "-") 123 OutputFile = "-"; 124 else 125 OutputFile = removeExt(InputFile) + kExt::SPIRVBinary; 126 } 127 128 llvm::StringRef outFile(OutputFile); 129 llvm::raw_fd_ostream OFS(outFile, EC, llvm::sys::fs::F_None); 130 131 if (!rs2spirv::WriteSPIRV(Ctxt, M.get(), OFS, Err)) { 132 errs() << "compiler error: " << Err << '\n'; 133 return -4; 134 } 135 136 return 0; 137 } 138 139 int main(int ac, char **av) { 140 EnablePrettyStackTrace(); 141 sys::PrintStackTraceOnErrorSignal(av[0]); 142 PrettyStackTraceProgram X(ac, av); 143 144 cl::ParseCommandLineOptions(ac, av, "RenderScript to SPIRV translator"); 145 146 return convertLLVMToSPIRV(); 147 } 148