mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-21 22:20:14 +01:00
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:
parent
91e08312d8
commit
c4755a7c32
5 changed files with 128 additions and 35 deletions
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue