Add API to compile from source string (#244)
* Added new API to compile a program from a string
* will not generate output files using the options
* modified build system to work as a linked in library
* added ability to specify sampler map as a string
* added ability to output binary to a vector
* Added data structure for descriptor map entries
* New exported header DescriptorMap.h
* Data structure to represent descriptor map entries
* ostream operator produces lines of descriptor map file
* Refactored ArgKind enum into exported header
* added PodUBO
* Needs to be integrated more cleanly
* Replaced generation of descriptor map to use new data structures
* vector populated in SPIRVProducerPass
* compile functions stream into the file
The clspv executable continues to function as before.
diff --git a/lib/Compiler.cpp b/lib/Compiler.cpp
index 178bc9c..e103007 100644
--- a/lib/Compiler.cpp
+++ b/lib/Compiler.cpp
@@ -23,19 +23,25 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/LinkAllPasses.h"
+#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/StringSaver.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "clspv/DescriptorMap.h"
#include "clspv/Option.h"
#include "clspv/Passes.h"
#include "clspv/opencl_builtins_header.h"
#include "FrontendPlugin.h"
+#include <cassert>
#include <numeric>
#include <string>
+#include <sstream>
using namespace clang;
@@ -151,8 +157,20 @@
// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
// if successful.
-int ParseSamplerMap(llvm::SmallVectorImpl<std::pair<unsigned, std::string>> *SamplerMapEntries) {
- if (!SamplerMap.empty()) {
+int ParseSamplerMap(const std::string &sampler_map,
+ llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
+ *SamplerMapEntries) {
+ std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
+ if (!sampler_map.empty()) {
+ // Parse the sampler map from the provided string.
+ samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
+
+ if (!SamplerMap.empty()) {
+ llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
+ "provided through a string.\n";
+ }
+ } else if (!SamplerMap.empty()) {
+ // Parse the sampler map from the option provided file.
auto errorOrSamplerMapFile =
llvm::MemoryBuffer::getFile(SamplerMap.getValue());
@@ -163,164 +181,169 @@
return -1;
}
- auto samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
-
+ samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
if (0 == samplerMapBuffer->getBufferSize()) {
llvm::errs() << "Error: Sampler map was an empty file!\n";
return -1;
}
+ }
- llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
+ // No sampler map to parse.
+ if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
+ return 0;
- // We need to keep track of the beginning of the current entry.
- const char *b = samplerMapBuffer->getBufferStart();
- for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
- // If we have a separator between declarations.
- if ((*i == '|') || (*i == ',') || (i == e)) {
- if (i == b) {
- llvm::errs() << "Error: Sampler map contained an empty entry!\n";
- return -1;
- }
+ llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
- samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
-
- // And set b the next character after i.
- b = i + 1;
+ // We need to keep track of the beginning of the current entry.
+ const char *b = samplerMapBuffer->getBufferStart();
+ for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
+ // If we have a separator between declarations.
+ if ((*i == '|') || (*i == ',') || (i == e)) {
+ if (i == b) {
+ llvm::errs() << "Error: Sampler map contained an empty entry!\n";
+ return -1;
}
- // If we have a separator between declarations within a single sampler.
- if ((*i == ',') || (i == e)) {
- enum NormalizedCoords {
- CLK_NORMALIZED_COORDS_FALSE = 0x00,
- CLK_NORMALIZED_COORDS_TRUE = 0x01,
- CLK_NORMALIZED_COORDS_NOT_SET
- } NormalizedCoord = CLK_NORMALIZED_COORDS_NOT_SET;
+ samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
- enum AddressingModes {
- CLK_ADDRESS_NONE = 0x00,
- CLK_ADDRESS_CLAMP_TO_EDGE = 0x02,
- CLK_ADDRESS_CLAMP = 0x04,
- CLK_ADDRESS_MIRRORED_REPEAT = 0x08,
- CLK_ADDRESS_REPEAT = 0x06,
- CLK_ADDRESS_NOT_SET
- } AddressingMode = CLK_ADDRESS_NOT_SET;
+ // And set b the next character after i.
+ b = i + 1;
+ }
- enum FilterModes {
- CLK_FILTER_NEAREST = 0x10,
- CLK_FILTER_LINEAR = 0x20,
- CLK_FILTER_NOT_SET
- } FilterMode = CLK_FILTER_NOT_SET;
+ // If we have a separator between declarations within a single sampler.
+ if ((*i == ',') || (i == e)) {
+ enum NormalizedCoords {
+ CLK_NORMALIZED_COORDS_FALSE = 0x00,
+ CLK_NORMALIZED_COORDS_TRUE = 0x01,
+ CLK_NORMALIZED_COORDS_NOT_SET
+ } NormalizedCoord = CLK_NORMALIZED_COORDS_NOT_SET;
- for (auto str : samplerStrings) {
- if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
- if (CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
- llvm::errs() << "Error: Sampler map normalized coordinates was "
- "previously set!\n";
- return -1;
- }
- NormalizedCoord = CLK_NORMALIZED_COORDS_FALSE;
- } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
- if (CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
- llvm::errs() << "Error: Sampler map normalized coordinates was "
- "previously set!\n";
- return -1;
- }
- NormalizedCoord = CLK_NORMALIZED_COORDS_TRUE;
- } else if ("CLK_ADDRESS_NONE" == str) {
- if (CLK_ADDRESS_NOT_SET != AddressingMode) {
- llvm::errs()
- << "Error: Sampler map addressing mode was previously set!\n";
- return -1;
- }
- AddressingMode = CLK_ADDRESS_NONE;
- } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
- if (CLK_ADDRESS_NOT_SET != AddressingMode) {
- llvm::errs()
- << "Error: Sampler map addressing mode was previously set!\n";
- return -1;
- }
- AddressingMode = CLK_ADDRESS_CLAMP_TO_EDGE;
- } else if ("CLK_ADDRESS_CLAMP" == str) {
- if (CLK_ADDRESS_NOT_SET != AddressingMode) {
- llvm::errs()
- << "Error: Sampler map addressing mode was previously set!\n";
- return -1;
- }
- AddressingMode = CLK_ADDRESS_CLAMP;
- } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
- if (CLK_ADDRESS_NOT_SET != AddressingMode) {
- llvm::errs()
- << "Error: Sampler map addressing mode was previously set!\n";
- return -1;
- }
- AddressingMode = CLK_ADDRESS_MIRRORED_REPEAT;
- } else if ("CLK_ADDRESS_REPEAT" == str) {
- if (CLK_ADDRESS_NOT_SET != AddressingMode) {
- llvm::errs()
- << "Error: Sampler map addressing mode was previously set!\n";
- return -1;
- }
- AddressingMode = CLK_ADDRESS_REPEAT;
- } else if ("CLK_FILTER_NEAREST" == str) {
- if (CLK_FILTER_NOT_SET != FilterMode) {
- llvm::errs()
- << "Error: Sampler map filtering mode was previously set!\n";
- return -1;
- }
- FilterMode = CLK_FILTER_NEAREST;
- } else if ("CLK_FILTER_LINEAR" == str) {
- if (CLK_FILTER_NOT_SET != FilterMode) {
- llvm::errs()
- << "Error: Sampler map filtering mode was previously set!\n";
- return -1;
- }
- FilterMode = CLK_FILTER_LINEAR;
- } else {
- llvm::errs() << "Error: Unknown sampler string '" << str
- << "' found!\n";
+ enum AddressingModes {
+ CLK_ADDRESS_NONE = 0x00,
+ CLK_ADDRESS_CLAMP_TO_EDGE = 0x02,
+ CLK_ADDRESS_CLAMP = 0x04,
+ CLK_ADDRESS_MIRRORED_REPEAT = 0x08,
+ CLK_ADDRESS_REPEAT = 0x06,
+ CLK_ADDRESS_NOT_SET
+ } AddressingMode = CLK_ADDRESS_NOT_SET;
+
+ enum FilterModes {
+ CLK_FILTER_NEAREST = 0x10,
+ CLK_FILTER_LINEAR = 0x20,
+ CLK_FILTER_NOT_SET
+ } FilterMode = CLK_FILTER_NOT_SET;
+
+ for (auto str : samplerStrings) {
+ if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
+ if (CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
+ llvm::errs() << "Error: Sampler map normalized coordinates was "
+ "previously set!\n";
return -1;
}
- }
-
- if (CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
- llvm::errs() << "Error: Sampler map entry did not contain normalized "
- "coordinates entry!\n";
+ NormalizedCoord = CLK_NORMALIZED_COORDS_FALSE;
+ } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
+ if (CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
+ llvm::errs() << "Error: Sampler map normalized coordinates was "
+ "previously set!\n";
+ return -1;
+ }
+ NormalizedCoord = CLK_NORMALIZED_COORDS_TRUE;
+ } else if ("CLK_ADDRESS_NONE" == str) {
+ if (CLK_ADDRESS_NOT_SET != AddressingMode) {
+ llvm::errs()
+ << "Error: Sampler map addressing mode was previously set!\n";
+ return -1;
+ }
+ AddressingMode = CLK_ADDRESS_NONE;
+ } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
+ if (CLK_ADDRESS_NOT_SET != AddressingMode) {
+ llvm::errs()
+ << "Error: Sampler map addressing mode was previously set!\n";
+ return -1;
+ }
+ AddressingMode = CLK_ADDRESS_CLAMP_TO_EDGE;
+ } else if ("CLK_ADDRESS_CLAMP" == str) {
+ if (CLK_ADDRESS_NOT_SET != AddressingMode) {
+ llvm::errs()
+ << "Error: Sampler map addressing mode was previously set!\n";
+ return -1;
+ }
+ AddressingMode = CLK_ADDRESS_CLAMP;
+ } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
+ if (CLK_ADDRESS_NOT_SET != AddressingMode) {
+ llvm::errs()
+ << "Error: Sampler map addressing mode was previously set!\n";
+ return -1;
+ }
+ AddressingMode = CLK_ADDRESS_MIRRORED_REPEAT;
+ } else if ("CLK_ADDRESS_REPEAT" == str) {
+ if (CLK_ADDRESS_NOT_SET != AddressingMode) {
+ llvm::errs()
+ << "Error: Sampler map addressing mode was previously set!\n";
+ return -1;
+ }
+ AddressingMode = CLK_ADDRESS_REPEAT;
+ } else if ("CLK_FILTER_NEAREST" == str) {
+ if (CLK_FILTER_NOT_SET != FilterMode) {
+ llvm::errs()
+ << "Error: Sampler map filtering mode was previously set!\n";
+ return -1;
+ }
+ FilterMode = CLK_FILTER_NEAREST;
+ } else if ("CLK_FILTER_LINEAR" == str) {
+ if (CLK_FILTER_NOT_SET != FilterMode) {
+ llvm::errs()
+ << "Error: Sampler map filtering mode was previously set!\n";
+ return -1;
+ }
+ FilterMode = CLK_FILTER_LINEAR;
+ } else {
+ llvm::errs() << "Error: Unknown sampler string '" << str
+ << "' found!\n";
return -1;
}
-
- if (CLK_ADDRESS_NOT_SET == AddressingMode) {
- llvm::errs() << "Error: Sampler map entry did not contain addressing "
- "mode entry!\n";
- return -1;
- }
-
- if (CLK_FILTER_NOT_SET == FilterMode) {
- llvm::errs()
- << "Error: Sampler map entry did not contain filer mode entry!\n";
- return -1;
- }
-
- // Generate an equivalent expression in string form. Sort the
- // strings to get a canonical ordering.
- std::sort(samplerStrings.begin(), samplerStrings.end(),
- std::less<StringRef>());
- const auto samplerExpr = std::accumulate(
- samplerStrings.begin(), samplerStrings.end(), std::string(),
- [](std::string left, std::string right) {
- return left + std::string(left.empty() ? "" : "|") + right;
- });
-
- SamplerMapEntries->emplace_back(
- NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
-
- // And reset the sampler strings for the next sampler in the map.
- samplerStrings.clear();
}
- // And lastly, if we are at the end of the file
- if (i == e) {
- break;
+ if (CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
+ llvm::errs() << "Error: Sampler map entry did not contain normalized "
+ "coordinates entry!\n";
+ return -1;
}
+
+ if (CLK_ADDRESS_NOT_SET == AddressingMode) {
+ llvm::errs() << "Error: Sampler map entry did not contain addressing "
+ "mode entry!\n";
+ return -1;
+ }
+
+ if (CLK_FILTER_NOT_SET == FilterMode) {
+ llvm::errs()
+ << "Error: Sampler map entry did not contain filer mode entry!\n";
+ return -1;
+ }
+
+ // Generate an equivalent expression in string form. Sort the
+ // strings to get a canonical ordering.
+ std::sort(samplerStrings.begin(), samplerStrings.end(),
+ std::less<StringRef>());
+ const auto samplerExpr = std::accumulate(
+ samplerStrings.begin(), samplerStrings.end(), std::string(),
+ [](std::string left, std::string right) {
+ return left + std::string(left.empty() ? "" : "|") + right;
+ });
+
+ // SamplerMapEntries->push_back(std::make_pair(
+ // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
+ SamplerMapEntries->emplace_back(
+ NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
+
+ // And reset the sampler strings for the next sampler in the map.
+ samplerStrings.clear();
+ }
+
+ // And lastly, if we are at the end of the file
+ if (i == e) {
+ break;
}
}
@@ -331,16 +354,26 @@
int SetCompilerInstanceOptions(CompilerInstance &instance,
const llvm::StringRef &overiddenInputFilename,
const clang::FrontendInputFile &kernelFile,
+ const std::string &program,
llvm::raw_string_ostream *diagnosticsStream) {
- auto errorOrInputFile =
- llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
+ std::unique_ptr<llvm::MemoryBuffer> memory_buffer(nullptr);
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
+ if (program.empty()) {
+ auto errorOrInputFile =
+ llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
- // If there was an error in getting the input file.
- if (!errorOrInputFile) {
- llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
- << InputFilename.getValue() << "'\n";
- return -1;
+ // If there was an error in getting the input file.
+ if (!errorOrInputFile) {
+ llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
+ << InputFilename.getValue() << "'\n";
+ return -1;
+ }
+ memory_buffer.reset(errorOrInputFile.get().release());
+ } else {
+ memory_buffer = llvm::MemoryBuffer::getMemBuffer(program.c_str(),
+ overiddenInputFilename);
}
+
if (verify) {
instance.getDiagnosticOpts().VerifyDiagnostics = true;
}
@@ -425,8 +458,10 @@
// Disable generation of lifetime intrinsic.
instance.getCodeGenOpts().DisableLifetimeMarkers = true;
instance.getFrontendOpts().Inputs.push_back(kernelFile);
- instance.getPreprocessorOpts().addRemappedFile(
- overiddenInputFilename, errorOrInputFile.get().release());
+ // instance.getPreprocessorOpts().addRemappedFile(
+ // overiddenInputFilename, errorOrInputFile.get().release());
+ instance.getPreprocessorOpts().addRemappedFile(overiddenInputFilename,
+ memory_buffer.release());
struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
@@ -476,16 +511,30 @@
return 0;
}
-// Populates |pm| with necessary passes to optimize and legalize the IR.
-void PopulatePassManager(llvm::legacy::PassManager *pm,
- llvm::raw_svector_ostream *binaryStream,
- llvm::raw_string_ostream *descriptor_map_out,
- llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
- *SamplerMapEntries) {
+// Populates |pm| with necessary passes to optimize and legalize the IR.
+int PopulatePassManager(
+ llvm::legacy::PassManager *pm, llvm::raw_svector_ostream *binaryStream,
+ std::vector<clspv::version0::DescriptorMapEntry> *descriptor_map_entries,
+ llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
+ *SamplerMapEntries) {
llvm::PassManagerBuilder pmBuilder;
switch (OptimizationLevel) {
case '0':
+ case '1':
+ case '2':
+ case '3':
+ case 's':
+ case 'z':
+ break;
+ default:
+ llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
+ << " specified!\n";
+ return -1;
+ }
+
+ switch (OptimizationLevel) {
+ case '0':
pmBuilder.OptLevel = 0;
break;
case '1':
@@ -602,8 +651,10 @@
// anymore so leave this right before SPIR-V generation.
pm->add(clspv::createUBOTypeTransformPass());
pm->add(clspv::createSPIRVProducerPass(
- *binaryStream, *descriptor_map_out, *SamplerMapEntries,
+ *binaryStream, descriptor_map_entries, *SamplerMapEntries,
OutputAssembly.getValue(), OutputFormat == "c"));
+
+ return 0;
}
} // namespace
@@ -613,29 +664,16 @@
// ParseCommandLineOptions with the specific option.
const int llvmArgc = 2;
const char *llvmArgv[llvmArgc] = {
- argv[0], "-simplifycfg-sink-common=false",
+ argv[0],
+ "-simplifycfg-sink-common=false",
};
llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
llvm::cl::ParseCommandLineOptions(argc, argv);
- switch (OptimizationLevel) {
- case '0':
- case '1':
- case '2':
- case '3':
- case 's':
- case 'z':
- break;
- default:
- llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
- << " specified!\n";
- return -1;
- }
-
llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
- if (auto error = ParseSamplerMap(&SamplerMapEntries))
+ if (auto error = ParseSamplerMap("", &SamplerMapEntries))
return error;
// if no output file was provided, use a default
@@ -652,8 +690,8 @@
clang::InputKind::OpenCL);
std::string log;
llvm::raw_string_ostream diagnosticsStream(log);
- if (auto error = SetCompilerInstanceOptions(instance, overiddenInputFilename,
- kernelFile, &diagnosticsStream))
+ if (auto error = SetCompilerInstanceOptions(
+ instance, overiddenInputFilename, kernelFile, "", &diagnosticsStream))
return error;
// Parse.
@@ -697,10 +735,12 @@
SmallVector<char, 10000> binary;
llvm::raw_svector_ostream binaryStream(binary);
std::string descriptor_map;
- llvm::raw_string_ostream descriptor_map_out(descriptor_map);
llvm::legacy::PassManager pm;
- PopulatePassManager(&pm, &binaryStream, &descriptor_map_out,
- &SamplerMapEntries);
+ std::vector<version0::DescriptorMapEntry> descriptor_map_entries;
+ if (auto error =
+ PopulatePassManager(&pm, &binaryStream,
+ &descriptor_map_entries, &SamplerMapEntries))
+ return error;
pm.run(*module);
// Write outputs
@@ -708,8 +748,6 @@
// Write the descriptor map, if requested.
std::error_code error;
if (!DescriptorMapFilename.empty()) {
- descriptor_map_out.flush();
-
llvm::raw_fd_ostream descriptor_map_out_fd(DescriptorMapFilename, error,
llvm::sys::fs::F_RW |
llvm::sys::fs::F_Text);
@@ -718,7 +756,12 @@
<< DescriptorMapFilename << "': " << error.message() << '\n';
return -1;
}
- descriptor_map_out_fd << descriptor_map;
+ std::string descriptor_map_string;
+ std::ostringstream str(descriptor_map_string);
+ for (const auto &entry : descriptor_map_entries) {
+ str << entry << "\n";
+ }
+ descriptor_map_out_fd << str.str();
descriptor_map_out_fd.close();
}
@@ -746,4 +789,114 @@
return 0;
}
+
+int CompileFromSourceString(const std::string &program,
+ const std::string &sampler_map,
+ const std::string &options,
+ std::vector<uint32_t> *output_binary,
+ std::vector<clspv::version0::DescriptorMapEntry> *descriptor_map_entries) {
+ // We need to change how one of the called passes works by spoofing
+ // ParseCommandLineOptions with the specific option.
+ const int llvmArgc = 2;
+ const char *llvmArgv[llvmArgc] = {
+ "clspv",
+ "-simplifycfg-sink-common=false",
+ };
+
+ llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
+
+ llvm::SmallVector<const char *, 20> argv;
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver(A);
+ argv.push_back(Saver.save("clspv").data());
+ llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
+ int argc = static_cast<int>(argv.size());
+ llvm::cl::ParseCommandLineOptions(argc, &argv[0]);
+
+ 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::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;
+ }
+
+ action.Execute();
+ action.EndSourceFile();
+
+ clang::DiagnosticConsumer *const consumer =
+ instance.getDiagnostics().getClient();
+ consumer->finish();
+
+ auto num_errors = consumer->getNumErrors();
+ if (num_errors > 0) {
+ llvm::errs() << log << "\n";
+ return -1;
+ }
+
+ if (clspv::Option::ConstantArgsInUniformBuffer() &&
+ !clspv::Option::InlineEntryPoints()) {
+ llvm::errs() << "clspv restriction: -constant-arg-ubo requires "
+ "-inline-entry-points\n";
+ return -1;
+ }
+
+ llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
+ llvm::initializeCore(Registry);
+ llvm::initializeScalarOpts(Registry);
+
+ std::unique_ptr<llvm::Module> module(action.takeModule());
+
+ // Optimize.
+ // Create a memory buffer for temporarily writing the result.
+ SmallVector<char, 10000> binary;
+ llvm::raw_svector_ostream binaryStream(binary);
+ std::string descriptor_map;
+ llvm::legacy::PassManager pm;
+ if (auto error =
+ PopulatePassManager(&pm, &binaryStream,
+ descriptor_map_entries, &SamplerMapEntries))
+ return error;
+ pm.run(*module);
+
+ // Write outputs
+
+ // Write the descriptor map. This is required.
+ assert(descriptor_map_entries && "Valid descriptor map container is required.");
+ if (!DescriptorMapFilename.empty()) {
+ llvm::errs() << "Warning: -descriptormap is ignored descriptor map container is provided.\n";
+ }
+
+ // 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;
+}
} // namespace clspv