Allow for all options in CompileFromSourceString (#823)
Shares core logic between Compile and CompileFromSourceString to
allow for some previously unsupported options in
CompileFromSourceString such as support for input languages
other than OpenCL and outputting to a file.
diff --git a/lib/Compiler.cpp b/lib/Compiler.cpp
index d8d4da3..959a6b9 100644
--- a/lib/Compiler.cpp
+++ b/lib/Compiler.cpp
@@ -412,12 +412,11 @@
}
// Sets |instance|'s options for compiling. Returns 0 if successful.
-int SetCompilerInstanceOptions(CompilerInstance &instance,
- const llvm::StringRef &overiddenInputFilename,
- const clang::FrontendInputFile &kernelFile,
- const std::string &program,
- llvm::raw_string_ostream *diagnosticsStream) {
- std::unique_ptr<llvm::MemoryBuffer> memory_buffer(nullptr);
+int SetCompilerInstanceOptions(
+ CompilerInstance &instance, const llvm::StringRef &overiddenInputFilename,
+ clang::FrontendInputFile &kernelFile, const std::string &program,
+ std::unique_ptr<llvm::MemoryBuffer> &file_memory_buffer,
+ llvm::raw_string_ostream *diagnosticsStream) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
if (program.empty()) {
auto errorOrInputFile =
@@ -429,10 +428,10 @@
<< InputFilename.getValue() << "'\n";
return -1;
}
- memory_buffer.reset(errorOrInputFile.get().release());
+ file_memory_buffer = std::move(errorOrInputFile.get());
} else {
- memory_buffer = llvm::MemoryBuffer::getMemBuffer(program.c_str(),
- overiddenInputFilename);
+ file_memory_buffer =
+ llvm::MemoryBuffer::getMemBuffer(program, overiddenInputFilename);
}
if (verify) {
@@ -550,9 +549,15 @@
instance.getCodeGenOpts().PreserveVec3Type = true;
// Disable generation of lifetime intrinsic.
instance.getCodeGenOpts().DisableLifetimeMarkers = true;
+ if (InputLanguage == clang::Language::OpenCL) {
+ instance.getPreprocessorOpts().addRemappedFile(
+ overiddenInputFilename, file_memory_buffer.release());
+ } else if (!program.empty()) {
+ // Can't use preprocessor to do file remapping for LLVM_IR
+ kernelFile = clang::FrontendInputFile(*file_memory_buffer,
+ clang::InputKind(InputLanguage));
+ }
instance.getFrontendOpts().Inputs.push_back(kernelFile);
- instance.getPreprocessorOpts().addRemappedFile(overiddenInputFilename,
- memory_buffer.release());
std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
@@ -939,42 +944,24 @@
} // namespace
namespace clspv {
-int Compile(const int argc, const char *const argv[]) {
-
- if (auto error = ParseOptions(argc, argv))
- return error;
-
+int Compile(const llvm::StringRef &input_filename, const std::string &program,
+ const std::string &sampler_map,
+ std::vector<uint32_t> *output_binary, std::string *output_log) {
llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
- if (auto error = ParseSamplerMap("", &SamplerMapEntries))
+ if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
return error;
- // if no output file was provided, use a default
- llvm::StringRef overiddenInputFilename = InputFilename.getValue();
-
- // If we are reading our input file from stdin.
- if ("-" == InputFilename) {
- // We need to overwrite the file name we use.
- switch (InputLanguage) {
- case clang::Language::OpenCL:
- overiddenInputFilename = "stdin.cl";
- break;
- case clang::Language::LLVM_IR:
- overiddenInputFilename = "stdin.ll";
- break;
- default:
- // Default to fix compiler warnings/errors. Option parsing will reject a
- // bad enum value for the option so there is no need for a message.
- return -1;
- }
- }
+ llvm::StringRef overiddenInputFilename = input_filename;
clang::CompilerInstance instance;
clang::FrontendInputFile kernelFile(overiddenInputFilename,
clang::InputKind(InputLanguage));
std::string log;
llvm::raw_string_ostream diagnosticsStream(log);
+ std::unique_ptr<llvm::MemoryBuffer> file_memory_buffer;
if (auto error = SetCompilerInstanceOptions(
- instance, overiddenInputFilename, kernelFile, "", &diagnosticsStream))
+ instance, overiddenInputFilename, kernelFile, program,
+ file_memory_buffer, &diagnosticsStream))
return error;
// Parse.
@@ -996,7 +983,9 @@
auto num_warnings = consumer->getNumWarnings();
auto num_errors = consumer->getNumErrors();
- if ((num_errors > 0) || (num_warnings > 0)) {
+ if (output_log != nullptr) {
+ *output_log = log;
+ } else if ((num_errors > 0) || (num_warnings > 0)) {
llvm::errs() << log;
}
if (result || num_errors > 0) {
@@ -1036,12 +1025,54 @@
return error;
pm.run(*module);
- // Write outputs
- std::error_code error;
-
// Write the resulting binary.
// Wait until now to try writing the file so that we only write it on
// successful compilation.
+ if (output_binary) {
+ output_binary->resize(binary.size() / 4);
+ memcpy(output_binary->data(), binary.data(), binary.size());
+ }
+
+ if (!OutputFilename.empty()) {
+ std::error_code error;
+ llvm::raw_fd_ostream outStream(OutputFilename, error,
+ llvm::sys::fs::FA_Write);
+
+ if (error) {
+ llvm::errs() << "Unable to open output file '" << OutputFilename
+ << "': " << error.message() << '\n';
+ return -1;
+ }
+ outStream << binaryStream.str();
+ }
+
+ return 0;
+}
+
+int Compile(const int argc, const char *const argv[]) {
+ if (auto error = ParseOptions(argc, argv))
+ return error;
+
+ // if no input file was provided, use a default
+ llvm::StringRef overiddenInputFilename = InputFilename.getValue();
+
+ // If we are reading our input file from stdin.
+ if ("-" == InputFilename) {
+ // We need to overwrite the file name we use.
+ switch (InputLanguage) {
+ case clang::Language::OpenCL:
+ overiddenInputFilename = "stdin.cl";
+ break;
+ case clang::Language::LLVM_IR:
+ overiddenInputFilename = "stdin.ll";
+ break;
+ default:
+ // Default to fix compiler warnings/errors. Option parsing will reject a
+ // bad enum value for the option so there is no need for a message.
+ return -1;
+ }
+ }
+
if (OutputFilename.empty()) {
if (OutputFormat == "c") {
OutputFilename = "a.spvinc";
@@ -1049,17 +1080,8 @@
OutputFilename = "a.spv";
}
}
- llvm::raw_fd_ostream outStream(OutputFilename, error,
- llvm::sys::fs::FA_Write);
- if (error) {
- llvm::errs() << "Unable to open output file '" << OutputFilename
- << "': " << error.message() << '\n';
- return -1;
- }
- outStream << binaryStream.str();
-
- return 0;
+ return Compile(overiddenInputFilename, "", "", nullptr, nullptr);
}
int CompileFromSourceString(const std::string &program,
@@ -1078,80 +1100,6 @@
if (auto error = ParseOptions(argc, &argv[0]))
return error;
- llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
- if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
- return error;
-
- InputFilename = "source.cl";
- llvm::StringRef overiddenInputFilename = InputFilename.getValue();
-
- clang::CompilerInstance instance;
- clang::FrontendInputFile kernelFile(
- overiddenInputFilename, clang::InputKind(clang::Language::OpenCL));
- std::string log;
- llvm::raw_string_ostream diagnosticsStream(log);
- if (auto error =
- SetCompilerInstanceOptions(instance, overiddenInputFilename,
- kernelFile, program, &diagnosticsStream))
- return error;
-
- // Parse.
- llvm::LLVMContext context;
- clang::EmitLLVMOnlyAction action(&context);
-
- // Prepare the action for processing kernelFile
- const bool success = action.BeginSourceFile(instance, kernelFile);
- if (!success) {
- return -1;
- }
-
- auto result = action.Execute();
- action.EndSourceFile();
-
- clang::DiagnosticConsumer *const consumer =
- instance.getDiagnostics().getClient();
- consumer->finish();
-
- if (output_log != nullptr) {
- *output_log = log;
- }
-
- auto num_errors = consumer->getNumErrors();
- if (result || num_errors > 0) {
- return -1;
- }
-
- llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
- llvm::initializeCore(Registry);
- llvm::initializeScalarOpts(Registry);
- llvm::initializeClspvPasses(Registry);
-
- std::unique_ptr<llvm::Module> module(action.takeModule());
-
- if (!LinkBuiltinLibrary(module.get())) {
- return -1;
- }
-
- // Optimize.
- // Create a memory buffer for temporarily writing the result.
- SmallVector<char, 10000> binary;
- llvm::raw_svector_ostream binaryStream(binary);
- llvm::legacy::PassManager pm;
- if (auto error = PopulatePassManager(&pm, &binaryStream, &SamplerMapEntries))
- return error;
- pm.run(*module);
-
- // Write the resulting binary.
- // Wait until now to try writing the file so that we only write it on
- // successful compilation.
- assert(output_binary && "Valid binary container is required.");
- if (!OutputFilename.empty()) {
- llvm::outs()
- << "Warning: -o is ignored when binary container is provided.\n";
- }
- output_binary->resize(binary.size() / 4);
- memcpy(output_binary->data(), binary.data(), binary.size());
-
- return 0;
+ return Compile("source", program, sampler_map, output_binary, output_log);
}
} // namespace clspv