llvmpipe: add an implementation with llvm orcjit

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26018>
This commit is contained in:
Yukari Chiba
2024-06-25 13:50:51 +08:00
committed by Dave Airlie
parent 0b69b8d0db
commit 6f02ec5ed1
9 changed files with 658 additions and 5 deletions

View File

@@ -1734,6 +1734,7 @@ if with_clc
llvm_optional_modules += ['all-targets', 'windowsdriver', 'frontendhlsl', 'frontenddriver'] llvm_optional_modules += ['all-targets', 'windowsdriver', 'frontendhlsl', 'frontenddriver']
endif endif
draw_with_llvm = get_option('draw-use-llvm') draw_with_llvm = get_option('draw-use-llvm')
llvm_with_orcjit = get_option('llvm-orcjit')
if draw_with_llvm if draw_with_llvm
llvm_modules += 'native' llvm_modules += 'native'
# lto is needded with LLVM>=15, but we don't know what LLVM verrsion we are using yet # lto is needded with LLVM>=15, but we don't know what LLVM verrsion we are using yet
@@ -1741,7 +1742,7 @@ if draw_with_llvm
endif endif
amd_with_llvm = get_option('amd-use-llvm') amd_with_llvm = get_option('amd-use-llvm')
if with_amd_vk or with_gallium_radeonsi or with_clc if with_amd_vk or with_gallium_radeonsi or with_clc or llvm_with_orcjit
_llvm_version = '>= 15.0.0' _llvm_version = '>= 15.0.0'
elif with_gallium_clover elif with_gallium_clover
_llvm_version = '>= 11.0.0' _llvm_version = '>= 11.0.0'
@@ -1827,6 +1828,7 @@ amd_with_llvm = amd_with_llvm and with_llvm
pre_args += '-DLLVM_AVAILABLE=@0@'.format(with_llvm.to_int()) pre_args += '-DLLVM_AVAILABLE=@0@'.format(with_llvm.to_int())
pre_args += '-DDRAW_LLVM_AVAILABLE=@0@'.format((with_llvm and draw_with_llvm).to_int()) pre_args += '-DDRAW_LLVM_AVAILABLE=@0@'.format((with_llvm and draw_with_llvm).to_int())
pre_args += '-DAMD_LLVM_AVAILABLE=@0@'.format(amd_with_llvm.to_int()) pre_args += '-DAMD_LLVM_AVAILABLE=@0@'.format(amd_with_llvm.to_int())
pre_args += '-DGALLIVM_USE_ORCJIT=@0@'.format((with_llvm and llvm_with_orcjit).to_int())
if with_clover_spirv or with_clc if with_clover_spirv or with_clc
chosen_llvm_version_array = dep_llvm.version().split('.') chosen_llvm_version_array = dep_llvm.version().split('.')

View File

