summaryrefslogtreecommitdiff
path: root/weerun_jit.hpp
diff options
context:
space:
mode:
authorHanjie Wu <hanjiew@andrew.cmu.edu>2022-12-08 17:45:55 -0500
committerHanjie Wu <hanjiew@andrew.cmu.edu>2022-12-08 17:45:55 -0500
commita054755b62e660d3d8aba42fdb0a992e2d215599 (patch)
tree5f2e793527f75240800b31025f4c4c1f58be23ab /weerun_jit.hpp
JIT implementation
Diffstat (limited to 'weerun_jit.hpp')
-rw-r--r--weerun_jit.hpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/weerun_jit.hpp b/weerun_jit.hpp
new file mode 100644
index 0000000..509f02c
--- /dev/null
+++ b/weerun_jit.hpp
@@ -0,0 +1,216 @@
+#pragma once
+
+#include <array>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "weerun.hpp"
+
+#include <xbyak/xbyak.h>
+#include <xbyak/xbyak_bin2hex.h>
+
+namespace reg {
+enum reg {
+ rax = 0,
+ rdx = 1,
+ rcx = 2,
+ rdi = 3,
+ rsi = 4,
+ r8 = 5,
+ r9 = 6,
+ r10 = 7,
+ r11 = 8,
+ // callee-saved:
+ rbx = 9,
+ r12 = 10,
+ r13 = 11,
+ r14 = 12,
+ r15 = 13,
+
+ xmm0 = 14,
+ xmm1 = 15,
+ xmm2 = 16,
+ xmm3 = 17,
+ xmm4 = 18,
+ xmm5 = 19,
+ xmm6 = 20,
+ xmm7 = 21,
+ xmm8 = 22,
+ xmm9 = 23,
+ xmm10 = 24,
+ xmm11 = 25,
+ xmm12 = 26,
+ xmm13 = 27,
+ xmm14 = 28,
+ xmm15 = 29,
+
+ num_r = 30
+};
+
+const int32_t in_reg = 0;
+const int32_t on_stack = 1;
+} // namespace reg
+
+struct wasm_jit_loc_t {
+ int32_t type; // 0:in register, 1:on stack
+ int32_t index; // register index or [rbp-8*index]
+
+ bool operator==(const wasm_jit_loc_t& rhs) {
+ return type == rhs.type && index == rhs.index;
+ }
+};
+
+enum class wasm_jit_type_t : int32_t {
+ INVALID,
+ CALLER_DATA,
+ INTERMEDIATE,
+ LOCAL_VAL, // index = local variable index
+ STACK_VAL, // index = stack index
+ GLOBAL_BASE,
+ MEMORY_BASE,
+ MEMORY_SIZE,
+};
+
+struct wasm_jit_val_t {
+ wasm_jit_type_t type;
+ int32_t index;
+
+ bool operator==(const wasm_jit_val_t& rhs) {
+ return type == rhs.type && index == rhs.index;
+ }
+ bool operator!=(const wasm_jit_val_t& rhs) {
+ return type != rhs.type || index != rhs.index;
+ }
+};
+
+struct wasm_jit_ctx_t {
+ std::array<wasm_jit_val_t, 30> reg_; // reg content
+ std::array<uint32_t, 30> reg_age_; // reg content
+ uint32_t age_;
+ std::vector<uint8_t> stack_valid_; // stack valid?
+
+ std::vector<wasm_jit_loc_t> stack_loc_; // location of wasm stack values
+ std::vector<wasm_jit_loc_t> local_loc_; // location of wasm local values
+
+ void init(wasm_jit_t* jit, wasm_func_t* f);
+};
+
+struct wasm_jit_t : public Xbyak::CodeGenerator {
+ wasm_module_t* mod_;
+ wasm_instance_t* ins_;
+ int max_prologue_size_;
+ bool enable_check_;
+ std::vector<uint8_t*> f_addr_;
+ uint8_t* run_fn_; // call helper function
+
+ // current function info
+ wasm_func_t* f_;
+ uint32_t funcidx_;
+ uint32_t num_locals_;
+ std::vector<uint8_t> local_types_;
+ uint32_t rsp_sub_;
+ std::array<uint8_t, 5> used_callee_;
+
+ // decoder info
+ uint32_t opcode_;
+ buffer_t buf_;
+ uint32_t next_bi_;
+ uint32_t stop_;
+
+ // register allocation context
+ wasm_jit_ctx_t ctx_;
+
+ // branch info
+ struct block_t {
+ uint32_t loop;
+ uint32_t index;
+ wasm_jit_ctx_t saved_ctx; // for loop, we need to save context early
+ std::vector<wasm_jit_ctx_t> br_ctxs; // brs' cpntext
+ };
+ std::vector<block_t> block_stack_;
+
+ wasm_jit_t(uint64_t code_size);
+
+ void compile_instance(wasm_instance_t* ins);
+ void emit_runtime_functions();
+ void compile_function(uint32_t index);
+ void run_fn(uint32_t index, wasm_value_t* args, wasm_value_t* r);
+
+ Xbyak::Reg64 to_xbyak_r64(int32_t index);
+ Xbyak::Reg32 to_xbyak_r32(int32_t index);
+ Xbyak::Reg16 to_xbyak_r16(int32_t index);
+ Xbyak::Reg8 to_xbyak_r8(int32_t index);
+ Xbyak::Xmm to_xbyak_xmm(int32_t index);
+
+ int32_t alloc_r(wasm_jit_val_t usage, uint8_t type);
+ void acquire_r(int32_t index, wasm_jit_val_t usage);
+ void use_r(int32_t index, wasm_jit_val_t usage);
+ void release_r(int32_t index); // mark a register as invalid
+
+ int32_t alloc_stk();
+ void release_stk(int32_t index);
+ void acquire_stk(int32_t index);
+
+ inline wasm_jit_loc_t peek_wasm_stk(uint32_t depth);
+ inline wasm_jit_loc_t pop_wasm_stk();
+
+ int32_t pop_r(uint8_t type); // pop to a 32bit register
+ void pop_r(int32_t index, uint8_t type); // pop to the given 32bit register
+ void push_r(int32_t index); // push a register
+
+ void restore_state(wasm_jit_ctx_t* from, wasm_jit_ctx_t* to);
+
+ typedef void (CodeGenerator::*oo_op_t)(const Xbyak::Operand&,
+ const Xbyak::Operand&);
+ typedef void (CodeGenerator::*or8_op_t)(const Xbyak::Operand&,
+ const Xbyak::Reg8&);
+ typedef void (CodeGenerator::*o_op_t)(const Xbyak::Operand&);
+ typedef void (CodeGenerator::*xo_op_t)(const Xbyak::Xmm&,
+ const Xbyak::Operand&);
+
+ int32_t pop_binop_r32_r32(oo_op_t binop);
+ int32_t pop_binop_xmm_xmm(xo_op_t binop);
+
+ void rbp_load_r(int32_t index, int32_t r, uint8_t type);
+ void rbp_save_r(int32_t index, int32_t r);
+
+ int32_t alloc_special(wasm_jit_type_t t,
+ size_t off); // load global base to a register
+ int32_t alloc_global_base(); // load global base to a register
+ int32_t alloc_memory_base(); // load memory base to a register
+ int32_t alloc_memory_size(); // load memory size to a register
+
+ void emit_lea_r_rip(int32_t r, size_t dest_offset);
+ void emit_mov_r_rip(int32_t r, size_t dest_offset);
+ void emit_call_internal(wasm_func_decl_t* sig, int is_direct, int index);
+ void emit_pop_result();
+
+ void emit_unreachable();
+ void emit_nop();
+ void emit_drop();
+ void emit_select();
+ void emit_local_get();
+ void emit_local_set();
+ void emit_local_tee();
+ void emit_global_get();
+ void emit_global_set();
+ void emit_i32_load();
+ void emit_f64_load();
+ void emit_i32_store();
+ void emit_f64_store();
+ void emit_i32_const();
+ void emit_f64_const();
+ void emit_i32_numeric();
+ void emit_i32_shift();
+ void emit_i32_convert();
+ void emit_f64_compute();
+ void emit_call();
+ void emit_call_indirect();
+ void emit_return();
+ void emit_block();
+ void emit_end();
+ void emit_br();
+ void emit_br_if();
+ void emit_br_table();
+};