llvmpipe: add shader cache support for ORCJIT implementation
Signed-off-by: Icenowy Zheng <uwu@icenowy.me> Reviewed-by: Dave Airlie <airlied@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30036>
This commit is contained in:
@@ -1636,8 +1636,10 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
|||||||
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
||||||
lp_add_function_attr(variant_func, i + 1, LP_FUNC_ATTR_NOALIAS);
|
lp_add_function_attr(variant_func, i + 1, LP_FUNC_ATTR_NOALIAS);
|
||||||
|
|
||||||
if (gallivm->cache && gallivm->cache->data_size)
|
if (gallivm->cache && gallivm->cache->data_size) {
|
||||||
|
gallivm_stub_func(gallivm, variant_func);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context_ptr = LLVMGetParam(variant_func, 0);
|
context_ptr = LLVMGetParam(variant_func, 0);
|
||||||
resources_ptr = LLVMGetParam(variant_func, 1);
|
resources_ptr = LLVMGetParam(variant_func, 1);
|
||||||
@@ -2367,8 +2369,11 @@ draw_gs_llvm_generate(struct draw_llvm *llvm,
|
|||||||
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
||||||
lp_add_function_attr(variant_func, i + 1, LP_FUNC_ATTR_NOALIAS);
|
lp_add_function_attr(variant_func, i + 1, LP_FUNC_ATTR_NOALIAS);
|
||||||
|
|
||||||
if (gallivm->cache && gallivm->cache->data_size)
|
if (gallivm->cache && gallivm->cache->data_size) {
|
||||||
|
gallivm_stub_func(gallivm, variant_func);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context_ptr = LLVMGetParam(variant_func, 0);
|
context_ptr = LLVMGetParam(variant_func, 0);
|
||||||
resources_ptr = LLVMGetParam(variant_func, 1);
|
resources_ptr = LLVMGetParam(variant_func, 1);
|
||||||
input_array = LLVMGetParam(variant_func, 2);
|
input_array = LLVMGetParam(variant_func, 2);
|
||||||
@@ -2961,8 +2966,11 @@ draw_tcs_llvm_generate(struct draw_llvm *llvm,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gallivm->cache && gallivm->cache->data_size)
|
if (gallivm->cache && gallivm->cache->data_size) {
|
||||||
|
gallivm_stub_func(gallivm, variant_func);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
resources_ptr = LLVMGetParam(variant_func, 0);
|
resources_ptr = LLVMGetParam(variant_func, 0);
|
||||||
input_array = LLVMGetParam(variant_func, 1);
|
input_array = LLVMGetParam(variant_func, 1);
|
||||||
output_array = LLVMGetParam(variant_func, 2);
|
output_array = LLVMGetParam(variant_func, 2);
|
||||||
@@ -3523,8 +3531,11 @@ draw_tes_llvm_generate(struct draw_llvm *llvm,
|
|||||||
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
||||||
lp_add_function_attr(variant_func, i + 1, LP_FUNC_ATTR_NOALIAS);
|
lp_add_function_attr(variant_func, i + 1, LP_FUNC_ATTR_NOALIAS);
|
||||||
|
|
||||||
if (gallivm->cache && gallivm->cache->data_size)
|
if (gallivm->cache && gallivm->cache->data_size) {
|
||||||
|
gallivm_stub_func(gallivm, variant_func);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
resources_ptr = LLVMGetParam(variant_func, 0);
|
resources_ptr = LLVMGetParam(variant_func, 0);
|
||||||
input_array = LLVMGetParam(variant_func, 1);
|
input_array = LLVMGetParam(variant_func, 1);
|
||||||
io_ptr = LLVMGetParam(variant_func, 2);
|
io_ptr = LLVMGetParam(variant_func, 2);
|
||||||
|
@@ -495,3 +495,14 @@ gallivm_jit_function(struct gallivm_state *gallivm,
|
|||||||
|
|
||||||
return jit_func;
|
return jit_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gallivm_stub_func(struct gallivm_state *gallivm, LLVMValueRef func)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* MCJIT can accept an empty function, nothing is needed here.
|
||||||
|
* The only code is to silence unused var warning.
|
||||||
|
*/
|
||||||
|
(void) gallivm;
|
||||||
|
(void) func;
|
||||||
|
}
|
||||||
|
@@ -116,6 +116,9 @@ func_pointer
|
|||||||
gallivm_jit_function(struct gallivm_state *gallivm,
|
gallivm_jit_function(struct gallivm_state *gallivm,
|
||||||
LLVMValueRef func, const char *func_name);
|
LLVMValueRef func, const char *func_name);
|
||||||
|
|
||||||
|
void
|
||||||
|
gallivm_stub_func(struct gallivm_state *gallivm, LLVMValueRef func);
|
||||||
|
|
||||||
unsigned gallivm_get_perf_flags(void);
|
unsigned gallivm_get_perf_flags(void);
|
||||||
|
|
||||||
void lp_init_clock_hook(struct gallivm_state *gallivm);
|
void lp_init_clock_hook(struct gallivm_state *gallivm);
|
||||||
|
@@ -37,6 +37,8 @@
|
|||||||
#include <llvm/ADT/StringMap.h>
|
#include <llvm/ADT/StringMap.h>
|
||||||
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
|
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
|
||||||
#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
|
#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
|
||||||
|
#include <llvm/ExecutionEngine/Orc/CompileUtils.h>
|
||||||
|
#include <llvm/ExecutionEngine/ObjectCache.h>
|
||||||
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
||||||
#include <llvm/Target/TargetMachine.h>
|
#include <llvm/Target/TargetMachine.h>
|
||||||
#include <llvm/Support/TargetSelect.h>
|
#include <llvm/Support/TargetSelect.h>
|
||||||
@@ -62,6 +64,41 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class LPObjectCacheORC : public llvm::ObjectCache {
|
||||||
|
private:
|
||||||
|
bool has_object;
|
||||||
|
std::string mid;
|
||||||
|
struct lp_cached_code *cache_out;
|
||||||
|
public:
|
||||||
|
LPObjectCacheORC(struct lp_cached_code *cache) {
|
||||||
|
cache_out = cache;
|
||||||
|
has_object = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~LPObjectCacheORC() {
|
||||||
|
}
|
||||||
|
void notifyObjectCompiled(const llvm::Module *M, llvm::MemoryBufferRef Obj) override {
|
||||||
|
const std::string ModuleID = M->getModuleIdentifier();
|
||||||
|
if (has_object)
|
||||||
|
fprintf(stderr, "CACHE ALREADY HAS MODULE OBJECT\n");
|
||||||
|
if (mid == ModuleID)
|
||||||
|
fprintf(stderr, "CACHING ANOTHER MODULE\n");
|
||||||
|
has_object = true;
|
||||||
|
mid = ModuleID;
|
||||||
|
cache_out->data_size = Obj.getBufferSize();
|
||||||
|
cache_out->data = malloc(cache_out->data_size);
|
||||||
|
memcpy(cache_out->data, Obj.getBufferStart(), cache_out->data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module *M) override {
|
||||||
|
const std::string ModuleID = M->getModuleIdentifier();
|
||||||
|
if (cache_out->data_size)
|
||||||
|
return llvm::MemoryBuffer::getMemBuffer(llvm::StringRef((const char *)cache_out->data, cache_out->data_size), "", false);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class LPJit;
|
class LPJit;
|
||||||
|
|
||||||
class LLVMEnsureMultithreaded {
|
class LLVMEnsureMultithreaded {
|
||||||
@@ -215,6 +252,12 @@ public:
|
|||||||
ExitOnErr(es.removeJITDylib(* ::unwrap(jd)));
|
ExitOnErr(es.removeJITDylib(* ::unwrap(jd)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_object_cache(llvm::ObjectCache *objcache) {
|
||||||
|
auto &ircl = LPJit::get_instance()->lljit->getIRCompileLayer();
|
||||||
|
auto &irc = ircl.getCompiler();
|
||||||
|
auto &sc = dynamic_cast<llvm::orc::SimpleCompiler &>(irc);
|
||||||
|
sc.setObjectCache(objcache);
|
||||||
|
}
|
||||||
LLVMTargetMachineRef tm;
|
LLVMTargetMachineRef tm;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -481,10 +524,7 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name,
|
|||||||
if (!lp_build_init())
|
if (!lp_build_init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// cache is not implemented
|
|
||||||
gallivm->cache = cache;
|
gallivm->cache = cache;
|
||||||
if (gallivm->cache)
|
|
||||||
gallivm->cache->data_size = 0;
|
|
||||||
|
|
||||||
gallivm->_ts_context = context->ref;
|
gallivm->_ts_context = context->ref;
|
||||||
gallivm->context = LLVMOrcThreadSafeContextGetContext(context->ref);
|
gallivm->context = LLVMOrcThreadSafeContextGetContext(context->ref);
|
||||||
@@ -543,6 +583,12 @@ gallivm_free_ir(struct gallivm_state *gallivm)
|
|||||||
if (gallivm->builder)
|
if (gallivm->builder)
|
||||||
LLVMDisposeBuilder(gallivm->builder);
|
LLVMDisposeBuilder(gallivm->builder);
|
||||||
|
|
||||||
|
if (gallivm->cache) {
|
||||||
|
if (gallivm->cache->jit_obj_cache)
|
||||||
|
lp_free_objcache(gallivm->cache->jit_obj_cache);
|
||||||
|
free(gallivm->cache->data);
|
||||||
|
}
|
||||||
|
|
||||||
gallivm->target = NULL;
|
gallivm->target = NULL;
|
||||||
gallivm->module=NULL;
|
gallivm->module=NULL;
|
||||||
gallivm->module_name=NULL;
|
gallivm->module_name=NULL;
|
||||||
@@ -551,6 +597,7 @@ gallivm_free_ir(struct gallivm_state *gallivm)
|
|||||||
gallivm->_ts_context=NULL;
|
gallivm->_ts_context=NULL;
|
||||||
gallivm->cache=NULL;
|
gallivm->cache=NULL;
|
||||||
LPJit::deregister_gallivm_state(gallivm);
|
LPJit::deregister_gallivm_state(gallivm);
|
||||||
|
LPJit::set_object_cache(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -580,6 +627,14 @@ gallivm_compile_module(struct gallivm_state *gallivm)
|
|||||||
LPJit::register_gallivm_state(gallivm);
|
LPJit::register_gallivm_state(gallivm);
|
||||||
gallivm->module = nullptr;
|
gallivm->module = nullptr;
|
||||||
|
|
||||||
|
if (gallivm->cache) {
|
||||||
|
if (!gallivm->cache->jit_obj_cache) {
|
||||||
|
LPObjectCacheORC *objcache = new LPObjectCacheORC(gallivm->cache);
|
||||||
|
gallivm->cache->jit_obj_cache = (void *)objcache;
|
||||||
|
}
|
||||||
|
auto *objcache = (LPObjectCacheORC *)gallivm->cache->jit_obj_cache;
|
||||||
|
LPJit::set_object_cache(objcache);
|
||||||
|
}
|
||||||
/* defer compilation till first lookup by gallivm_jit_function */
|
/* defer compilation till first lookup by gallivm_jit_function */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,3 +645,18 @@ gallivm_jit_function(struct gallivm_state *gallivm,
|
|||||||
return pointer_to_func(
|
return pointer_to_func(
|
||||||
LPJit::lookup_in_jd(func_name, gallivm->_per_module_jd));
|
LPJit::lookup_in_jd(func_name, gallivm->_per_module_jd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gallivm_stub_func(struct gallivm_state *gallivm, LLVMValueRef func)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* ORCJIT cannot accept a function with absolutely no content at all.
|
||||||
|
* Generate a "void func() {}" stub here.
|
||||||
|
*/
|
||||||
|
LLVMBasicBlockRef block = LLVMAppendBasicBlockInContext(gallivm->context,
|
||||||
|
func, "entry");
|
||||||
|
LLVMBuilderRef builder = gallivm->builder;
|
||||||
|
assert(builder);
|
||||||
|
LLVMPositionBuilderAtEnd(builder, block);
|
||||||
|
LLVMBuildRetVoid(builder);
|
||||||
|
}
|
||||||
|
@@ -409,8 +409,10 @@ generate_compute(struct llvmpipe_context *lp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variant->gallivm->cache->data_size)
|
if (variant->gallivm->cache->data_size) {
|
||||||
|
gallivm_stub_func(gallivm, function);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context_ptr = LLVMGetParam(function, CS_ARG_CONTEXT);
|
context_ptr = LLVMGetParam(function, CS_ARG_CONTEXT);
|
||||||
resources_ptr = LLVMGetParam(function, CS_ARG_RESOURCES);
|
resources_ptr = LLVMGetParam(function, CS_ARG_RESOURCES);
|
||||||
|
@@ -3217,8 +3217,10 @@ generate_fragment(struct llvmpipe_context *lp,
|
|||||||
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
||||||
lp_add_function_attr(function, i + 1, LP_FUNC_ATTR_NOALIAS);
|
lp_add_function_attr(function, i + 1, LP_FUNC_ATTR_NOALIAS);
|
||||||
|
|
||||||
if (variant->gallivm->cache->data_size)
|
if (variant->gallivm->cache->data_size) {
|
||||||
|
gallivm_stub_func(gallivm, function);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context_ptr = LLVMGetParam(function, 0);
|
context_ptr = LLVMGetParam(function, 0);
|
||||||
resources_ptr = LLVMGetParam(function, 1);
|
resources_ptr = LLVMGetParam(function, 1);
|
||||||
|
@@ -301,8 +301,10 @@ llvmpipe_fs_variant_linear_llvm(struct llvmpipe_context *lp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variant->gallivm->cache->data_size)
|
if (variant->gallivm->cache->data_size) {
|
||||||
|
gallivm_stub_func(gallivm, function);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LLVMValueRef context_ptr = LLVMGetParam(function, 0);
|
LLVMValueRef context_ptr = LLVMGetParam(function, 0);
|
||||||
LLVMValueRef x = LLVMGetParam(function, 1);
|
LLVMValueRef x = LLVMGetParam(function, 1);
|
||||||
|
Reference in New Issue
Block a user