new orc compile stack complete
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 18 Aug 2017 07:28:42 +0000 (00:28 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 18 Aug 2017 07:28:42 +0000 (00:28 -0700)
new orc compile stack supports debugging JIT code using gdb
ready to add optimizations

src/llvm_wrapper/CMakeLists.txt
src/llvm_wrapper/llvm_wrapper.cpp
src/llvm_wrapper/llvm_wrapper.h
src/llvm_wrapper/orc_compile_stack.cpp
src/llvm_wrapper/orc_compile_stack.h
src/pipeline/pipeline.cpp
src/pipeline/pipeline.h
src/spirv_to_llvm/spirv_to_llvm.h

index 8a56efc168ba357d5f3ba7223b7ae05c06b9e08d..203275105672d38c26d0478842d04724645f9e1f 100644 (file)
@@ -29,3 +29,4 @@ else()
 set(llvm_libraries LLVM)
 endif()
 target_link_libraries(vulkan_cpu_llvm_wrapper util ${llvm_libraries})
+set_source_files_properties(orc_compile_stack.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) # prevent link errors with missing type info
index 68293172df40ca87872ceefc88a05f0953d4227d..24b579d07206a15aec46eeb5da8a45391b5f908c 100644 (file)
@@ -25,6 +25,7 @@
 #include <llvm/ExecutionEngine/SectionMemoryManager.h>
 #include <llvm-c/ExecutionEngine.h>
 #include <llvm/IR/DataLayout.h>
+#include <llvm/Target/TargetMachine.h>
 #include <iostream>
 #include <cstdlib>
 #include <algorithm>
@@ -33,6 +34,12 @@ namespace vulkan_cpu
 {
 namespace llvm_wrapper
 {
+// implement the unwrap functions that aren't in public llvm headers
+static llvm::TargetMachine *unwrap(::LLVMTargetMachineRef v) noexcept
+{
+    return reinterpret_cast<llvm::TargetMachine *>(v);
+}
+
 void Context::init_helper()
 {
     if(!::LLVMIsMultithreaded())
@@ -92,18 +99,34 @@ std::size_t Target_data::get_pointer_alignment(::LLVMTargetDataRef td) noexcept
     return llvm::unwrap(td)->getPointerABIAlignment(0);
 }
 
-Target_machine Target_machine::create_native_target_machine()
+Target_machine Target_machine::create_native_target_machine(::LLVMCodeGenOptLevel code_gen_level)
 {
     auto target = Target::get_native_target();
     return Target_machine(::LLVMCreateTargetMachine(target.get(),
                                                     Target::get_process_target_triple().get(),
                                                     Target::get_host_cpu_name().get(),
                                                     Target::get_host_cpu_features().get(),
-                                                    ::LLVMCodeGenLevelDefault,
+                                                    code_gen_level,
                                                     ::LLVMRelocDefault,
                                                     ::LLVMCodeModelJITDefault));
 }
 
+::LLVMCodeGenOptLevel Target_machine::get_code_gen_opt_level(::LLVMTargetMachineRef tm) noexcept
+{
+    switch(unwrap(tm)->getOptLevel())
+    {
+    case llvm::CodeGenOpt::Level::None:
+        return ::LLVMCodeGenLevelNone;
+    case llvm::CodeGenOpt::Level::Less:
+        return ::LLVMCodeGenLevelLess;
+    case llvm::CodeGenOpt::Level::Default:
+        return ::LLVMCodeGenLevelDefault;
+    case llvm::CodeGenOpt::Level::Aggressive:
+        return ::LLVMCodeGenLevelAggressive;
+    }
+    return ::LLVMCodeGenLevelDefault;
+}
+
 void Module::set_target_machine(::LLVMModuleRef module, ::LLVMTargetMachineRef target_machine)
 {
     ::LLVMSetTarget(module, Target_machine::get_target_triple(target_machine).get());
index 8ab6604020f5bfc8353439cedbc5ed820264c92f..e3555f8fb2ef603e93f6a05dd4a55f9aa903fef4 100644 (file)
@@ -259,7 +259,8 @@ struct Target_machine_deleter
 struct Target_machine : public Wrapper<::LLVMTargetMachineRef, Target_machine_deleter>
 {
     using Wrapper::Wrapper;
-    static Target_machine create_native_target_machine();
+    static Target_machine create_native_target_machine(
+        ::LLVMCodeGenOptLevel code_gen_level = ::LLVMCodeGenLevelDefault);
     static Target get_target(::LLVMTargetMachineRef tm)
     {
         return Target(::LLVMGetTargetMachineTarget(tm));
@@ -300,6 +301,11 @@ struct Target_machine : public Wrapper<::LLVMTargetMachineRef, Target_machine_de
     {
         return get_feature_string(get());
     }
+    static ::LLVMCodeGenOptLevel get_code_gen_opt_level(::LLVMTargetMachineRef tm) noexcept;
+    ::LLVMCodeGenOptLevel get_code_gen_opt_level() const noexcept
+    {
+        return get_code_gen_opt_level(get());
+    }
 };
 
 struct Module_deleter
@@ -649,7 +655,7 @@ struct Create_llvm_type<T[N]>
     }
 };
 
-template <typename Return_type, typename ...Args>
+template <typename Return_type, typename... Args>
 struct Create_llvm_type<Return_type (*)(Args...)>
 {
     ::LLVMTypeRef operator()(::LLVMContextRef context) const
index 3b437e9730413cb691123b4ef44319488544bc2e..c0f672061ce76ccfc83c0bf02af30ab11a40d27d 100644 (file)
 #include <llvm/ExecutionEngine/ExecutionEngine.h>
 #include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
 #include <llvm/ExecutionEngine/JITEventListener.h>
+#include <llvm/ExecutionEngine/JITSymbol.h>
 #include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
+#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
+#include <llvm/ExecutionEngine/Orc/IRTransformLayer.h>
+#include <llvm/ExecutionEngine/Orc/CompileUtils.h>
+#include <llvm/ExecutionEngine/Orc/LambdaResolver.h>
 #include <llvm/Target/TargetMachine.h>
 #include <llvm/Config/llvm-config.h>
+#include <unordered_map>
+#include <unordered_set>
 
 #if LLVM_VERSION_MAJOR != 4 || LLVM_VERSION_MINOR != 0
 #error Orc compile stack is not yet implemented for this version of LLVM
@@ -36,13 +43,14 @@ namespace vulkan_cpu
 {
 namespace llvm_wrapper
 {
-namespace
-{
 // implement the unwrap functions that aren't in public llvm headers
-llvm::TargetMachine *unwrap(::LLVMTargetMachineRef v) noexcept
+static llvm::TargetMachine *unwrap(::LLVMTargetMachineRef v) noexcept
 {
     return reinterpret_cast<llvm::TargetMachine *>(v);
 }
+static ::LLVMTargetMachineRef wrap(llvm::TargetMachine *v) noexcept
+{
+    return reinterpret_cast<::LLVMTargetMachineRef>(v);
 }
 
 class Orc_compile_stack_implementation
@@ -53,29 +61,180 @@ class Orc_compile_stack_implementation
     Orc_compile_stack_implementation &operator=(Orc_compile_stack_implementation &&) = delete;
 
 private:
+    typedef Orc_compile_stack::Symbol_resolver_callback Symbol_resolver_callback;
+    typedef Orc_compile_stack::Module_handle Module_handle;
+
+private:
+    // implement a wrapper for llvm::orc::ObjectLinkingLayer
+    // in order to tell GDB about the contained objects
+    class My_object_linking_layer
+    {
+        My_object_linking_layer(const My_object_linking_layer &) = delete;
+        My_object_linking_layer(My_object_linking_layer &&) = delete;
+        My_object_linking_layer &operator=(const My_object_linking_layer &) = delete;
+        My_object_linking_layer &operator=(My_object_linking_layer &&) = delete;
+
+    private:
+        class On_loaded_functor
+        {
+            friend class My_object_linking_layer;
+
+        private:
+            My_object_linking_layer *my_object_linking_layer;
+            explicit On_loaded_functor(My_object_linking_layer *my_object_linking_layer) noexcept
+                : my_object_linking_layer(my_object_linking_layer)
+            {
+            }
+
+        public:
+            void operator()(
+                llvm::orc::ObjectLinkingLayerBase::ObjSetHandleT,
+                const std::
+                    vector<std::unique_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>>
+                        &object_set,
+                const std::vector<std::unique_ptr<llvm::RuntimeDyld::LoadedObjectInfo>>
+                    &load_result)
+            {
+                assert(object_set.size() == load_result.size());
+                for(std::size_t i = 0; i < object_set.size(); i++)
+                    my_object_linking_layer->handle_loaded_object(*object_set[i]->getBinary(),
+                                                                  *load_result[i]);
+            }
+        };
+
+    private:
+        Module_handle create_module_handle() noexcept
+        {
+            return next_module_handle++;
+        }
+        static std::vector<std::shared_ptr<llvm::JITEventListener>> make_jit_event_listener_list()
+        {
+            std::vector<std::shared_ptr<llvm::JITEventListener>> retval;
+            auto static_deleter = [](llvm::JITEventListener *)
+            {
+            };
+            if(auto *v = llvm::JITEventListener::createGDBRegistrationListener())
+            {
+                // createGDBRegistrationListener returns a static object
+                retval.push_back(std::shared_ptr<llvm::JITEventListener>(v, static_deleter));
+            }
+            if(auto *v = llvm::JITEventListener::createIntelJITEventListener())
+            {
+                retval.push_back(std::shared_ptr<llvm::JITEventListener>(v));
+            }
+            if(auto *v = llvm::JITEventListener::createOProfileJITEventListener())
+            {
+                retval.push_back(std::shared_ptr<llvm::JITEventListener>(v));
+            }
+            return retval;
+        }
+        void handle_loaded_object(const llvm::object::ObjectFile &object,
+                                  const llvm::RuntimeDyld::LoadedObjectInfo &load_info)
+        {
+            loaded_object_set.insert(&object);
+            for(auto &jit_event_listener : jit_event_listener_list)
+                jit_event_listener->NotifyObjectEmitted(object, load_info);
+        }
+
+    public:
+        My_object_linking_layer()
+            : jit_event_listener_list(make_jit_event_listener_list()),
+              object_linking_layer(On_loaded_functor(this))
+        {
+        }
+        ~My_object_linking_layer()
+        {
+            for(auto i = loaded_object_set.begin(); i != loaded_object_set.end();)
+            {
+                for(auto &jit_event_listener : jit_event_listener_list)
+                    jit_event_listener->NotifyFreeingObject(**i);
+                i = loaded_object_set.erase(i);
+            }
+        }
+        typedef Module_handle ObjSetHandleT;
+        llvm::JITSymbol findSymbol(const std::string &name, bool exported_symbols_only)
+        {
+            return object_linking_layer.findSymbol(name, exported_symbols_only);
+        }
+        template <typename Symbol_resolver_pointer>
+        Module_handle addObjectSet(
+            std::vector<std::unique_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>>
+                object_set,
+            std::unique_ptr<llvm::SectionMemoryManager> memory_manager,
+            Symbol_resolver_pointer symbol_resolver)
+        {
+            auto retval = create_module_handle();
+            auto &handle = handle_map[retval];
+            handle = object_linking_layer.addObjectSet(
+                std::move(object_set), std::move(memory_manager), std::move(symbol_resolver));
+            return retval;
+        }
+
+    private:
+        Module_handle next_module_handle = 1;
+        std::vector<std::shared_ptr<llvm::JITEventListener>> jit_event_listener_list;
+        llvm::orc::ObjectLinkingLayer<On_loaded_functor> object_linking_layer;
+        std::unordered_map<Module_handle, decltype(object_linking_layer)::ObjSetHandleT> handle_map;
+        std::unordered_multiset<const llvm::object::ObjectFile *> loaded_object_set;
+    };
+    typedef std::function<std::unique_ptr<llvm::Module>(std::unique_ptr<llvm::Module>)>
+        Optimize_function;
+
+private:
+    Orc_compile_stack::Optimize_function optimize_function;
     std::unique_ptr<llvm::TargetMachine> target_machine;
-    const llvm::DataLayout data_layout;
-    llvm::orc::ObjectLinkingLayer<> object_linking_layer;
+    My_object_linking_layer object_linking_layer;
+    llvm::orc::IRCompileLayer<decltype(object_linking_layer)> compile_layer;
+    llvm::orc::IRTransformLayer<decltype(compile_layer), Optimize_function> optimize_layer;
 
 public:
-    explicit Orc_compile_stack_implementation(Target_machine target_machine_in)
-        : target_machine(unwrap(target_machine_in.release())),
-          data_layout(target_machine->createDataLayout())
+    explicit Orc_compile_stack_implementation(
+        Target_machine target_machine_in, Orc_compile_stack::Optimize_function optimize_function)
+        : optimize_function(std::move(optimize_function)),
+          target_machine(unwrap(target_machine_in.release())),
+          object_linking_layer(),
+          compile_layer(object_linking_layer, llvm::orc::SimpleCompiler(*target_machine)),
+          optimize_layer(compile_layer,
+                         [this](std::unique_ptr<llvm::Module> module)
+                         {
+                             if(this->optimize_function)
+                             {
+                                 auto rewrapped_module = Module(llvm::wrap(module.release()));
+                                 rewrapped_module = this->optimize_function(
+                                     std::move(rewrapped_module), wrap(target_machine.get()));
+                                 return std::unique_ptr<llvm::Module>(
+                                     llvm::unwrap(rewrapped_module.release()));
+                             }
+                             return module;
+                         })
     {
-#warning finish
-        assert(!"finish");
     }
-    void add_eagerly_compiled_ir(Module module,
-                                 ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
-                                 void *symbol_resolver_user_data)
+    Module_handle add_eagerly_compiled_ir(Module module,
+                                          Symbol_resolver_callback symbol_resolver_callback,
+                                          void *symbol_resolver_user_data)
     {
-#warning finish
-        assert(!"finish");
+        auto resolver = llvm::orc::createLambdaResolver(
+            [this](const std::string &name)
+            {
+                return compile_layer.findSymbol(name, false);
+            },
+            [symbol_resolver_user_data, symbol_resolver_callback](const std::string &name)
+            {
+                return llvm::JITSymbol(symbol_resolver_callback(name, symbol_resolver_user_data),
+                                       llvm::JITSymbolFlags::Exported);
+            });
+        std::vector<std::unique_ptr<llvm::Module>> module_set;
+        module_set.reserve(1);
+        module_set.push_back(std::unique_ptr<llvm::Module>(llvm::unwrap(module.release())));
+        return optimize_layer.addModuleSet(std::move(module_set),
+                                           std::make_unique<llvm::SectionMemoryManager>(),
+                                           std::move(resolver));
     }
-    std::uintptr_t get_symbol_address(const char *symbol_name)
+    std::uintptr_t get_symbol_address(const std::string &symbol_name)
     {
-#warning finish
-        assert(!"finish");
+        auto symbol = compile_layer.findSymbol(symbol_name, true);
+        if(symbol)
+            return symbol.getAddress();
         return 0;
     }
 };
@@ -85,24 +244,25 @@ void Orc_compile_stack_deleter::operator()(Orc_compile_stack_ref v) const noexce
     delete v;
 }
 
-Orc_compile_stack Orc_compile_stack::create(Target_machine target_machine)
+Orc_compile_stack Orc_compile_stack::create(Target_machine target_machine,
+                                            Optimize_function optimize_function)
 {
-#warning finish
-    assert(!"finish");
-    return {};
+    return Orc_compile_stack(new Orc_compile_stack_implementation(std::move(target_machine),
+                                                                  std::move(optimize_function)));
 }
 
-void Orc_compile_stack::add_eagerly_compiled_ir(Orc_compile_stack_ref orc_compile_stack,
-                                                Module module,
-                                                ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
-                                                void *symbol_resolver_user_data)
+Orc_compile_stack::Module_handle Orc_compile_stack::add_eagerly_compiled_ir(
+    Orc_compile_stack_ref orc_compile_stack,
+    Module module,
+    Symbol_resolver_callback symbol_resolver_callback,
+    void *symbol_resolver_user_data)
 {
-    orc_compile_stack->add_eagerly_compiled_ir(
+    return orc_compile_stack->add_eagerly_compiled_ir(
         std::move(module), symbol_resolver_callback, symbol_resolver_user_data);
 }
 
 std::uintptr_t Orc_compile_stack::get_symbol_address(Orc_compile_stack_ref orc_compile_stack,
-                                                     const char *symbol_name)
+                                                     const std::string &symbol_name)
 {
     return orc_compile_stack->get_symbol_address(symbol_name);
 }
index 413d31456b32dcf1b9fdadf25d110dcdb2643e8c..80042c8a79222483d6dfdeb1ce1244348cf20318 100644 (file)
@@ -24,6 +24,9 @@
 #define LLVM_WRAPPER_ORC_COMPILE_STACK_H_
 
 #include "llvm_wrapper.h"
+#include <string>
+#include <utility>
+#include <functional>
 
 namespace vulkan_cpu
 {
@@ -41,31 +44,35 @@ struct Orc_compile_stack_deleter
 struct Orc_compile_stack : public Wrapper<Orc_compile_stack_ref, Orc_compile_stack_deleter>
 {
     using Wrapper::Wrapper;
-    static Orc_compile_stack create(Target_machine target_machine);
-    static void add_eagerly_compiled_ir(Orc_compile_stack_ref orc_compile_stack,
-                                        Module module,
-                                        ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
-                                        void *symbol_resolver_user_data);
-    void add_eagerly_compiled_ir(Module module,
-                                 ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
-                                 void *symbol_resolver_user_data)
+    typedef std::uintptr_t (*Symbol_resolver_callback)(const std::string &name, void *user_data);
+    typedef std::uint64_t Module_handle;
+    typedef std::function<Module(Module, ::LLVMTargetMachineRef target_machine)> Optimize_function;
+    static Orc_compile_stack create(Target_machine target_machine,
+                                    Optimize_function optimize_function = nullptr);
+    static Module_handle add_eagerly_compiled_ir(Orc_compile_stack_ref orc_compile_stack,
+                                                 Module module,
+                                                 Symbol_resolver_callback symbol_resolver_callback,
+                                                 void *symbol_resolver_user_data);
+    Module_handle add_eagerly_compiled_ir(Module module,
+                                          Symbol_resolver_callback symbol_resolver_callback,
+                                          void *symbol_resolver_user_data)
     {
-        add_eagerly_compiled_ir(
+        return add_eagerly_compiled_ir(
             get(), std::move(module), symbol_resolver_callback, symbol_resolver_user_data);
     }
     static std::uintptr_t get_symbol_address(Orc_compile_stack_ref orc_compile_stack,
-                                             const char *symbol_name);
+                                             const std::string &symbol_name);
     template <typename T>
-    static T *get_symbol(Orc_compile_stack_ref orc_compile_stack, const char *symbol_name)
+    static T *get_symbol(Orc_compile_stack_ref orc_compile_stack, const std::string &symbol_name)
     {
         return reinterpret_cast<T *>(get_symbol_address(orc_compile_stack, symbol_name));
     }
-    std::uintptr_t get_symbol_address(const char *symbol_name)
+    std::uintptr_t get_symbol_address(const std::string &symbol_name)
     {
         return get_symbol_address(get(), symbol_name);
     }
     template <typename T>
-    T *get_symbol(const char *symbol_name)
+    T *get_symbol(const std::string &symbol_name)
     {
         return get_symbol<T>(get(), symbol_name);
     }
index 84182a5b8fb39c3c8913e0d844cc12ebd694b607..70cae74dbcc5b3463bd911a86a081136a0efc6cb 100644 (file)
@@ -23,6 +23,7 @@
 #include "pipeline.h"
 #include "spirv_to_llvm/spirv_to_llvm.h"
 #include "llvm_wrapper/llvm_wrapper.h"
+#include "llvm_wrapper/orc_compile_stack.h"
 #include "vulkan/util.h"
 #include "util/soft_float.h"
 #include "json/json.h"
@@ -78,11 +79,31 @@ Pipeline_layout_handle Pipeline_layout_handle::make(
     return Pipeline_layout_handle(new Pipeline_layout());
 }
 
+llvm_wrapper::Module Pipeline::optimize_module(llvm_wrapper::Module module,
+                                               ::LLVMTargetMachineRef target_machine)
+{
+    switch(llvm_wrapper::Target_machine::get_code_gen_opt_level(target_machine))
+    {
+    case ::LLVMCodeGenLevelNone:
+    case ::LLVMCodeGenLevelLess:
+        break;
+    case ::LLVMCodeGenLevelDefault:
+    case ::LLVMCodeGenLevelAggressive:
+    {
+#warning finish implementing module optimizations
+        std::cerr << "optimized module:" << std::endl;
+        ::LLVMDumpModule(module.get());
+        break;
+    }
+    }
+    return module;
+}
+
 struct Graphics_pipeline::Implementation
 {
     llvm_wrapper::Context llvm_context = llvm_wrapper::Context::create();
     spirv_to_llvm::Jit_symbol_resolver jit_symbol_resolver;
-    llvm_wrapper::Orc_jit_stack jit_stack;
+    llvm_wrapper::Orc_compile_stack jit_stack;
     llvm_wrapper::Target_data data_layout;
     std::vector<spirv_to_llvm::Converted_module> compiled_shaders;
     std::shared_ptr<spirv_to_llvm::Struct_type_descriptor> vertex_shader_output_struct;
@@ -354,7 +375,11 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
         throw std::runtime_error("creating derived pipelines is not implemented");
     }
     auto implementation = std::make_shared<Implementation>();
-    auto llvm_target_machine = llvm_wrapper::Target_machine::create_native_target_machine();
+    auto optimization_level = ::LLVMCodeGenLevelDefault;
+    if(create_info.flags & VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT)
+        optimization_level = ::LLVMCodeGenLevelNone;
+    auto llvm_target_machine =
+        llvm_wrapper::Target_machine::create_native_target_machine(optimization_level);
     implementation->compiled_shaders.reserve(create_info.stageCount);
     for(std::size_t i = 0; i < create_info.stageCount; i++)
     {
@@ -394,7 +419,8 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
         implementation->compiled_shaders.push_back(std::move(compiled_shader));
     }
     implementation->data_layout = llvm_target_machine.create_target_data_layout();
-    implementation->jit_stack = llvm_wrapper::Orc_jit_stack::create(std::move(llvm_target_machine));
+    implementation->jit_stack =
+        llvm_wrapper::Orc_compile_stack::create(std::move(llvm_target_machine), optimize_module);
     Vertex_shader_function vertex_shader_function = nullptr;
     std::size_t vertex_shader_output_struct_size = 0;
     for(auto &compiled_shader : implementation->compiled_shaders)
index 80ccedc5ac3c15b612d38d5c699e1a28950ff6c8..d62eb5ce9532730aea21c86c14de6b8069b5841b 100644 (file)
@@ -179,6 +179,10 @@ public:
     {
         return reinterpret_cast<Pipeline *>(pipeline);
     }
+
+protected:
+    static llvm_wrapper::Module optimize_module(llvm_wrapper::Module module,
+                                                ::LLVMTargetMachineRef target_machine);
 };
 
 inline VkPipeline to_handle(Pipeline *pipeline) noexcept
index 1291233f2fcacdd275891a07a32c567782ae455c..1171b7a0552b79dc79c2770b092601462385107b 100644 (file)
@@ -33,6 +33,7 @@
 #include <utility>
 #include <cstddef>
 #include "llvm_wrapper/llvm_wrapper.h"
+#include "util/string_view.h"
 
 namespace vulkan_cpu
 {
@@ -589,7 +590,7 @@ struct Converted_module
 struct Jit_symbol_resolver
 {
     typedef void (*Resolved_symbol)();
-    Resolved_symbol resolve(const char *name)
+    Resolved_symbol resolve(util::string_view name)
     {
 #warning finish implementing
         return nullptr;
@@ -599,6 +600,11 @@ struct Jit_symbol_resolver
         return reinterpret_cast<std::uint64_t>(
             static_cast<Jit_symbol_resolver *>(user_data)->resolve(name));
     }
+    static std::uintptr_t resolve(const std::string &name, void *user_data) noexcept
+    {
+        return reinterpret_cast<std::uintptr_t>(
+            static_cast<Jit_symbol_resolver *>(user_data)->resolve(name));
+    }
 };
 
 class Spirv_to_llvm;