#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>
{
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())
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());
#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
{
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
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;
}
};
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);
}
#define LLVM_WRAPPER_ORC_COMPILE_STACK_H_
#include "llvm_wrapper.h"
+#include <string>
+#include <utility>
+#include <functional>
namespace vulkan_cpu
{
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);
}
#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"
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;
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++)
{
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)