Home | History | Annotate | Download | only in compiler
      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