1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00
rpcs3/Utilities/JIT.h

205 lines
4.3 KiB
C
Raw Normal View History

#pragma once
2019-11-30 00:11:28 +01:00
// Include asmjit with warnings ignored
2018-06-12 20:03:53 +02:00
#define ASMJIT_EMBED
#define ASMJIT_DEBUG
2019-11-30 00:11:28 +01:00
#ifdef _MSC_VER
#pragma warning(push, 0)
#include <asmjit/asmjit.h>
#pragma warning(pop)
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#pragma GCC diagnostic ignored "-Wold-style-cast"
2018-06-12 20:03:53 +02:00
#include <asmjit/asmjit.h>
2019-11-30 00:11:28 +01:00
#pragma GCC diagnostic pop
#endif
#include <array>
#include <functional>
enum class jit_class
{
ppu_code,
ppu_data,
spu_code,
spu_data,
};
// ASMJIT runtime for emitting code in a single 2G region
struct jit_runtime final : asmjit::HostRuntime
{
jit_runtime();
~jit_runtime() override;
// Allocate executable memory
asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override;
// Do nothing (deallocation is delayed)
asmjit::Error _release(void* p) noexcept override;
// Allocate memory
static u8* alloc(std::size_t size, uint align, bool exec = true) noexcept;
// Should be called at least once after global initialization
static void initialize();
// Deallocate all memory
static void finalize() noexcept;
};
namespace asmjit
{
// Should only be used to build global functions
asmjit::Runtime& get_global_runtime();
// Emit xbegin and adjacent loop, return label at xbegin (don't use xabort please)
template <typename F>
[[nodiscard]] inline asmjit::Label build_transaction_enter(asmjit::X86Assembler& c, asmjit::Label fallback, const asmjit::X86Gp& ctr, uint less_than, F func)
{
Label fall = c.newLabel();
Label begin = c.newLabel();
c.jmp(begin);
c.bind(fall);
// First invoked after failure
func();
c.add(ctr, 1);
// Don't repeat on zero status (may indicate syscall or interrupt)
c.test(x86::eax, x86::eax);
c.jz(fallback);
// Other bad statuses are ignored regardless of repeat flag (TODO)
c.cmp(ctr, less_than);
c.jae(fallback);
c.align(kAlignCode, 16);
c.bind(begin);
return fall;
// xbegin should be issued manually, allows to add more check before entering transaction
}
}
// Build runtime function with asmjit::X86Assembler
template <typename FT, typename F>
inline FT build_function_asm(F&& builder)
{
using namespace asmjit;
auto& rt = get_global_runtime();
CodeHolder code;
code.init(rt.getCodeInfo());
code._globalHints = asmjit::CodeEmitter::kHintOptimizedAlign;
std::array<X86Gp, 4> args;
#ifdef _WIN32
args[0] = x86::rcx;
args[1] = x86::rdx;
args[2] = x86::r8;
args[3] = x86::r9;
#else
args[0] = x86::rdi;
args[1] = x86::rsi;
args[2] = x86::rdx;
args[3] = x86::rcx;
#endif
X86Assembler compiler(&code);
builder(std::ref(compiler), args);
ASSERT(compiler.getLastError() == 0);
FT result;
if (rt.add(&result, &code))
{
return nullptr;
}
return result;
}
#ifdef LLVM_AVAILABLE
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include "types.h"
2017-06-24 17:36:49 +02:00
#include "mutex.h"
2017-01-28 13:32:45 +01:00
#include "restore_new.h"
#ifdef _MSC_VER
#pragma warning(push, 0)
2019-11-30 00:11:28 +01:00
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#ifdef _MSC_VER
#pragma warning(pop)
2019-11-30 00:11:28 +01:00
#else
#pragma GCC diagnostic pop
#endif
2017-01-28 13:32:45 +01:00
#include "define_new_memleakdetect.h"
// Temporary compiler interface
class jit_compiler final
{
2017-06-24 17:36:49 +02:00
// Local LLVM context
llvm::LLVMContext m_context;
// Execution instance
std::unique_ptr<llvm::ExecutionEngine> m_engine;
2017-02-26 16:56:31 +01:00
// Arch
std::string m_cpu;
public:
jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags = 0);
~jit_compiler();
2017-06-24 17:36:49 +02:00
// Get LLVM context
auto& get_context()
{
return m_context;
}
2018-05-01 12:20:36 +02:00
auto& get_engine() const
{
return *m_engine;
}
2017-07-15 11:20:40 +02:00
// Add module (path to obj cache dir)
void add(std::unique_ptr<llvm::Module> _module, const std::string& path);
2018-05-01 12:20:36 +02:00
// Add module (not cached)
void add(std::unique_ptr<llvm::Module> _module);
2018-05-01 12:20:36 +02:00
2017-07-15 11:20:40 +02:00
// Add object (path to obj file)
void add(const std::string& path);
// Check object file
static bool check(const std::string& path);
// Finalize
2017-06-24 17:36:49 +02:00
void fin();
2017-02-26 16:56:31 +01:00
// Get compiled function address
2017-06-24 17:36:49 +02:00
u64 get(const std::string& name);
2017-02-26 16:56:31 +01:00
// Get CPU info
static std::string cpu(const std::string& _cpu);
};
#endif