X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Fgallivm%2Flp_bld_misc.cpp;h=bd4d4d3c0947380d73e13e2df6da4ff3432c54d3;hb=c2a602d21a4dd7da9d3226a70cb83ab85ceb446a;hp=024819ece190e97d98a9a81b5b7a6168d518d563;hpb=dbb690872eb0f3578880bbf8e58b8816078f912c;p=mesa.git diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp index 024819ece19..bd4d4d3c094 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp +++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp @@ -50,171 +50,413 @@ #include +// Workaround http://llvm.org/PR23628 +#if HAVE_LLVM >= 0x0307 +# pragma push_macro("DEBUG") +# undef DEBUG +#endif + #include #include #include #include -#if HAVE_LLVM >= 0x0301 #include +#if HAVE_LLVM >= 0x0307 +#include +#else +#include +#endif +#if HAVE_LLVM < 0x0306 #include +#else +#include #endif #include +#include #include -#if HAVE_LLVM >= 0x0300 #include -#else /* HAVE_LLVM < 0x0300 */ -#include -#endif /* HAVE_LLVM < 0x0300 */ -#include "pipe/p_config.h" -#include "util/u_debug.h" -#include "util/u_cpu_detect.h" - -#include "lp_bld_misc.h" - - -extern "C" void -lp_set_target_options(void) -{ -#if HAVE_LLVM <= 0x0300 -#if defined(DEBUG) -#if HAVE_LLVM >= 0x0207 - llvm::JITEmitDebugInfo = true; -#endif +#if HAVE_LLVM >= 0x0305 +#include #endif +#include +#include +#include - /* - * LLVM revision 123367 switched the default stack alignment to 16 bytes on - * Linux (and several other Unices in later revisions), to match recent gcc - * versions. - * - * However our drivers can be loaded by old binary applications, still - * maintaining a 4 bytes stack alignment. Therefore we must tell LLVM here - * to only assume a 4 bytes alignment for backwards compatibility. - */ -#if defined(PIPE_ARCH_X86) -#if HAVE_LLVM == 0x0300 - llvm::StackAlignmentOverride = 4; -#else - llvm::StackAlignment = 4; -#endif +#include +#if LLVM_USE_INTEL_JITEVENTS +#include #endif -#if defined(DEBUG) || defined(PROFILE) - llvm::NoFramePointerElim = true; -#if HAVE_LLVM >= 0x0208 - llvm::NoFramePointerElimNonLeaf = true; -#endif +// Workaround http://llvm.org/PR23628 +#if HAVE_LLVM >= 0x0307 +# pragma pop_macro("DEBUG") #endif - llvm::NoExcessFPPrecision = false; +#include "c11/threads.h" +#include "os/os_thread.h" +#include "pipe/p_config.h" +#include "util/u_debug.h" +#include "util/u_cpu_detect.h" - /* XXX: Investigate this */ -#if 0 - llvm::UnsafeFPMath = true; -#endif -#endif /* HAVE_LLVM <= 0x0300 */ +#include "lp_bld_misc.h" -#if HAVE_LLVM < 0x0209 - /* - * LLVM will generate MMX instructions for vectors <= 64 bits, leading to - * innefficient code, and in 32bit systems, to the corruption of the FPU - * stack given that it expects the user to generate the EMMS instructions. - * - * See also: - * - http://llvm.org/bugs/show_bug.cgi?id=3287 - * - http://l4.me.uk/post/2009/06/07/llvm-wrinkle-3-configuration-what-configuration/ - * - * The -disable-mmx global option can be specified only once since we - * dynamically link against LLVM it will reside in a separate shared object, - * which may or not be delete when this shared object is, so we use the - * llvm::DisablePrettyStackTrace variable (which we set below and should - * reside in the same shared library) to determine whether the -disable-mmx - * option has been set or not. - * - * Thankfully this ugly hack is not necessary on LLVM 2.9 onwards. - */ - if (!llvm::DisablePrettyStackTrace) { - static boolean first = TRUE; - static const char* options[] = { - "prog", - "-disable-mmx" - }; - assert(first); - llvm::cl::ParseCommandLineOptions(2, const_cast(options)); - first = FALSE; +namespace { + +class LLVMEnsureMultithreaded { +public: + LLVMEnsureMultithreaded() + { + if (!LLVMIsMultithreaded()) { + LLVMStartMultithreaded(); + } } -#endif +}; - /* - * By default LLVM adds a signal handler to output a pretty stack trace. - * This signal handler is never removed, causing problems when unloading the - * shared object where the gallium driver resides. - */ - llvm::DisablePrettyStackTrace = true; +static LLVMEnsureMultithreaded lLVMEnsureMultithreaded; + +} + +static once_flag init_native_targets_once_flag = ONCE_FLAG_INIT; +static void init_native_targets() +{ // If we have a native target, initialize it to ensure it is linked in and // usable by the JIT. llvm::InitializeNativeTarget(); -#if HAVE_LLVM >= 0x0208 llvm::InitializeNativeTargetAsmPrinter(); -#elif defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) - LLVMInitializeX86AsmPrinter(); -#elif defined(PIPE_ARCH_ARM) - LLVMInitializeARMAsmPrinter(); -#elif defined(PIPE_ARCH_PPC) - LLVMInitializePowerPCAsmPrinter(); -#endif -#if HAVE_LLVM >= 0x0207 -# if HAVE_LLVM >= 0x0301 llvm::InitializeNativeTargetDisassembler(); -# elif defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) - LLVMInitializeX86Disassembler(); -# elif defined(PIPE_ARCH_ARM) - LLVMInitializeARMDisassembler(); -# endif -#endif } - +/** + * The llvm target registry is not thread-safe, so drivers and state-trackers + * that want to initialize targets should use the gallivm_init_llvm_targets() + * function to safely initialize targets. + * + * LLVM targets should be initialized before the driver or state-tracker tries + * to access the registry. + */ extern "C" void -lp_func_delete_body(LLVMValueRef FF) +gallivm_init_llvm_targets(void) { - llvm::Function *func = llvm::unwrap(FF); - func->deleteBody(); + call_once(&init_native_targets_once_flag, init_native_targets); } +extern "C" void +lp_set_target_options(void) +{ +#if HAVE_LLVM < 0x0304 + /* + * By default LLVM adds a signal handler to output a pretty stack trace. + * This signal handler is never removed, causing problems when unloading the + * shared object where the gallium driver resides. + */ + llvm::DisablePrettyStackTrace = true; +#endif + + gallivm_init_llvm_targets(); +} extern "C" -LLVMValueRef -lp_build_load_volatile(LLVMBuilderRef B, LLVMValueRef PointerVal, - const char *Name) +LLVMTargetLibraryInfoRef +gallivm_create_target_library_info(const char *triple) { - return llvm::wrap(llvm::unwrap(B)->CreateLoad(llvm::unwrap(PointerVal), true, Name)); + return reinterpret_cast( +#if HAVE_LLVM < 0x0307 + new llvm::TargetLibraryInfo( +#else + new llvm::TargetLibraryInfoImpl( +#endif + llvm::Triple(triple))); } - extern "C" void -lp_set_load_alignment(LLVMValueRef Inst, - unsigned Align) +gallivm_dispose_target_library_info(LLVMTargetLibraryInfoRef library_info) { - llvm::unwrap(Inst)->setAlignment(Align); + delete reinterpret_cast< +#if HAVE_LLVM < 0x0307 + llvm::TargetLibraryInfo +#else + llvm::TargetLibraryInfoImpl +#endif + *>(library_info); } + +#if HAVE_LLVM < 0x0304 + extern "C" void -lp_set_store_alignment(LLVMValueRef Inst, - unsigned Align) +LLVMSetAlignmentBackport(LLVMValueRef V, + unsigned Bytes) { - llvm::unwrap(Inst)->setAlignment(Align); + switch (LLVMGetInstructionOpcode(V)) { + case LLVMLoad: + llvm::unwrap(V)->setAlignment(Bytes); + break; + case LLVMStore: + llvm::unwrap(V)->setAlignment(Bytes); + break; + default: + assert(0); + break; + } } +#endif + + +#if HAVE_LLVM < 0x0306 +typedef llvm::JITMemoryManager BaseMemoryManager; +#else +typedef llvm::RTDyldMemoryManager BaseMemoryManager; +#endif + + +/* + * Delegating is tedious but the default manager class is hidden in an + * anonymous namespace in LLVM, so we cannot just derive from it to change + * its behavior. + */ +class DelegatingJITMemoryManager : public BaseMemoryManager { + + protected: + virtual BaseMemoryManager *mgr() const = 0; + + public: +#if HAVE_LLVM < 0x0306 + /* + * From JITMemoryManager + */ + virtual void setMemoryWritable() { + mgr()->setMemoryWritable(); + } + virtual void setMemoryExecutable() { + mgr()->setMemoryExecutable(); + } + virtual void setPoisonMemory(bool poison) { + mgr()->setPoisonMemory(poison); + } + virtual void AllocateGOT() { + mgr()->AllocateGOT(); + /* + * isManagingGOT() is not virtual in base class so we can't delegate. + * Instead we mirror the value of HasGOT in our instance. + */ + HasGOT = mgr()->isManagingGOT(); + } + virtual uint8_t *getGOTBase() const { + return mgr()->getGOTBase(); + } + virtual uint8_t *startFunctionBody(const llvm::Function *F, + uintptr_t &ActualSize) { + return mgr()->startFunctionBody(F, ActualSize); + } + virtual uint8_t *allocateStub(const llvm::GlobalValue *F, + unsigned StubSize, + unsigned Alignment) { + return mgr()->allocateStub(F, StubSize, Alignment); + } + virtual void endFunctionBody(const llvm::Function *F, + uint8_t *FunctionStart, + uint8_t *FunctionEnd) { + mgr()->endFunctionBody(F, FunctionStart, FunctionEnd); + } + virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { + return mgr()->allocateSpace(Size, Alignment); + } + virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) { + return mgr()->allocateGlobal(Size, Alignment); + } + virtual void deallocateFunctionBody(void *Body) { + mgr()->deallocateFunctionBody(Body); + } +#if HAVE_LLVM < 0x0304 + virtual uint8_t *startExceptionTable(const llvm::Function *F, + uintptr_t &ActualSize) { + return mgr()->startExceptionTable(F, ActualSize); + } + virtual void endExceptionTable(const llvm::Function *F, + uint8_t *TableStart, + uint8_t *TableEnd, + uint8_t *FrameRegister) { + mgr()->endExceptionTable(F, TableStart, TableEnd, + FrameRegister); + } + virtual void deallocateExceptionTable(void *ET) { + mgr()->deallocateExceptionTable(ET); + } +#endif + virtual bool CheckInvariants(std::string &s) { + return mgr()->CheckInvariants(s); + } + virtual size_t GetDefaultCodeSlabSize() { + return mgr()->GetDefaultCodeSlabSize(); + } + virtual size_t GetDefaultDataSlabSize() { + return mgr()->GetDefaultDataSlabSize(); + } + virtual size_t GetDefaultStubSlabSize() { + return mgr()->GetDefaultStubSlabSize(); + } + virtual unsigned GetNumCodeSlabs() { + return mgr()->GetNumCodeSlabs(); + } + virtual unsigned GetNumDataSlabs() { + return mgr()->GetNumDataSlabs(); + } + virtual unsigned GetNumStubSlabs() { + return mgr()->GetNumStubSlabs(); + } +#endif + + /* + * From RTDyldMemoryManager + */ +#if HAVE_LLVM >= 0x0304 + virtual uint8_t *allocateCodeSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID, + llvm::StringRef SectionName) { + return mgr()->allocateCodeSection(Size, Alignment, SectionID, + SectionName); + } +#else + virtual uint8_t *allocateCodeSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID) { + return mgr()->allocateCodeSection(Size, Alignment, SectionID); + } +#endif + virtual uint8_t *allocateDataSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID, +#if HAVE_LLVM >= 0x0304 + llvm::StringRef SectionName, +#endif + bool IsReadOnly) { + return mgr()->allocateDataSection(Size, Alignment, SectionID, +#if HAVE_LLVM >= 0x0304 + SectionName, +#endif + IsReadOnly); + } +#if HAVE_LLVM >= 0x0304 + virtual void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) { + mgr()->registerEHFrames(Addr, LoadAddr, Size); + } + virtual void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) { + mgr()->deregisterEHFrames(Addr, LoadAddr, Size); + } +#else + virtual void registerEHFrames(llvm::StringRef SectionData) { + mgr()->registerEHFrames(SectionData); + } +#endif + virtual void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure=true) { + return mgr()->getPointerToNamedFunction(Name, AbortOnFailure); + } +#if HAVE_LLVM <= 0x0303 + virtual bool applyPermissions(std::string *ErrMsg = 0) { + return mgr()->applyPermissions(ErrMsg); + } +#else + virtual bool finalizeMemory(std::string *ErrMsg = 0) { + return mgr()->finalizeMemory(ErrMsg); + } +#endif +}; + + +/* + * Delegate memory management to one shared manager for more efficient use + * of memory than creating a separate pool for each LLVM engine. + * Keep generated code until freeGeneratedCode() is called, instead of when + * memory manager is destroyed, which happens during engine destruction. + * This allows additional memory savings as we don't have to keep the engine + * around in order to use the code. + * All methods are delegated to the shared manager except destruction and + * deallocating code. For the latter we just remember what needs to be + * deallocated later. The shared manager is deleted once it is empty. + */ +class ShaderMemoryManager : public DelegatingJITMemoryManager { + + BaseMemoryManager *TheMM; + + struct GeneratedCode { + typedef std::vector Vec; + Vec FunctionBody, ExceptionTable; + BaseMemoryManager *TheMM; + + GeneratedCode(BaseMemoryManager *MM) { + TheMM = MM; + } + + ~GeneratedCode() { + /* + * Deallocate things as previously requested and + * free shared manager when no longer used. + */ +#if HAVE_LLVM < 0x0306 + Vec::iterator i; + + assert(TheMM); + for ( i = FunctionBody.begin(); i != FunctionBody.end(); ++i ) + TheMM->deallocateFunctionBody(*i); +#if HAVE_LLVM < 0x0304 + for ( i = ExceptionTable.begin(); i != ExceptionTable.end(); ++i ) + TheMM->deallocateExceptionTable(*i); +#endif /* HAVE_LLVM < 0x0304 */ +#endif /* HAVE_LLVM < 0x0306 */ + } + }; + + GeneratedCode *code; + + BaseMemoryManager *mgr() const { + return TheMM; + } + + public: + + ShaderMemoryManager(BaseMemoryManager* MM) { + TheMM = MM; + code = new GeneratedCode(MM); + } + + virtual ~ShaderMemoryManager() { + /* + * 'code' is purposely not deleted. It is the user's responsibility + * to call getGeneratedCode() and freeGeneratedCode(). + */ + } + + struct lp_generated_code *getGeneratedCode() { + return (struct lp_generated_code *) code; + } + + static void freeGeneratedCode(struct lp_generated_code *code) { + delete (GeneratedCode *) code; + } + +#if HAVE_LLVM < 0x0304 + virtual void deallocateExceptionTable(void *ET) { + // remember for later deallocation + code->ExceptionTable.push_back(ET); + } +#endif + + virtual void deallocateFunctionBody(void *Body) { + // remember for later deallocation + code->FunctionBody.push_back(Body); + } +}; -#if HAVE_LLVM >= 0x301 /** * Same as LLVMCreateJITCompilerForModule, but: @@ -229,7 +471,9 @@ lp_set_store_alignment(LLVMValueRef Inst, extern "C" LLVMBool lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT, + lp_generated_code **OutCode, LLVMModuleRef M, + LLVMMCJITMemoryManagerRef CMM, unsigned OptLevel, int useMCJIT, char **OutError) @@ -237,7 +481,11 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT, using namespace llvm; std::string Error; +#if HAVE_LLVM >= 0x0306 + EngineBuilder builder(std::unique_ptr(unwrap(M))); +#else EngineBuilder builder(unwrap(M)); +#endif /** * LLVM 3.1+ haven't more "extern unsigned llvm::StackAlignmentOverride" and @@ -246,16 +494,24 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT, TargetOptions options; #if defined(PIPE_ARCH_X86) options.StackAlignmentOverride = 4; +#if HAVE_LLVM < 0x0304 options.RealignStack = true; #endif +#endif -#if defined(DEBUG) +#if defined(DEBUG) && HAVE_LLVM < 0x0307 options.JITEmitDebugInfo = true; #endif -#if defined(DEBUG) || defined(PROFILE) + /* XXX: Workaround http://llvm.org/PR21435 */ +#if defined(DEBUG) || defined(PROFILE) || \ + (HAVE_LLVM >= 0x0303 && (defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64))) +#if HAVE_LLVM < 0x0304 options.NoFramePointerElimNonLeaf = true; +#endif +#if HAVE_LLVM < 0x0307 options.NoFramePointerElim = true; +#endif #endif builder.setEngineKind(EngineKind::JIT) @@ -264,43 +520,216 @@ lp_build_create_jit_compiler_for_module(LLVMExecutionEngineRef *OutJIT, .setOptLevel((CodeGenOpt::Level)OptLevel); if (useMCJIT) { +#if HAVE_LLVM < 0x0306 builder.setUseMCJIT(true); +#endif +#ifdef _WIN32 + /* + * MCJIT works on Windows, but currently 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 + LLVMSetTarget(M, "x86_64-pc-win32-elf"); +# else + LLVMSetTarget(M, "i686-pc-win32-elf"); +# endif +#endif } - llvm::SmallVector MAttrs; - if (util_cpu_caps.has_avx) { + llvm::SmallVector MAttrs; + +#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) + /* + * We need to unset attributes because sometimes LLVM mistakenly assumes + * certain features are present given the processor name. + * + * https://bugs.freedesktop.org/show_bug.cgi?id=92214 + * http://llvm.org/PR25021 + * http://llvm.org/PR19429 + * http://llvm.org/PR16721 + */ + MAttrs.push_back(util_cpu_caps.has_sse ? "+sse" : "-sse" ); + MAttrs.push_back(util_cpu_caps.has_sse2 ? "+sse2" : "-sse2" ); + MAttrs.push_back(util_cpu_caps.has_sse3 ? "+sse3" : "-sse3" ); + MAttrs.push_back(util_cpu_caps.has_ssse3 ? "+ssse3" : "-ssse3" ); +#if HAVE_LLVM >= 0x0304 + MAttrs.push_back(util_cpu_caps.has_sse4_1 ? "+sse4.1" : "-sse4.1"); +#else + MAttrs.push_back(util_cpu_caps.has_sse4_1 ? "+sse41" : "-sse41" ); +#endif +#if HAVE_LLVM >= 0x0304 + MAttrs.push_back(util_cpu_caps.has_sse4_2 ? "+sse4.2" : "-sse4.2"); +#else + MAttrs.push_back(util_cpu_caps.has_sse4_2 ? "+sse42" : "-sse42" ); +#endif + /* + * AVX feature is not automatically detected from CPUID by the X86 target + * yet, because the old (yet default) JIT engine is not capable of + * emitting the opcodes. On newer llvm versions it is and at least some + * versions (tested with 3.3) will emit avx opcodes without this anyway. + */ + MAttrs.push_back(util_cpu_caps.has_avx ? "+avx" : "-avx"); + MAttrs.push_back(util_cpu_caps.has_f16c ? "+f16c" : "-f16c"); + if (HAVE_LLVM >= 0x0304) { + MAttrs.push_back(util_cpu_caps.has_fma ? "+fma" : "-fma"); + } else { /* - * AVX feature is not automatically detected from CPUID by the X86 target - * yet, because the old (yet default) JIT engine is not capable of - * emitting the opcodes. But as we're using MCJIT here, it is safe to - * add set this attribute. + * The old JIT in LLVM 3.3 has a bug encoding llvm.fmuladd.f32 and + * llvm.fmuladd.v2f32 intrinsics when FMA is available. */ - MAttrs.push_back("+avx"); - if (util_cpu_caps.has_f16c) { - MAttrs.push_back("+f16c"); - } - builder.setMAttrs(MAttrs); + MAttrs.push_back("-fma"); } - builder.setJITMemoryManager(JITMemoryManager::CreateDefaultMemManager()); + MAttrs.push_back(util_cpu_caps.has_avx2 ? "+avx2" : "-avx2"); + /* disable avx512 and all subvariants */ +#if HAVE_LLVM >= 0x0304 + MAttrs.push_back("-avx512cd"); + MAttrs.push_back("-avx512er"); + MAttrs.push_back("-avx512f"); + MAttrs.push_back("-avx512pf"); +#endif +#if HAVE_LLVM >= 0x0305 + MAttrs.push_back("-avx512bw"); + MAttrs.push_back("-avx512dq"); + MAttrs.push_back("-avx512vl"); +#endif +#endif - ExecutionEngine *JIT; -#if 0 - JIT = builder.create(); -#else +#if defined(PIPE_ARCH_PPC) + MAttrs.push_back(util_cpu_caps.has_altivec ? "+altivec" : "-altivec"); +#if HAVE_LLVM >= 0x0304 /* - * Workaround http://llvm.org/bugs/show_bug.cgi?id=12833 + * Make sure VSX instructions are disabled + * See LLVM bug https://llvm.org/bugs/show_bug.cgi?id=25503#c7 */ - StringRef MArch = ""; - StringRef MCPU = ""; - Triple TT(unwrap(M)->getTargetTriple()); - JIT = builder.create(builder.selectTarget(TT, MArch, MCPU, MAttrs)); + if (util_cpu_caps.has_altivec) { + MAttrs.push_back("-vsx"); + } +#endif +#endif + + builder.setMAttrs(MAttrs); + +#if HAVE_LLVM >= 0x0305 + StringRef MCPU = llvm::sys::getHostCPUName(); + /* + * The cpu bits are no longer set automatically, so need to set mcpu manually. + * 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. + */ + builder.setMCPU(MCPU); +#endif + + ShaderMemoryManager *MM = NULL; + if (useMCJIT) { + BaseMemoryManager* JMM = reinterpret_cast(CMM); + MM = new ShaderMemoryManager(JMM); + *OutCode = MM->getGeneratedCode(); + +#if HAVE_LLVM >= 0x0306 + builder.setMCJITMemoryManager(std::unique_ptr(MM)); + MM = NULL; // ownership taken by std::unique_ptr +#elif HAVE_LLVM > 0x0303 + builder.setMCJITMemoryManager(MM); +#else + builder.setJITMemoryManager(MM); +#endif + } else { +#if HAVE_LLVM < 0x0306 + BaseMemoryManager* JMM = reinterpret_cast(CMM); + MM = new ShaderMemoryManager(JMM); + *OutCode = MM->getGeneratedCode(); + + builder.setJITMemoryManager(MM); +#else + assert(0); +#endif + } + + ExecutionEngine *JIT; + + JIT = builder.create(); +#if LLVM_USE_INTEL_JITEVENTS + JITEventListener *JEL = JITEventListener::createIntelJITEventListener(); + JIT->RegisterJITEventListener(JEL); #endif if (JIT) { *OutJIT = wrap(JIT); return 0; } + lp_free_generated_code(*OutCode); + *OutCode = 0; + delete MM; *OutError = strdup(Error.c_str()); return 1; } -#endif /* HAVE_LLVM >= 0x301 */ + +extern "C" +void +lp_free_generated_code(struct lp_generated_code *code) +{ + ShaderMemoryManager::freeGeneratedCode(code); +} + +extern "C" +LLVMMCJITMemoryManagerRef +lp_get_default_memory_manager() +{ + BaseMemoryManager *mm; +#if HAVE_LLVM < 0x0306 + mm = llvm::JITMemoryManager::CreateDefaultMemManager(); +#else + mm = new llvm::SectionMemoryManager(); +#endif + return reinterpret_cast(mm); +} + +extern "C" +void +lp_free_memory_manager(LLVMMCJITMemoryManagerRef memorymgr) +{ + delete reinterpret_cast(memorymgr); +} + +extern "C" void +lp_add_attr_dereferenceable(LLVMValueRef val, uint64_t bytes) +{ +#if HAVE_LLVM >= 0x0306 + llvm::Argument *A = llvm::unwrap(val); + llvm::AttrBuilder B; + B.addDereferenceableAttr(bytes); + A->addAttr(llvm::AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); +#endif +} + +extern "C" LLVMValueRef +lp_get_called_value(LLVMValueRef call) +{ +#if HAVE_LLVM >= 0x0309 + return LLVMGetCalledValue(call); +#elif HAVE_LLVM >= 0x0305 + return llvm::wrap(llvm::CallSite(llvm::unwrap(call)).getCalledValue()); +#else + return NULL; /* radeonsi doesn't support so old LLVM. */ +#endif +} + +extern "C" bool +lp_is_function(LLVMValueRef v) +{ +#if HAVE_LLVM >= 0x0309 + return LLVMGetValueKind(v) == LLVMFunctionValueKind; +#else + return llvm::isa(llvm::unwrap(v)); +#endif +}