summaryrefslogtreecommitdiff
path: root/src/microsoft/clc/clc_helpers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/microsoft/clc/clc_helpers.cpp')
-rw-r--r--src/microsoft/clc/clc_helpers.cpp812
1 files changed, 0 insertions, 812 deletions
diff --git a/src/microsoft/clc/clc_helpers.cpp b/src/microsoft/clc/clc_helpers.cpp
deleted file mode 100644
index 20bad26112b..00000000000
--- a/src/microsoft/clc/clc_helpers.cpp
+++ /dev/null
@@ -1,812 +0,0 @@
-//
-// Copyright 2012-2016 Francisco Jerez
-// Copyright 2012-2016 Advanced Micro Devices, Inc.
-// Copyright 2014-2016 Jan Vesely
-// Copyright 2014-2015 Serge Martin
-// Copyright 2015 Zoltan Gilian
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-
-#include <sstream>
-
-#include <llvm/ADT/ArrayRef.h>
-#include <llvm/IR/DiagnosticPrinter.h>
-#include <llvm/IR/DiagnosticInfo.h>
-#include <llvm/IR/LLVMContext.h>
-#include <llvm/IR/Type.h>
-#include <llvm/Support/raw_ostream.h>
-#include <llvm-c/Core.h>
-#include <llvm-c/Target.h>
-#include <LLVMSPIRVLib/LLVMSPIRVLib.h>
-
-#include <clang/CodeGen/CodeGenAction.h>
-#include <clang/Lex/PreprocessorOptions.h>
-#include <clang/Frontend/CompilerInstance.h>
-#include <clang/Frontend/TextDiagnosticBuffer.h>
-#include <clang/Frontend/TextDiagnosticPrinter.h>
-#include <clang/Basic/TargetInfo.h>
-
-#include <spirv-tools/libspirv.hpp>
-#include <spirv-tools/linker.hpp>
-
-#include "util/macros.h"
-#include "glsl_types.h"
-#include "nir.h"
-#include "nir_types.h"
-
-#include "clc_helpers.h"
-#include "spirv.h"
-
-#include "opencl-c.h.h"
-#include "opencl-c-base.h.h"
-
-using ::llvm::Function;
-using ::llvm::LLVMContext;
-using ::llvm::Module;
-using ::llvm::raw_string_ostream;
-
-static void
-llvm_log_handler(const ::llvm::DiagnosticInfo &di, void *data) {
- raw_string_ostream os { *reinterpret_cast<std::string *>(data) };
- ::llvm::DiagnosticPrinterRawOStream printer { os };
- di.print(printer);
-}
-
-class SPIRVKernelArg {
-public:
- SPIRVKernelArg(uint32_t id, uint32_t typeId) : id(id), typeId(typeId),
- addrQualifier(CLC_KERNEL_ARG_ADDRESS_PRIVATE),
- accessQualifier(0),
- typeQualifier(0) { }
- ~SPIRVKernelArg() { }
-
- uint32_t id;
- uint32_t typeId;
- std::string name;
- std::string typeName;
- enum clc_kernel_arg_address_qualifier addrQualifier;
- unsigned accessQualifier;
- unsigned typeQualifier;
-};
-
-class SPIRVKernelInfo {
-public:
- SPIRVKernelInfo(uint32_t fid, const char *nm) : funcId(fid), name(nm), vecHint(0) { }
- ~SPIRVKernelInfo() { }
-
- uint32_t funcId;
- std::string name;
- std::vector<SPIRVKernelArg> args;
- unsigned vecHint;
-};
-
-class SPIRVKernelParser {
-public:
- SPIRVKernelParser() : curKernel(NULL)
- {
- ctx = spvContextCreate(SPV_ENV_UNIVERSAL_1_0);
- }
-
- ~SPIRVKernelParser()
- {
- spvContextDestroy(ctx);
- }
-
- void parseEntryPoint(const spv_parsed_instruction_t *ins)
- {
- assert(ins->num_operands >= 3);
-
- const spv_parsed_operand_t *op = &ins->operands[1];
-
- assert(op->type == SPV_OPERAND_TYPE_ID);
-
- uint32_t funcId = ins->words[op->offset];
-
- for (auto &iter : kernels) {
- if (funcId == iter.funcId)
- return;
- }
-
- op = &ins->operands[2];
- assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING);
- const char *name = reinterpret_cast<const char *>(ins->words + op->offset);
-
- kernels.push_back(SPIRVKernelInfo(funcId, name));
- }
-
- void parseFunction(const spv_parsed_instruction_t *ins)
- {
- assert(ins->num_operands == 4);
-
- const spv_parsed_operand_t *op = &ins->operands[1];
-
- assert(op->type == SPV_OPERAND_TYPE_RESULT_ID);
-
- uint32_t funcId = ins->words[op->offset];
-
- SPIRVKernelInfo *kernel = NULL;
-
- for (auto &kernel : kernels) {
- if (funcId == kernel.funcId && !kernel.args.size()) {
- curKernel = &kernel;
- return;
- }
- }
- }
-
- void parseFunctionParam(const spv_parsed_instruction_t *ins)
- {
- const spv_parsed_operand_t *op;
- uint32_t id, typeId;
-
- if (!curKernel)
- return;
-
- assert(ins->num_operands == 2);
- op = &ins->operands[0];
- assert(op->type == SPV_OPERAND_TYPE_TYPE_ID);
- typeId = ins->words[op->offset];
- op = &ins->operands[1];
- assert(op->type == SPV_OPERAND_TYPE_RESULT_ID);
- id = ins->words[op->offset];
- curKernel->args.push_back(SPIRVKernelArg(id, typeId));
- }
-
- void parseName(const spv_parsed_instruction_t *ins)
- {
- const spv_parsed_operand_t *op;
- const char *name;
- uint32_t id;
-
- assert(ins->num_operands == 2);
-
- op = &ins->operands[0];
- assert(op->type == SPV_OPERAND_TYPE_ID);
- id = ins->words[op->offset];
- op = &ins->operands[1];
- assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING);
- name = reinterpret_cast<const char *>(ins->words + op->offset);
-
- for (auto &kernel : kernels) {
- for (auto &arg : kernel.args) {
- if (arg.id == id && arg.name.empty()) {
- arg.name = name;
- break;
- }
- }
- }
- }
-
- void parseTypePointer(const spv_parsed_instruction_t *ins)
- {
- enum clc_kernel_arg_address_qualifier addrQualifier;
- uint32_t typeId, storageClass;
- const spv_parsed_operand_t *op;
-
- assert(ins->num_operands == 3);
-
- op = &ins->operands[0];
- assert(op->type == SPV_OPERAND_TYPE_RESULT_ID);
- typeId = ins->words[op->offset];
-
- op = &ins->operands[1];
- assert(op->type == SPV_OPERAND_TYPE_STORAGE_CLASS);
- storageClass = ins->words[op->offset];
- switch (storageClass) {
- case SpvStorageClassCrossWorkgroup:
- addrQualifier = CLC_KERNEL_ARG_ADDRESS_GLOBAL;
- break;
- case SpvStorageClassWorkgroup:
- addrQualifier = CLC_KERNEL_ARG_ADDRESS_LOCAL;
- break;
- case SpvStorageClassUniformConstant:
- addrQualifier = CLC_KERNEL_ARG_ADDRESS_CONSTANT;
- break;
- default:
- addrQualifier = CLC_KERNEL_ARG_ADDRESS_PRIVATE;
- break;
- }
-
- for (auto &kernel : kernels) {
- for (auto &arg : kernel.args) {
- if (arg.typeId == typeId)
- arg.addrQualifier = addrQualifier;
- }
- }
- }
-
- void parseOpString(const spv_parsed_instruction_t *ins)
- {
- const spv_parsed_operand_t *op;
- std::string str;
-
- assert(ins->num_operands == 2);
-
- op = &ins->operands[1];
- assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING);
- str = reinterpret_cast<const char *>(ins->words + op->offset);
-
- if (str.find("kernel_arg_type.") != 0)
- return;
-
- size_t start = sizeof("kernel_arg_type.") - 1;
-
- for (auto &kernel : kernels) {
- size_t pos;
-
- pos = str.find(kernel.name, start);
- if (pos == std::string::npos ||
- pos != start || str[start + kernel.name.size()] != '.')
- continue;
-
- pos = start + kernel.name.size();
- if (str[pos++] != '.')
- continue;
-
- for (auto &arg : kernel.args) {
- if (arg.name.empty())
- break;
-
- size_t typeEnd = str.find(',', pos);
- if (typeEnd == std::string::npos)
- break;
-
- arg.typeName = str.substr(pos, typeEnd - pos);
- pos = typeEnd + 1;
- }
- }
- }
-
- void applyDecoration(uint32_t id, const spv_parsed_instruction_t *ins)
- {
- auto iter = decorationGroups.find(id);
- if (iter != decorationGroups.end()) {
- for (uint32_t entry : iter->second)
- applyDecoration(entry, ins);
- return;
- }
-
- const spv_parsed_operand_t *op;
- uint32_t decoration;
-
- assert(ins->num_operands >= 2);
-
- op = &ins->operands[1];
- assert(op->type == SPV_OPERAND_TYPE_DECORATION);
- decoration = ins->words[op->offset];
-
- for (auto &kernel : kernels) {
- for (auto &arg : kernel.args) {
- if (arg.id == id) {
- switch (decoration) {
- case SpvDecorationVolatile:
- arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_VOLATILE;
- break;
- case SpvDecorationConstant:
- arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_CONST;
- break;
- case SpvDecorationRestrict:
- arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_RESTRICT;
- break;
- case SpvDecorationFuncParamAttr:
- op = &ins->operands[2];
- assert(op->type == SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE);
- switch (ins->words[op->offset]) {
- case SpvFunctionParameterAttributeNoAlias:
- arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_RESTRICT;
- break;
- case SpvFunctionParameterAttributeNoWrite:
- arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_CONST;
- break;
- }
- break;
- }
- }
-
- }
- }
- }
-
- void parseOpDecorate(const spv_parsed_instruction_t *ins)
- {
- const spv_parsed_operand_t *op;
- uint32_t id;
-
- assert(ins->num_operands >= 2);
-
- op = &ins->operands[0];
- assert(op->type == SPV_OPERAND_TYPE_ID);
- id = ins->words[op->offset];
-
- applyDecoration(id, ins);
- }
-
- void parseOpGroupDecorate(const spv_parsed_instruction_t *ins)
- {
- assert(ins->num_operands >= 2);
-
- const spv_parsed_operand_t *op = &ins->operands[0];
- assert(op->type == SPV_OPERAND_TYPE_ID);
- uint32_t groupId = ins->words[op->offset];
-
- auto lowerBound = decorationGroups.lower_bound(groupId);
- if (lowerBound != decorationGroups.end() &&
- lowerBound->first == groupId)
- // Group already filled out
- return;
-
- auto iter = decorationGroups.emplace_hint(lowerBound, groupId, std::vector<uint32_t>{});
- auto& vec = iter->second;
- vec.reserve(ins->num_operands - 1);
- for (uint32_t i = 1; i < ins->num_operands; ++i) {
- op = &ins->operands[i];
- assert(op->type == SPV_OPERAND_TYPE_ID);
- vec.push_back(ins->words[op->offset]);
- }
- }
-
- void parseOpTypeImage(const spv_parsed_instruction_t *ins)
- {
- const spv_parsed_operand_t *op;
- uint32_t typeId;
- unsigned accessQualifier = CLC_KERNEL_ARG_ACCESS_READ;
-
- op = &ins->operands[0];
- assert(op->type == SPV_OPERAND_TYPE_RESULT_ID);
- typeId = ins->words[op->offset];
-
- if (ins->num_operands >= 9) {
- op = &ins->operands[8];
- assert(op->type == SPV_OPERAND_TYPE_ACCESS_QUALIFIER);
- switch (ins->words[op->offset]) {
- case SpvAccessQualifierReadOnly:
- accessQualifier = CLC_KERNEL_ARG_ACCESS_READ;
- break;
- case SpvAccessQualifierWriteOnly:
- accessQualifier = CLC_KERNEL_ARG_ACCESS_WRITE;
- break;
- case SpvAccessQualifierReadWrite:
- accessQualifier = CLC_KERNEL_ARG_ACCESS_WRITE |
- CLC_KERNEL_ARG_ACCESS_READ;
- break;
- }
- }
-
- for (auto &kernel : kernels) {
- for (auto &arg : kernel.args) {
- if (arg.typeId == typeId) {
- arg.accessQualifier = accessQualifier;
- arg.addrQualifier = CLC_KERNEL_ARG_ADDRESS_GLOBAL;
- }
- }
- }
- }
-
- void parseExecutionMode(const spv_parsed_instruction_t *ins)
- {
- uint32_t executionMode = ins->words[ins->operands[1].offset];
- if (executionMode != SpvExecutionModeVecTypeHint)
- return;
-
- uint32_t funcId = ins->words[ins->operands[0].offset];
- uint32_t vecHint = ins->words[ins->operands[2].offset];
- for (auto& kernel : kernels) {
- if (kernel.funcId == funcId)
- kernel.vecHint = vecHint;
- }
- }
-
- static spv_result_t
- parseInstruction(void *data, const spv_parsed_instruction_t *ins)
- {
- SPIRVKernelParser *parser = reinterpret_cast<SPIRVKernelParser *>(data);
-
- switch (ins->opcode) {
- case SpvOpName:
- parser->parseName(ins);
- break;
- case SpvOpEntryPoint:
- parser->parseEntryPoint(ins);
- break;
- case SpvOpFunction:
- parser->parseFunction(ins);
- break;
- case SpvOpFunctionParameter:
- parser->parseFunctionParam(ins);
- break;
- case SpvOpFunctionEnd:
- case SpvOpLabel:
- parser->curKernel = NULL;
- break;
- case SpvOpTypePointer:
- parser->parseTypePointer(ins);
- break;
- case SpvOpTypeImage:
- parser->parseOpTypeImage(ins);
- break;
- case SpvOpString:
- parser->parseOpString(ins);
- break;
- case SpvOpDecorate:
- parser->parseOpDecorate(ins);
- break;
- case SpvOpGroupDecorate:
- parser->parseOpGroupDecorate(ins);
- break;
- case SpvOpExecutionMode:
- parser->parseExecutionMode(ins);
- break;
- default:
- break;
- }
-
- return SPV_SUCCESS;
- }
-
- bool parsingComplete()
- {
- for (auto &kernel : kernels) {
- if (kernel.name.empty())
- return false;
-
- for (auto &arg : kernel.args) {
- if (arg.name.empty() || arg.typeName.empty())
- return false;
- }
- }
-
- return true;
- }
-
- void parseBinary(const struct spirv_binary &spvbin)
- {
- /* 3 passes should be enough to retrieve all kernel information:
- * 1st pass: all entry point name and number of args
- * 2nd pass: argument names and type names
- * 3rd pass: pointer type names
- */
- for (unsigned pass = 0; pass < 3; pass++) {
- spvBinaryParse(ctx, reinterpret_cast<void *>(this),
- spvbin.data, spvbin.size / 4,
- NULL, parseInstruction, NULL);
-
- if (parsingComplete())
- return;
- }
-
- assert(0);
- }
-
- std::vector<SPIRVKernelInfo> kernels;
- std::map<uint32_t, std::vector<uint32_t>> decorationGroups;
- SPIRVKernelInfo *curKernel;
- spv_context ctx;
-};
-
-const struct clc_kernel_info *
-clc_spirv_get_kernels_info(const struct spirv_binary *spvbin,
- unsigned *num_kernels)
-{
- struct clc_kernel_info *kernels;
-
- SPIRVKernelParser parser;
-
- parser.parseBinary(*spvbin);
- *num_kernels = parser.kernels.size();
- if (!*num_kernels)
- return NULL;
-
- kernels = reinterpret_cast<struct clc_kernel_info *>(calloc(*num_kernels,
- sizeof(*kernels)));
- assert(kernels);
- for (unsigned i = 0; i < parser.kernels.size(); i++) {
- kernels[i].name = strdup(parser.kernels[i].name.c_str());
- kernels[i].num_args = parser.kernels[i].args.size();
- kernels[i].vec_hint_size = parser.kernels[i].vecHint >> 16;
- kernels[i].vec_hint_type = (enum clc_vec_hint_type)(parser.kernels[i].vecHint & 0xFFFF);
- if (!kernels[i].num_args)
- continue;
-
- struct clc_kernel_arg *args;
-
- args = reinterpret_cast<struct clc_kernel_arg *>(calloc(kernels[i].num_args,
- sizeof(*kernels->args)));
- kernels[i].args = args;
- assert(args);
- for (unsigned j = 0; j < kernels[i].num_args; j++) {
- if (!parser.kernels[i].args[j].name.empty())
- args[j].name = strdup(parser.kernels[i].args[j].name.c_str());
- args[j].type_name = strdup(parser.kernels[i].args[j].typeName.c_str());
- args[j].address_qualifier = parser.kernels[i].args[j].addrQualifier;
- args[j].type_qualifier = parser.kernels[i].args[j].typeQualifier;
- args[j].access_qualifier = parser.kernels[i].args[j].accessQualifier;
- }
- }
-
- return kernels;
-}
-
-void
-clc_free_kernels_info(const struct clc_kernel_info *kernels,
- unsigned num_kernels)
-{
- if (!kernels)
- return;
-
- for (unsigned i = 0; i < num_kernels; i++) {
- if (kernels[i].args) {
- for (unsigned j = 0; j < kernels[i].num_args; j++) {
- free((void *)kernels[i].args[j].name);
- free((void *)kernels[i].args[j].type_name);
- }
- }
- free((void *)kernels[i].name);
- }
-
- free((void *)kernels);
-}
-
-int
-clc_to_spirv(const struct clc_compile_args *args,
- struct spirv_binary *spvbin,
- const struct clc_logger *logger)
-{
- LLVMInitializeAllTargets();
- LLVMInitializeAllTargetInfos();
- LLVMInitializeAllTargetMCs();
- LLVMInitializeAllAsmPrinters();
-
- std::string log;
- std::unique_ptr<LLVMContext> llvm_ctx { new LLVMContext };
- llvm_ctx->setDiagnosticHandlerCallBack(llvm_log_handler, &log);
-
- std::unique_ptr<clang::CompilerInstance> c { new clang::CompilerInstance };
- clang::DiagnosticsEngine diag { new clang::DiagnosticIDs,
- new clang::DiagnosticOptions,
- new clang::TextDiagnosticPrinter(*new raw_string_ostream(log),
- &c->getDiagnosticOpts(), true)};
-
- std::vector<const char *> clang_opts = {
- args->source.name,
- "-triple", "spir64-unknown-unknown",
- // By default, clang prefers to use modules to pull in the default headers,
- // which doesn't work with our technique of embedding the headers in our binary
- "-finclude-default-header",
- // Add a default CL compiler version. Clang will pick the last one specified
- // on the command line, so the app can override this one.
- "-cl-std=cl1.2",
- // The LLVM-SPIRV-Translator doesn't support memset with variable size
- "-fno-builtin-memset",
- // LLVM's optimizations can produce code that the translator can't translate
- "-O0",
- // Ensure inline functions are actually emitted
- "-fgnu89-inline"
- };
- // We assume there's appropriate defines for __OPENCL_VERSION__ and __IMAGE_SUPPORT__
- // being provided by the caller here.
- clang_opts.insert(clang_opts.end(), args->args, args->args + args->num_args);
-
- if (!clang::CompilerInvocation::CreateFromArgs(c->getInvocation(),
-#if LLVM_VERSION_MAJOR >= 10
- clang_opts,
-#else
- clang_opts.data(),
- clang_opts.data() + clang_opts.size(),
-#endif
- diag)) {
- log += "Couldn't create Clang invocation.\n";
- clc_error(logger, log.c_str());
- return -1;
- }
-
- if (diag.hasErrorOccurred()) {
- log += "Errors occurred during Clang invocation.\n";
- clc_error(logger, log.c_str());
- return -1;
- }
-
- // This is a workaround for a Clang bug which causes the number
- // of warnings and errors to be printed to stderr.
- // http://www.llvm.org/bugs/show_bug.cgi?id=19735
- c->getDiagnosticOpts().ShowCarets = false;
-
- c->createDiagnostics(new clang::TextDiagnosticPrinter(
- *new raw_string_ostream(log),
- &c->getDiagnosticOpts(), true));
-
- c->setTarget(clang::TargetInfo::CreateTargetInfo(
- c->getDiagnostics(), c->getInvocation().TargetOpts));
-
- c->getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly;
- c->getHeaderSearchOpts().UseBuiltinIncludes = false;
- c->getHeaderSearchOpts().UseStandardSystemIncludes = false;
-
- // Add opencl-c generic search path
- {
- ::llvm::SmallString<128> system_header_path;
- ::llvm::sys::path::system_temp_directory(true, system_header_path);
- ::llvm::sys::path::append(system_header_path, "openclon12");
- c->getHeaderSearchOpts().AddPath(system_header_path.str(),
- clang::frontend::Angled,
- false, false);
-
- ::llvm::sys::path::append(system_header_path, "opencl-c.h");
- c->getPreprocessorOpts().addRemappedFile(system_header_path.str(),
- ::llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(opencl_c_source, _countof(opencl_c_source) - 1)).release());
-
- ::llvm::sys::path::remove_filename(system_header_path);
- ::llvm::sys::path::append(system_header_path, "opencl-c-base.h");
- c->getPreprocessorOpts().addRemappedFile(system_header_path.str(),
- ::llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(opencl_c_base_source, _countof(opencl_c_base_source) - 1)).release());
- }
-
- if (args->num_headers) {
- ::llvm::SmallString<128> tmp_header_path;
- ::llvm::sys::path::system_temp_directory(true, tmp_header_path);
- ::llvm::sys::path::append(tmp_header_path, "openclon12");
-
- c->getHeaderSearchOpts().AddPath(tmp_header_path.str(),
- clang::frontend::Quoted,
- false, false);
-
- for (size_t i = 0; i < args->num_headers; i++) {
- auto path_copy = tmp_header_path;
- ::llvm::sys::path::append(path_copy, ::llvm::sys::path::convert_to_slash(args->headers[i].name));
- c->getPreprocessorOpts().addRemappedFile(path_copy.str(),
- ::llvm::MemoryBuffer::getMemBufferCopy(args->headers[i].value).release());
- }
- }
-
- c->getPreprocessorOpts().addRemappedFile(
- args->source.name,
- ::llvm::MemoryBuffer::getMemBufferCopy(std::string(args->source.value)).release());
-
- // Compile the code
- clang::EmitLLVMOnlyAction act(llvm_ctx.get());
- if (!c->ExecuteAction(act)) {
- log += "Error executing LLVM compilation action.\n";
- clc_error(logger, log.c_str());
- return -1;
- }
-
- auto mod = act.takeModule();
- std::ostringstream spv_stream;
- if (!::llvm::writeSpirv(mod.get(), spv_stream, log)) {
- log += "Translation from LLVM IR to SPIR-V failed.\n";
- clc_error(logger, log.c_str());
- return -1;
- }
-
- const std::string spv_out = spv_stream.str();
- spvbin->size = spv_out.size();
- spvbin->data = static_cast<uint32_t *>(malloc(spvbin->size));
- memcpy(spvbin->data, spv_out.data(), spvbin->size);
-
- return 0;
-}
-
-static const char *
-spv_result_to_str(spv_result_t res)
-{
- switch (res) {
- case SPV_SUCCESS: return "success";
- case SPV_UNSUPPORTED: return "unsupported";
- case SPV_END_OF_STREAM: return "end of stream";
- case SPV_WARNING: return "warning";
- case SPV_FAILED_MATCH: return "failed match";
- case SPV_REQUESTED_TERMINATION: return "requested termination";
- case SPV_ERROR_INTERNAL: return "internal error";
- case SPV_ERROR_OUT_OF_MEMORY: return "out of memory";
- case SPV_ERROR_INVALID_POINTER: return "invalid pointer";
- case SPV_ERROR_INVALID_BINARY: return "invalid binary";
- case SPV_ERROR_INVALID_TEXT: return "invalid text";
- case SPV_ERROR_INVALID_TABLE: return "invalid table";
- case SPV_ERROR_INVALID_VALUE: return "invalid value";
- case SPV_ERROR_INVALID_DIAGNOSTIC: return "invalid diagnostic";
- case SPV_ERROR_INVALID_LOOKUP: return "invalid lookup";
- case SPV_ERROR_INVALID_ID: return "invalid id";
- case SPV_ERROR_INVALID_CFG: return "invalid config";
- case SPV_ERROR_INVALID_LAYOUT: return "invalid layout";
- case SPV_ERROR_INVALID_CAPABILITY: return "invalid capability";
- case SPV_ERROR_INVALID_DATA: return "invalid data";
- case SPV_ERROR_MISSING_EXTENSION: return "missing extension";
- case SPV_ERROR_WRONG_VERSION: return "wrong version";
- default: return "unknown error";
- }
-}
-
-class SPIRVMessageConsumer {
-public:
- SPIRVMessageConsumer(const struct clc_logger *logger): logger(logger) {}
-
- void operator()(spv_message_level_t level, const char *src,
- const spv_position_t &pos, const char *msg)
- {
- switch(level) {
- case SPV_MSG_FATAL:
- case SPV_MSG_INTERNAL_ERROR:
- case SPV_MSG_ERROR:
- clc_error(logger, "(file=%s,line=%ld,column=%ld,index=%ld): %s",
- src, pos.line, pos.column, pos.index, msg);
- break;
-
- case SPV_MSG_WARNING:
- clc_warning(logger, "(file=%s,line=%ld,column=%ld,index=%ld): %s",
- src, pos.line, pos.column, pos.index, msg);
- break;
-
- default:
- break;
- }
- }
-
-private:
- const struct clc_logger *logger;
-};
-
-int
-clc_link_spirv_binaries(const struct clc_linker_args *args,
- struct spirv_binary *dst_bin,
- const struct clc_logger *logger)
-{
- std::vector<std::vector<uint32_t>> binaries;
-
- for (unsigned i = 0; i < args->num_in_objs; i++) {
- std::vector<uint32_t> bin(args->in_objs[i]->spvbin.data,
- args->in_objs[i]->spvbin.data +
- (args->in_objs[i]->spvbin.size / 4));
- binaries.push_back(bin);
- }
-
- SPIRVMessageConsumer msgconsumer(logger);
- spvtools::Context context(SPV_ENV_UNIVERSAL_1_0);
- context.SetMessageConsumer(msgconsumer);
- spvtools::LinkerOptions options;
- options.SetAllowPartialLinkage(args->create_library);
- options.SetCreateLibrary(args->create_library);
- std::vector<uint32_t> linkingResult;
- spv_result_t status = spvtools::Link(context, binaries, &linkingResult, options);
- if (status != SPV_SUCCESS) {
- return -1;
- }
-
- dst_bin->size = linkingResult.size() * 4;
- dst_bin->data = static_cast<uint32_t *>(malloc(dst_bin->size));
- memcpy(dst_bin->data, linkingResult.data(), dst_bin->size);
-
- return 0;
-}
-
-void
-clc_dump_spirv(const struct spirv_binary *spvbin, FILE *f)
-{
- spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
- std::vector<uint32_t> bin(spvbin->data, spvbin->data + (spvbin->size / 4));
- std::string out;
- tools.Disassemble(bin, &out,
- SPV_BINARY_TO_TEXT_OPTION_INDENT |
- SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
- fwrite(out.c_str(), out.size(), 1, f);
-}
-
-void
-clc_free_spirv_binary(struct spirv_binary *spvbin)
-{
- free(spvbin->data);
-}