@@ -431,6 +431,13 @@ option(
'is included.' 'is included.'
) )
option (
'llvm-orcjit',
type : 'boolean',
value : false,
description: 'Build llvmpipe with LLVM ORCJIT support.'
)
option( option(
'valgrind', 'valgrind',
type : 'feature', type : 'feature',

View File

@@ -50,6 +50,10 @@
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#if GALLIVM_USE_ORCJIT
#include <llvm-c/Orc.h>
#endif
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@@ -132,7 +136,11 @@ LLVMBuildCall2(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
#endif /* LLVM_VERSION_MAJOR < 8 */ #endif /* LLVM_VERSION_MAJOR < 8 */
typedef struct lp_context_ref { typedef struct lp_context_ref {
#if GALLIVM_USE_ORCJIT
LLVMOrcThreadSafeContextRef ref;
#else
LLVMContextRef ref; LLVMContextRef ref;
#endif
bool owned; bool owned;
} lp_context_ref; } lp_context_ref;
@@ -140,11 +148,19 @@ static inline void
lp_context_create(lp_context_ref *context) lp_context_create(lp_context_ref *context)
{ {
assert(context != NULL); assert(context != NULL);
#if GALLIVM_USE_ORCJIT
context->ref = LLVMOrcCreateNewThreadSafeContext();
#else
context->ref = LLVMContextCreate(); context->ref = LLVMContextCreate();
#endif
context->owned = true; context->owned = true;
#if LLVM_VERSION_MAJOR == 15 #if LLVM_VERSION_MAJOR == 15
if (context->ref) { if (context->ref) {
#if GALLIVM_USE_ORCJIT
LLVMContextSetOpaquePointers(LLVMOrcThreadSafeContextGetContext(context->ref), false);
#else
LLVMContextSetOpaquePointers(context->ref, false); LLVMContextSetOpaquePointers(context->ref, false);
#endif
} }
#endif #endif
} }
@@ -154,7 +170,11 @@ lp_context_destroy(lp_context_ref *context)
{ {
assert(context != NULL); assert(context != NULL);
if (context->owned) { if (context->owned) {
#if GALLIVM_USE_ORCJIT
LLVMOrcDisposeThreadSafeContext(context->ref);
#else
LLVMContextDispose(context->ref); LLVMContextDispose(context->ref);
#endif
context->ref = NULL; context->ref = NULL;
} }
} }

View File

@@ -161,7 +161,9 @@ coro_free(char *ptr)
void lp_build_coro_add_malloc_hooks(struct gallivm_state *gallivm) void lp_build_coro_add_malloc_hooks(struct gallivm_state *gallivm)
{ {
#if !GALLIVM_USE_ORCJIT
assert(gallivm->engine); assert(gallivm->engine);
#endif
assert(gallivm->coro_malloc_hook); assert(gallivm->coro_malloc_hook);
assert(gallivm->coro_free_hook); assert(gallivm->coro_free_hook);

View File

@@ -35,7 +35,12 @@
#include "util/u_cpu_detect.h" #include "util/u_cpu_detect.h"
#include "lp_bld.h" #include "lp_bld.h"
#include "lp_bld_passmgr.h" #include "lp_bld_passmgr.h"
#if GALLIVM_USE_ORCJIT
#include <llvm-c/Orc.h>
#else
#include <llvm-c/ExecutionEngine.h> #include <llvm-c/ExecutionEngine.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -46,13 +51,20 @@ struct gallivm_state
{ {
char *module_name; char *module_name;
LLVMModuleRef module; LLVMModuleRef module;
LLVMExecutionEngineRef engine;
LLVMTargetDataRef target; LLVMTargetDataRef target;
#if GALLIVM_USE_ORCJIT
/* own this->module */
LLVMOrcThreadSafeContextRef _ts_context;
/* each module is in its own jitdylib */
LLVMOrcJITDylibRef _per_module_jd;
#else
LLVMExecutionEngineRef engine;
struct lp_passmgr *passmgr; struct lp_passmgr *passmgr;
LLVMContextRef context;
LLVMBuilderRef builder;
LLVMMCJITMemoryManagerRef memorymgr; LLVMMCJITMemoryManagerRef memorymgr;
struct lp_generated_code *code; struct lp_generated_code *code;
#endif
LLVMContextRef context;
LLVMBuilderRef builder;
struct lp_cached_code *cache; struct lp_cached_code *cache;
unsigned compiled; unsigned compiled;
LLVMValueRef coro_malloc_hook; LLVMValueRef coro_malloc_hook;

View File

@@ -0,0 +1,592 @@
/*
* Copyright (c) 2022 Alex Fan <alex.fan.q@gmail.com>
* SPDX-License-Identifier: MIT
*/
#include "util/detect.h"
#include "util/u_cpu_detect.h"
#include "util/u_debug.h"
#include "util/os_time.h"
#include <string>
#include <vector>
#include "lp_bld.h"
#include "lp_bld_debug.h"
#include "lp_bld_init.h"
#include "lp_bld_coro.h"
#include "lp_bld_misc.h"
#include "lp_bld_printf.h"
#include "lp_bld_passmgr.h"
#include "lp_bld_type.h"
#include <llvm/Config/llvm-config.h>
#include <llvm-c/Core.h>
#include <llvm-c/Orc.h>
#include <llvm-c/LLJIT.h>
#include <llvm-c/TargetMachine.h>
#include <llvm-c/Support.h>
#include <llvm-c/Analysis.h>
#if LLVM_VERSION_MAJOR < 17
#include <llvm-c/Transforms/Scalar.h>
#if LLVM_VERSION_MAJOR >= 7
#include <llvm-c/Transforms/Utils.h>
#endif
#endif
#include <llvm-c/BitWriter.h>
#include <llvm/ADT/StringMap.h>
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include <llvm/Target/TargetMachine.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Casting.h>
#if LLVM_VERSION_MAJOR >= 18
#include <llvm/TargetParser/Host.h>
#else
#include <llvm/Support/Host.h>
#endif
#include <llvm/Support/CBindingWrapping.h>
#if LLVM_USE_INTEL_JITEVENTS
#include <llvm/ExecutionEngine/JITEventListener.h>
#endif
/* conflict with ObjectLinkingLayer.h */
#include "util/u_memory.h"
#if DETECT_ARCH_RISCV64 == 1 || DETECT_ARCH_RISCV32 == 1 || (defined(_WIN32) && LLVM_VERSION_MAJOR >= 15)
/* use ObjectLinkingLayer (JITLINK backend) */
#define USE_JITLINK
#endif
/* else use old RTDyldObjectLinkingLayer (RuntimeDyld backend) */
namespace {
class LPJit;
class LLVMEnsureMultithreaded {
public:
LLVMEnsureMultithreaded()
{
if (!LLVMIsMultithreaded()) {
LLVMStartMultithreaded();
}
}
};
LLVMEnsureMultithreaded lLVMEnsureMultithreaded;
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::orc::ThreadSafeContext,
LLVMOrcThreadSafeContextRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::orc::IRTransformLayer,
LLVMOrcIRTransformLayerRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::orc::JITDylib, LLVMOrcJITDylibRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::orc::JITTargetMachineBuilder,
LLVMOrcJITTargetMachineBuilderRef)
LLVMTargetMachineRef wrap(const llvm::TargetMachine *P) {
return reinterpret_cast<LLVMTargetMachineRef>(const_cast<llvm::TargetMachine*>(P));
}
llvm::ExitOnError ExitOnErr;
inline const char* get_module_name(LLVMModuleRef mod) {
using llvm::Module;
return llvm::unwrap(mod)->getModuleIdentifier().c_str();
}
once_flag init_lpjit_once_flag = ONCE_FLAG_INIT;
/* A JIT singleton built upon LLJIT */
class LPJit
{
public:
static LPJit* get_instance() {
call_once(&init_lpjit_once_flag, init_lpjit);
return jit;
}
gallivm_state *find_gallivm_state(LLVMModuleRef mod) {
#if DEBUG
using llvm::Module;
auto I = gallivm_modules.find(llvm::unwrap(mod)->getModuleIdentifier());
if (I == gallivm_modules.end()) {
debug_printf("No gallivm state found for module: %s", get_module_name(mod));
return NULL;
}
return I->second;
#endif
return NULL;
}
static char *get_unique_name(const char* name) {
LPJit* jit = get_instance();
size_t size = name == NULL? 16: strlen(name) + 16;
char *name_uniq = (char *)MALLOC(size);
if (!name_uniq) {
return NULL;
}
do {
snprintf(name_uniq, size, "%s_%u", name, jit->jit_dylib_count++);
} while(jit->lljit->getExecutionSession().getJITDylibByName(name_uniq));
return name_uniq;
}
static LLVMOrcJITDylibRef create_jit_dylib(const char * name) {
using llvm::orc::JITDylib;
LPJit* jit = get_instance();
JITDylib& tmp = ExitOnErr(jit->lljit->createJITDylib(name));
return wrap(&tmp);
}
static void register_gallivm_state(gallivm_state *gallivm) {
#if DEBUG
LPJit* jit = get_instance();
jit->gallivm_modules[gallivm->module_name] = gallivm;
#endif
}
static void deregister_gallivm_state(gallivm_state *gallivm) {
#if DEBUG
LPJit* jit = get_instance();
(void)jit->gallivm_modules.erase(gallivm->module_name);
#endif
}
static void add_ir_module_to_jd(
LLVMOrcThreadSafeContextRef ts_context,
LLVMModuleRef mod,
LLVMOrcJITDylibRef jd) {
using llvm::Module;
using llvm::orc::ThreadSafeModule;
using llvm::orc::JITDylib;
ThreadSafeModule tsm(
std::unique_ptr<Module>(llvm::unwrap(mod)), *::unwrap(ts_context));
ExitOnErr(get_instance()->lljit->addIRModule(
*::unwrap(jd), std::move(tsm)
));
}
static void add_mapping_to_jd(
LLVMValueRef sym,
void *addr,
LLVMOrcJITDylibRef jd) {
#if LLVM_VERSION_MAJOR >= 17
using llvm::orc::ExecutorAddr;
using llvm::orc::ExecutorSymbolDef;
using llvm::JITSymbolFlags;
#else
using llvm::JITEvaluatedSymbol;
#endif
using llvm::orc::ExecutionSession;
using llvm::orc::JITDylib;
using llvm::orc::SymbolMap;
JITDylib* JD = ::unwrap(jd);
auto& es = LPJit::get_instance()->lljit->getExecutionSession();
auto name = es.intern(llvm::unwrap(sym)->getName());
SymbolMap map(1);
#if LLVM_VERSION_MAJOR >= 17
map[name] = ExecutorSymbolDef(ExecutorAddr::fromPtr(addr), JITSymbolFlags::Exported);
#else
map[name] = JITEvaluatedSymbol::fromPointer(addr);
#endif
auto munit = llvm::orc::absoluteSymbols(map);
llvm::cantFail(JD->define(std::move(munit)));
}
static void *lookup_in_jd(
const char *func_name,
LLVMOrcJITDylibRef jd) {
using llvm::orc::JITDylib;
using llvm::JITEvaluatedSymbol;
using llvm::orc::ExecutorAddr;
JITDylib* JD = ::unwrap(jd);
auto func = ExitOnErr(LPJit::get_instance()->lljit->lookup(*JD, func_name));
#if LLVM_VERSION_MAJOR >= 15
return func.toPtr<void *>();
#else
return (void *)(func.getAddress());
#endif
}
static void remove_jd(LLVMOrcJITDylibRef jd) {
using llvm::orc::ExecutionSession;
using llvm::orc::JITDylib;
auto& es = LPJit::get_instance()->lljit->getExecutionSession();
ExitOnErr(es.removeJITDylib(* ::unwrap(jd)));
}
LLVMTargetMachineRef tm;
private:
LPJit();
~LPJit() = default;
LPJit(const LPJit&) = delete;
LPJit& operator=(const LPJit&) = delete;
static void init_native_targets();
llvm::orc::JITTargetMachineBuilder create_jtdb();
static void init_lpjit() {
jit = new LPJit;
}
static LPJit* jit;
std::unique_ptr<llvm::orc::LLJIT> lljit;
/* avoid name conflict */
unsigned jit_dylib_count;
#if DEBUG
/* map from module name to gallivm_state */
llvm::StringMap<gallivm_state *> gallivm_modules;
#endif
};
LPJit* LPJit::jit = NULL;
LLVMErrorRef module_transform(void *Ctx, LLVMModuleRef mod) {
struct lp_passmgr *mgr;
lp_passmgr_create(mod, &mgr);
lp_passmgr_run(mgr, mod,
LPJit::get_instance()->tm,
get_module_name(mod));
lp_passmgr_dispose(mgr);
return LLVMErrorSuccess;
}
LLVMErrorRef module_transform_wrapper(
void *Ctx, LLVMOrcThreadSafeModuleRef *ModInOut,
LLVMOrcMaterializationResponsibilityRef MR) {
return LLVMOrcThreadSafeModuleWithModuleDo(*ModInOut, *module_transform, Ctx);
}
LPJit::LPJit() :jit_dylib_count(0) {
using namespace llvm::orc;
lp_init_env_options();
init_native_targets();
JITTargetMachineBuilder JTMB = create_jtdb();
tm = wrap(ExitOnErr(JTMB.createTargetMachine()).release());
/* Create an LLJIT instance with an ObjectLinkingLayer (JITLINK)
* or RuntimeDyld as the base layer.
* intel & perf listeners are not supported by ObjectLinkingLayer yet
*/
lljit = ExitOnErr(
LLJITBuilder()
.setJITTargetMachineBuilder(std::move(JTMB))
#ifdef USE_JITLINK
.setObjectLinkingLayerCreator(
[&](ExecutionSession &ES, const llvm::Triple &TT) {
return std::make_unique<ObjectLinkingLayer>(
ES, ExitOnErr(llvm::jitlink::InProcessMemoryManager::Create()));
})
#else
#if LLVM_USE_INTEL_JITEVENTS
.RegisterJITEventListener(
llvm::JITEventListener::createIntelJITEventListener())
#endif
#endif
.create());
LLVMOrcIRTransformLayerRef TL = wrap(&lljit->getIRTransformLayer());
LLVMOrcIRTransformLayerSetTransform(TL, *module_transform_wrapper, NULL);
}
void LPJit::init_native_targets() {
lp_bld_init_native_targets();
lp_build_init_native_width();
lp_bld_ppc_disable_denorms();
}
llvm::orc::JITTargetMachineBuilder LPJit::create_jtdb() {
using namespace llvm;
using orc::JITTargetMachineBuilder;
#if defined(_WIN32) && LLVM_VERSION_MAJOR < 15
/*
* JITLink works on Windows, but only through ELF object format.
*
* XXX: We could use `LLVM_HOST_TRIPLE "-elf"` but LLVM_HOST_TRIPLE has
* different strings for MinGW/MSVC, so better play it safe and be
* explicit.
*/
# ifdef _WIN64
JITTargetMachineBuilder JTMB((Triple("x86_64-pc-win32-elf")));
# else
JITTargetMachineBuilder JTMB((Triple("i686-pc-win32-elf")));
# endif
#else
/*
* llvm::sys::getProcessTriple() is bogus. It returns the host LLVM was
* compiled on. Be careful when doing cross compilation
*/
JITTargetMachineBuilder JTMB((Triple(sys::getProcessTriple())));
#endif
TargetOptions options;
/**
* LLVM 3.1+ haven't more "extern unsigned llvm::StackAlignmentOverride" and
* friends for configuring code generation options, like stack alignment.
*/
#if DETECT_ARCH_X86 == 1 && LLVM_VERSION_MAJOR < 13
options.StackAlignmentOverride = 4;
#endif
#if DETECT_ARCH_RISCV64 == 1
#if defined(__riscv_float_abi_soft)
options.MCOptions.ABIName = "lp64";
#elif defined(__riscv_float_abi_single)
options.MCOptions.ABIName = "lp64f";
#elif defined(__riscv_float_abi_double)
options.MCOptions.ABIName = "lp64d";
#else
#error "GALLIVM: unknown target riscv float abi"
#endif
#endif
#if DETECT_ARCH_RISCV32 == 1
#if defined(__riscv_float_abi_soft)
options.MCOptions.ABIName = "ilp32";
#elif defined(__riscv_float_abi_single)
options.MCOptions.ABIName = "ilp32f";
#elif defined(__riscv_float_abi_double)
options.MCOptions.ABIName = "ilp32d";
#else
#error "GALLIVM: unknown target riscv float abi"
#endif
#endif
JTMB.setOptions(options);
std::vector<std::string> MAttrs;
lp_build_fill_mattrs(MAttrs);
JTMB.addFeatures(MAttrs);
lp_build_dump_mattrs(MAttrs);
std::string MCPU = llvm::sys::getHostCPUName().str();
/*
* Note that the MAttrs set above will be sort of ignored (since we should
* not set any which would not be set by specifying the cpu anyway).
* It ought to be safe though since getHostCPUName() should include bits
* not only from the cpu but environment as well (for instance if it's safe
* to use avx instructions which need OS support). According to
* http://llvm.org/bugs/show_bug.cgi?id=19429 however if I understand this
* right it may be necessary to specify older cpu (or disable mattrs) though
* when not using MCJIT so no instructions are generated which the old JIT
* can't handle. Not entirely sure if we really need to do anything yet.
*
* Not sure if the above is also the case for ORCJIT, but we need set CPU
* manually since we don't use JITTargetMachineBuilder::detectHost()
*/
#if DETECT_ARCH_PPC_64 == 1
/*
* Large programs, e.g. gnome-shell and firefox, may tax the addressability
* of the Medium code model once dynamically generated JIT-compiled shader
* programs are linked in and relocated. Yet the default code model as of
* LLVM 8 is Medium or even Small.
* The cost of changing from Medium to Large is negligible:
* - an additional 8-byte pointer stored immediately before the shader entrypoint;
* - change an add-immediate (addis) instruction to a load (ld).
*/
JTMB.setCodeModel(CodeModel::Large);
#if UTIL_ARCH_LITTLE_ENDIAN
/*
* Versions of LLVM prior to 4.0 lacked a table entry for "POWER8NVL",
* resulting in (big-endian) "generic" being returned on
* little-endian Power8NVL systems. The result was that code that
* attempted to load the least significant 32 bits of a 64-bit quantity
* from memory loaded the wrong half. This resulted in failures in some
* Piglit tests, e.g.
* .../arb_gpu_shader_fp64/execution/conversion/frag-conversion-explicit-double-uint
*/
if (MCPU == "generic")
MCPU = "pwr8";
#endif
#endif
#if DETECT_ARCH_MIPS64 == 1
/*
* ls3a4000 CPU and ls2k1000 SoC is a mips64r5 compatible with MSA SIMD
* instruction set implemented, while ls3a3000 is mips64r2 compatible
* only. getHostCPUName() return "generic" on all loongson
* mips CPU currently. So we override the MCPU to mips64r5 if MSA is
* implemented, feedback to mips64r2 for all other ordinary mips64 cpu.
*/
if (MCPU == "generic")
MCPU = util_get_cpu_caps()->has_msa ? "mips64r5" : "mips64r2";
#endif
#if DETECT_ARCH_RISCV64 == 1
/**
* should be fixed with https://reviews.llvm.org/D121149 in llvm 15,
* set it anyway for llvm 14
*/
if (MCPU == "generic")
MCPU = "generic-rv64";
JTMB.setCodeModel(CodeModel::Medium);
JTMB.setRelocationModel(Reloc::PIC_);
#endif
#if DETECT_ARCH_RISCV32 == 1
/**
* should be fixed with https://reviews.llvm.org/D121149 in llvm 15,
* set it anyway for llvm 14
*/
if (MCPU == "generic")
MCPU = "generic-rv32";
JTMB.setCodeModel(CodeModel::Medium);
JTMB.setRelocationModel(Reloc::PIC_);
#endif
JTMB.setCPU(MCPU);
if (gallivm_debug & (GALLIVM_DEBUG_IR | GALLIVM_DEBUG_ASM | GALLIVM_DEBUG_DUMP_BC)) {
debug_printf("llc -mcpu option: %s\n", MCPU.c_str());
}
return JTMB;
}
} /* Anonymous namespace */
bool
lp_build_init(void)
{
(void)LPJit::get_instance();
return true;
}
bool
init_gallivm_state(struct gallivm_state *gallivm, const char *name,
lp_context_ref *context, struct lp_cached_code *cache)
{
assert(!gallivm->context);
assert(!gallivm->_ts_context);
assert(!gallivm->module);
if (!lp_build_init())
return false;
// cache is not implemented
gallivm->cache = cache;
if (gallivm->cache)
gallivm->cache->data_size = 0;
gallivm->_ts_context = context->ref;
gallivm->context = LLVMOrcThreadSafeContextGetContext(context->ref);
gallivm->module_name = LPJit::get_unique_name(name);
gallivm->module = LLVMModuleCreateWithNameInContext(gallivm->module_name,
gallivm->context);
#if DETECT_ARCH_X86 == 1
lp_set_module_stack_alignment_override(gallivm->module, 4);
#endif
gallivm->builder = LLVMCreateBuilderInContext(gallivm->context);
gallivm->_per_module_jd = LPJit::create_jit_dylib(gallivm->module_name);
gallivm->target = LLVMCreateTargetDataLayout(LPJit::get_instance()->tm);
lp_build_coro_declare_malloc_hooks(gallivm);
return true;
}
struct gallivm_state *
gallivm_create(const char *name, lp_context_ref *context,
struct lp_cached_code *cache){
struct gallivm_state *gallivm;
gallivm = CALLOC_STRUCT(gallivm_state);
if (gallivm) {
if (!init_gallivm_state(gallivm, name, context, cache)) {
FREE(gallivm);
gallivm = NULL;
}
}
assert(gallivm != NULL);
return gallivm;
}
void
gallivm_destroy(struct gallivm_state *gallivm)
{
LPJit::remove_jd(gallivm->_per_module_jd);
gallivm->_per_module_jd = nullptr;
FREE(gallivm);
}
void
gallivm_free_ir(struct gallivm_state *gallivm)
{
if (gallivm->module)
LLVMDisposeModule(gallivm->module);
FREE(gallivm->module_name);
if (gallivm->target) {
LLVMDisposeTargetData(gallivm->target);
}
if (gallivm->builder)
LLVMDisposeBuilder(gallivm->builder);
gallivm->target = NULL;
gallivm->module=NULL;
gallivm->module_name=NULL;
gallivm->builder=NULL;
gallivm->context=NULL;
gallivm->_ts_context=NULL;
gallivm->cache=NULL;
LPJit::deregister_gallivm_state(gallivm);
}
void
gallivm_add_global_mapping(struct gallivm_state *gallivm, LLVMValueRef sym, void* addr)
{
LPJit::add_mapping_to_jd(sym, addr, gallivm->_per_module_jd);
}
void
gallivm_compile_module(struct gallivm_state *gallivm)
{
lp_init_printf_hook(gallivm);
gallivm_add_global_mapping(gallivm, gallivm->debug_printf_hook,
(void *)debug_printf);
lp_init_clock_hook(gallivm);
gallivm_add_global_mapping(gallivm, gallivm->get_time_hook,
(void *)os_time_get_nano);
lp_build_coro_add_malloc_hooks(gallivm);
LPJit::add_ir_module_to_jd(gallivm->_ts_context, gallivm->module,
gallivm->_per_module_jd);
/* ownership of module is now transferred into orc jit,
* disallow modifying it
*/
LPJit::register_gallivm_state(gallivm);
gallivm->module = nullptr;
/* defer compilation till first lookup by gallivm_jit_function */
}
func_pointer
gallivm_jit_function(struct gallivm_state *gallivm,
LLVMValueRef func, const char *func_name)
{
return pointer_to_func(
LPJit::lookup_in_jd(func_name, gallivm->_per_module_jd));
}

View File

@@ -329,7 +329,6 @@ if draw_with_llvm
'gallivm/lp_bld_gather.c', 'gallivm/lp_bld_gather.c',
'gallivm/lp_bld_gather.h', 'gallivm/lp_bld_gather.h',
'gallivm/lp_bld.h', 'gallivm/lp_bld.h',
'gallivm/lp_bld_init.c',
'gallivm/lp_bld_init_common.c', 'gallivm/lp_bld_init_common.c',
'gallivm/lp_bld_init.h', 'gallivm/lp_bld_init.h',
'gallivm/lp_bld_intr.c', 'gallivm/lp_bld_intr.c',
@@ -384,6 +383,11 @@ if draw_with_llvm
'nir/nir_to_tgsi_info.c', 'nir/nir_to_tgsi_info.c',
'nir/nir_to_tgsi_info.h', 'nir/nir_to_tgsi_info.h',
) )
if llvm_with_orcjit
files_libgallium += files('gallivm/lp_bld_init_orc.cpp',)
else
files_libgallium += files('gallivm/lp_bld_init.c',)
endif
endif endif
files_libgalliumvl = files( files_libgalliumvl = files(

View File

@@ -1274,9 +1274,16 @@ generate_variant(struct llvmpipe_context *lp,
generate_compute(lp, shader, variant); generate_compute(lp, shader, variant);
#if GALLIVM_USE_ORCJIT
/* module has been moved into ORCJIT after gallivm_compile_module */
variant->nr_instrs += lp_build_count_ir_module(variant->gallivm->module);
gallivm_compile_module(variant->gallivm);
#else
gallivm_compile_module(variant->gallivm); gallivm_compile_module(variant->gallivm);
variant->nr_instrs += lp_build_count_ir_module(variant->gallivm->module); variant->nr_instrs += lp_build_count_ir_module(variant->gallivm->module);
#endif
variant->jit_function = (lp_jit_cs_func) variant->jit_function = (lp_jit_cs_func)
gallivm_jit_function(variant->gallivm, variant->function, variant->function_name); gallivm_jit_function(variant->gallivm, variant->function, variant->function_name);

View File

@@ -3916,9 +3916,16 @@ generate_variant(struct llvmpipe_context *lp,
* Compile everything * Compile everything
*/ */
#if GALLIVM_USE_ORCJIT
/* module has been moved into ORCJIT after gallivm_compile_module */
variant->nr_instrs += lp_build_count_ir_module(variant->gallivm->module);
gallivm_compile_module(variant->gallivm);
#else
gallivm_compile_module(variant->gallivm); gallivm_compile_module(variant->gallivm);
variant->nr_instrs += lp_build_count_ir_module(variant->gallivm->module); variant->nr_instrs += lp_build_count_ir_module(variant->gallivm->module);
#endif
if (variant->function[RAST_EDGE_TEST]) { if (variant->function[RAST_EDGE_TEST]) {
variant->jit_function[RAST_EDGE_TEST] = (lp_jit_frag_func) variant->jit_function[RAST_EDGE_TEST] = (lp_jit_frag_func)