#include <llvm/Config/llvm-config.h>
+#if LLVM_VERSION_MAJOR < 7
// Workaround http://llvm.org/PR23628
#pragma push_macro("DEBUG")
#undef DEBUG
+#endif
#include <llvm/Config/llvm-config.h>
#include <llvm-c/Core.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/PrettyStackTrace.h>
-
+#include <llvm/ExecutionEngine/ObjectCache.h>
#include <llvm/Support/TargetSelect.h>
+#if LLVM_VERSION_MAJOR < 11
#include <llvm/IR/CallSite.h>
+#endif
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/CBindingWrapping.h>
#include <llvm/ExecutionEngine/JITEventListener.h>
#endif
+#if LLVM_VERSION_MAJOR < 7
// Workaround http://llvm.org/PR23628
#pragma pop_macro("DEBUG")
+#endif
#include "c11/threads.h"
#include "os/os_thread.h"
extern "C" void
lp_set_target_options(void)
{
- /* The llvm target registry is not thread-safe, so drivers and state-trackers
+ /* The llvm target registry is not thread-safe, so drivers and gallium frontends
* that want to initialize targets should use the lp_set_target_options()
* function to safely initialize targets.
*
- * LLVM targets should be initialized before the driver or state-tracker tries
+ * LLVM targets should be initialized before the driver or gallium frontend tries
* to access the registry.
*/
call_once(&init_native_targets_once_flag, init_native_targets);
}
};
+class LPObjectCache : public llvm::ObjectCache {
+private:
+ bool has_object;
+ struct lp_cached_code *cache_out;
+public:
+ LPObjectCache(struct lp_cached_code *cache) {
+ cache_out = cache;
+ has_object = false;
+ }
+
+ ~LPObjectCache() {
+ }
+ void notifyObjectCompiled(const llvm::Module *M, llvm::MemoryBufferRef Obj) {
+ const std::string ModuleID = M->getModuleIdentifier();
+ if (has_object)
+ fprintf(stderr, "CACHE ALREADY HAS MODULE OBJECT\n");
+ has_object = true;
+ cache_out->data_size = Obj.getBufferSize();
+ cache_out->data = malloc(cache_out->data_size);
+ memcpy(cache_out->data, Obj.getBufferStart(), cache_out->data_size);
+ }
+
+ virtual std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module *M) {
+ if (cache_out->data_size) {
+ return llvm::MemoryBuffer::getMemBuffer(llvm::StringRef((const char *)cache_out->data, cache_out->data_size), "", false);
+ }
+ return NULL;
+ }
+
+};
/**
* Same as LLVMCreateJITCompilerForModule, but:
LLVMBool
lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT,
lp_generated_code **OutCode,
+ struct lp_cached_code *cache_out,
LLVMModuleRef M,
LLVMMCJITMemoryManagerRef CMM,
unsigned OptLevel,
* 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.
*/
-#if defined(PIPE_ARCH_LITTLE_ENDIAN) && defined(PIPE_ARCH_PPC_64)
+
+#ifdef PIPE_ARCH_PPC_64
+ /*
+ * 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).
+ */
+ builder.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
*/
if (MCPU == "generic")
MCPU = "pwr8";
+#endif
#endif
builder.setMCPU(MCPU);
if (gallivm_debug & (GALLIVM_DEBUG_IR | GALLIVM_DEBUG_ASM | GALLIVM_DEBUG_DUMP_BC)) {
ExecutionEngine *JIT;
JIT = builder.create();
+
+ if (cache_out) {
+ LPObjectCache *objcache = new LPObjectCache(cache_out);
+ JIT->setObjectCache(objcache);
+ cache_out->jit_obj_cache = (void *)objcache;
+ }
+
#if LLVM_USE_INTEL_JITEVENTS
JITEventListener *JEL = JITEventListener::createIntelJITEventListener();
JIT->RegisterJITEventListener(JEL);
delete reinterpret_cast<BaseMemoryManager*>(memorymgr);
}
+extern "C" void
+lp_free_objcache(void *objcache_ptr)
+{
+ LPObjectCache *objcache = (LPObjectCache *)objcache_ptr;
+ delete objcache;
+}
+
extern "C" LLVMValueRef
lp_get_called_value(LLVMValueRef call)
{