microsoft/clc: Support SPIR intermediates in the compilation APIs

We can now export SPIR (mainly just for testing) or import SPIR and
convert to SPIR-V.

Acked-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10322>
This commit is contained in:
Jesse Natalie 2021-04-19 06:58:56 -07:00 committed by Marge Bot
parent 91e08312d8
commit c4755a7c32
5 changed files with 128 additions and 35 deletions

View file

@ -575,6 +575,34 @@ struct clc_libclc *
return ctx; return ctx;
} }
bool
clc_compile_c_to_spir(const struct clc_compile_args *args,
const struct clc_logger *logger,
struct clc_binary *out_spir)
{
return clc_c_to_spir(args, logger, out_spir) >= 0;
}
void
clc_free_spir(struct clc_binary *spir)
{
clc_free_spir_binary(spir);
}
bool
clc_compile_spir_to_spirv(const struct clc_binary *in_spir,
const struct clc_logger *logger,
struct clc_binary *out_spirv)
{
if (clc_spir_to_spirv(in_spir, logger, out_spirv) < 0)
return false;
if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV)
clc_dump_spirv(out_spirv, stdout);
return true;
}
void void
clc_free_spirv(struct clc_binary *spirv) clc_free_spirv(struct clc_binary *spirv)
{ {

View file

@ -200,6 +200,19 @@ void clc_libclc_serialize(struct clc_libclc *lib, void **serialized, size_t *siz
void clc_libclc_free_serialized(void *serialized); void clc_libclc_free_serialized(void *serialized);
struct clc_libclc *clc_libclc_deserialize(void *serialized, size_t size); struct clc_libclc *clc_libclc_deserialize(void *serialized, size_t size);
bool
clc_compile_c_to_spir(const struct clc_compile_args *args,
const struct clc_logger *logger,
struct clc_binary *out_spir);
void
clc_free_spir(struct clc_binary *spir);
bool
clc_compile_spir_to_spirv(const struct clc_binary *in_spir,
const struct clc_logger *logger,
struct clc_binary *out_spirv);
void void
clc_free_spirv(struct clc_binary *spirv); clc_free_spirv(struct clc_binary *spirv);

View file

@ -31,6 +31,8 @@
#include <llvm/IR/LLVMContext.h> #include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Type.h> #include <llvm/IR/Type.h>
#include <llvm/Support/raw_ostream.h> #include <llvm/Support/raw_ostream.h>
#include <llvm/Bitcode/BitcodeWriter.h>
#include <llvm/Bitcode/BitcodeReader.h>
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#include <llvm-c/Target.h> #include <llvm-c/Target.h>
#include <LLVMSPIRVLib/LLVMSPIRVLib.h> #include <LLVMSPIRVLib/LLVMSPIRVLib.h>
@ -576,10 +578,9 @@ clc_free_kernels_info(const struct clc_kernel_info *kernels,
free((void *)kernels); free((void *)kernels);
} }
int static std::pair<std::unique_ptr<::llvm::Module>, std::unique_ptr<LLVMContext>>
clc_c_to_spirv(const struct clc_compile_args *args, clc_compile_to_llvm_module(const struct clc_compile_args *args,
const struct clc_logger *logger, const struct clc_logger *logger)
struct clc_binary *out_spirv)
{ {
LLVMInitializeAllTargets(); LLVMInitializeAllTargets();
LLVMInitializeAllTargetInfos(); LLVMInitializeAllTargetInfos();
@ -626,13 +627,13 @@ clc_c_to_spirv(const struct clc_compile_args *args,
diag)) { diag)) {
log += "Couldn't create Clang invocation.\n"; log += "Couldn't create Clang invocation.\n";
clc_error(logger, log.c_str()); clc_error(logger, log.c_str());
return -1; return {};
} }
if (diag.hasErrorOccurred()) { if (diag.hasErrorOccurred()) {
log += "Errors occurred during Clang invocation.\n"; log += "Errors occurred during Clang invocation.\n";
clc_error(logger, log.c_str()); clc_error(logger, log.c_str());
return -1; return {};
} }
// This is a workaround for a Clang bug which causes the number // This is a workaround for a Clang bug which causes the number
@ -696,10 +697,19 @@ clc_c_to_spirv(const struct clc_compile_args *args,
if (!c->ExecuteAction(act)) { if (!c->ExecuteAction(act)) {
log += "Error executing LLVM compilation action.\n"; log += "Error executing LLVM compilation action.\n";
clc_error(logger, log.c_str()); clc_error(logger, log.c_str());
return -1; return {};
} }
auto mod = act.takeModule(); return { act.takeModule(), std::move(llvm_ctx) };
}
static int
llvm_mod_to_spirv(std::unique_ptr<::llvm::Module> mod,
std::unique_ptr<LLVMContext> context,
const struct clc_logger *logger,
struct clc_binary *out_spirv)
{
std::string log;
std::ostringstream spv_stream; std::ostringstream spv_stream;
if (!::llvm::writeSpirv(mod.get(), spv_stream, log)) { if (!::llvm::writeSpirv(mod.get(), spv_stream, log)) {
log += "Translation from LLVM IR to SPIR-V failed.\n"; log += "Translation from LLVM IR to SPIR-V failed.\n";
@ -715,34 +725,54 @@ clc_c_to_spirv(const struct clc_compile_args *args,
return 0; return 0;
} }
static const char * int
spv_result_to_str(spv_result_t res) clc_c_to_spir(const struct clc_compile_args *args,
const struct clc_logger *logger,
struct clc_binary *out_spir)
{ {
switch (res) { auto pair = clc_compile_to_llvm_module(args, logger);
case SPV_SUCCESS: return "success"; if (!pair.first)
case SPV_UNSUPPORTED: return "unsupported"; return -1;
case SPV_END_OF_STREAM: return "end of stream";
case SPV_WARNING: return "warning"; ::llvm::SmallVector<char> buffer;
case SPV_FAILED_MATCH: return "failed match"; ::llvm::BitcodeWriter writer(buffer);
case SPV_REQUESTED_TERMINATION: return "requested termination"; writer.writeModule(*pair.first);
case SPV_ERROR_INTERNAL: return "internal error";
case SPV_ERROR_OUT_OF_MEMORY: return "out of memory"; out_spir->size = buffer.size_in_bytes();
case SPV_ERROR_INVALID_POINTER: return "invalid pointer"; out_spir->data = malloc(out_spir->size);
case SPV_ERROR_INVALID_BINARY: return "invalid binary"; memcpy(out_spir->data, buffer.data(), out_spir->size);
case SPV_ERROR_INVALID_TEXT: return "invalid text";
case SPV_ERROR_INVALID_TABLE: return "invalid table"; return 0;
case SPV_ERROR_INVALID_VALUE: return "invalid value"; }
case SPV_ERROR_INVALID_DIAGNOSTIC: return "invalid diagnostic";
case SPV_ERROR_INVALID_LOOKUP: return "invalid lookup"; int
case SPV_ERROR_INVALID_ID: return "invalid id"; clc_c_to_spirv(const struct clc_compile_args *args,
case SPV_ERROR_INVALID_CFG: return "invalid config"; const struct clc_logger *logger,
case SPV_ERROR_INVALID_LAYOUT: return "invalid layout"; struct clc_binary *out_spirv)
case SPV_ERROR_INVALID_CAPABILITY: return "invalid capability"; {
case SPV_ERROR_INVALID_DATA: return "invalid data"; auto pair = clc_compile_to_llvm_module(args, logger);
case SPV_ERROR_MISSING_EXTENSION: return "missing extension"; if (!pair.first)
case SPV_ERROR_WRONG_VERSION: return "wrong version"; return -1;
default: return "unknown error"; return llvm_mod_to_spirv(std::move(pair.first), std::move(pair.second), logger, out_spirv);
} }
int
clc_spir_to_spirv(const struct clc_binary *in_spir,
const struct clc_logger *logger,
struct clc_binary *out_spirv)
{
LLVMInitializeAllTargets();
LLVMInitializeAllTargetInfos();
LLVMInitializeAllTargetMCs();
LLVMInitializeAllAsmPrinters();
std::unique_ptr<LLVMContext> llvm_ctx{ new LLVMContext };
::llvm::StringRef spir_ref(static_cast<const char*>(in_spir->data), in_spir->size);
auto mod = ::llvm::parseBitcodeFile(::llvm::MemoryBufferRef(spir_ref, "<spir>"), *llvm_ctx);
if (!mod)
return -1;
return llvm_mod_to_spirv(std::move(mod.get()), std::move(llvm_ctx), logger, out_spirv);
} }
class SPIRVMessageConsumer { class SPIRVMessageConsumer {
@ -819,6 +849,12 @@ clc_dump_spirv(const struct clc_binary *spvbin, FILE *f)
fwrite(out.c_str(), out.size(), 1, f); fwrite(out.c_str(), out.size(), 1, f);
} }
void
clc_free_spir_binary(struct clc_binary *spir)
{
free(spir->data);
}
void void
clc_free_spirv_binary(struct clc_binary *spvbin) clc_free_spirv_binary(struct clc_binary *spvbin)
{ {

View file

@ -48,6 +48,16 @@ void
clc_free_kernels_info(const struct clc_kernel_info *kernels, clc_free_kernels_info(const struct clc_kernel_info *kernels,
unsigned num_kernels); unsigned num_kernels);
int
clc_c_to_spir(const struct clc_compile_args *args,
const struct clc_logger *logger,
struct clc_binary *out_spir);
int
clc_spir_to_spirv(const struct clc_binary *in_spir,
const struct clc_logger *logger,
struct clc_binary *out_spirv);
int int
clc_c_to_spirv(const struct clc_compile_args *args, clc_c_to_spirv(const struct clc_compile_args *args,
const struct clc_logger *logger, const struct clc_logger *logger,
@ -61,6 +71,9 @@ clc_link_spirv_binaries(const struct clc_linker_args *args,
void void
clc_dump_spirv(const struct clc_binary *spvbin, FILE *f); clc_dump_spirv(const struct clc_binary *spvbin, FILE *f);
void
clc_free_spir_binary(struct clc_binary *spir);
void void
clc_free_spirv_binary(struct clc_binary *spvbin); clc_free_spirv_binary(struct clc_binary *spvbin);

View file

@ -4,6 +4,9 @@ EXPORTS
clc_libclc_serialize clc_libclc_serialize
clc_libclc_free_serialized clc_libclc_free_serialized
clc_libclc_deserialize clc_libclc_deserialize
clc_compile_c_to_spir
clc_free_spir
clc_compile_spir_to_spirv
clc_free_spirv clc_free_spirv
clc_compile_c_to_spirv clc_compile_c_to_spirv
clc_link_spirv clc_link_spirv