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/LLVMContext.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Support/CommandLine.h"
25#include "llvm/Support/DataStream.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/FileSystem.h"
28#include "llvm/Support/PrettyStackTrace.h"
29#include "llvm/Support/Signals.h"
30#include "llvm/Support/ToolOutputFile.h"
31#include "llvm/Support/raw_ostream.h"
32
33#define DEBUG_TYPE "rs2spirv"
34
35namespace kExt {
36const char SPIRVBinary[] = ".spv";
37} // namespace kExt
38
39using namespace llvm;
40
41static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"),
42                                      cl::init("-"));
43
44static cl::opt<std::string> OutputFile("o",
45                                       cl::desc("Override output filename"),
46                                       cl::value_desc("filename"));
47
48static std::string removeExt(const std::string &FileName) {
49  size_t Pos = FileName.find_last_of(".");
50  if (Pos != std::string::npos)
51    return FileName.substr(0, Pos);
52  return FileName;
53}
54
55static int convertLLVMToSPIRV() {
56  LLVMContext Context;
57
58  std::string Err;
59  auto DS = getDataFileStreamer(InputFile, &Err);
60  if (!DS) {
61    errs() << "Fails to open input file: " << Err;
62    return -1;
63  }
64  ErrorOr<std::unique_ptr<Module>> MOrErr =
65      getStreamedBitcodeModule(InputFile, std::move(DS), Context);
66
67  if (std::error_code EC = MOrErr.getError()) {
68    errs() << "Fails to load bitcode: " << EC.message();
69    return -1;
70  }
71
72  std::unique_ptr<Module> M = std::move(*MOrErr);
73
74  if (std::error_code EC = M->materializeAll()) {
75    errs() << "Fails to materialize: " << EC.message();
76    return -1;
77  }
78
79  if (OutputFile.empty()) {
80    if (InputFile == "-")
81      OutputFile = "-";
82    else
83      OutputFile = removeExt(InputFile) + kExt::SPIRVBinary;
84  }
85
86  llvm::StringRef outFile(OutputFile);
87  std::error_code EC;
88  llvm::raw_fd_ostream OFS(outFile, EC, llvm::sys::fs::F_None);
89
90  std::vector<char> bitcode = android::spirit::readFile<char>(InputFile);
91  std::unique_ptr<bcinfo::MetadataExtractor> ME(
92      new bcinfo::MetadataExtractor(bitcode.data(), bitcode.size()));
93
94  if (!rs2spirv::WriteSPIRV(M.get(), std::move(ME), OFS, Err)) {
95    errs() << "compiler error: " << Err << '\n';
96    return -1;
97  }
98
99  return 0;
100}
101
102int main(int ac, char **av) {
103  EnablePrettyStackTrace();
104  sys::PrintStackTraceOnErrorSignal(av[0]);
105  PrettyStackTraceProgram X(ac, av);
106
107  cl::ParseCommandLineOptions(ac, av, "RenderScript to SPIRV translator");
108
109  return convertLLVMToSPIRV();
110}
111