diff options
author | Jose Narvaez <[email protected]> | 2021-03-06 23:46:56 +0000 |
---|---|---|
committer | Alan Wu <[email protected]> | 2021-10-20 18:19:31 -0400 |
commit | 4e2eb7695e9b45cb5d2ae757bdb5c2043d78be78 (patch) | |
tree | 71e02cd04b191b9ce66801b67736cf69d831bd0b /yjit_asm.h | |
parent | 7f7e79d80221949f93c7ded7cbd8d26afd3dea1d (diff) |
Yet Another Ruby JIT!
Renaming uJIT to YJIT. AKA s/ujit/yjit/g.
Diffstat (limited to 'yjit_asm.h')
-rw-r--r-- | yjit_asm.h | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/yjit_asm.h b/yjit_asm.h new file mode 100644 index 0000000000..617a32aafc --- /dev/null +++ b/yjit_asm.h @@ -0,0 +1,384 @@ +#ifndef YJIT_ASM_H +#define YJIT_ASM_H 1 + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + +// Maximum number of labels to link +#define MAX_LABELS 32 + +// Maximum number of label references +#define MAX_LABEL_REFS 32 + +// Reference to an ASM label +typedef struct LabelRef +{ + // Position in the code block where the label reference exists + uint32_t pos; + + // Label which this refers to + uint32_t label_idx; + +} labelref_t; + +// Block of executable memory into which instructions can be written +typedef struct CodeBlock +{ + // Memory block + uint8_t* mem_block; + + // Memory block size + uint32_t mem_size; + + /// Current writing position + uint32_t write_pos; + + // Table of registered label addresses + uint32_t label_addrs[MAX_LABELS]; + + // Table of registered label names + // Note that these should be constant strings only + const char* label_names[MAX_LABELS]; + + // References to labels + labelref_t label_refs[MAX_LABEL_REFS]; + + // Number of labels registeered + uint32_t num_labels; + + // Number of references to labels + uint32_t num_refs; + + // TODO: system for disassembly/comment strings, indexed by position + + // Flag to enable or disable comments + bool has_asm; + +} codeblock_t; + +enum OpndType +{ + OPND_NONE, + OPND_REG, + OPND_IMM, + OPND_MEM +}; + +enum RegType +{ + REG_GP, + REG_FP, + REG_XMM, + REG_IP +}; + +typedef struct X86Reg +{ + // Register type + uint8_t reg_type; + + // Register index number + uint8_t reg_no; + +} x86reg_t; + +typedef struct X86Mem +{ + /// Base register number + uint8_t base_reg_no; + + /// Index register number + uint8_t idx_reg_no; + + /// SIB scale exponent value (power of two, two bits) + uint8_t scale_exp; + + /// Has index register flag + bool has_idx; + + // TODO: should this be here, or should we have an extra operand type? + /// IP-relative addressing flag + bool is_iprel; + + /// Constant displacement from the base, not scaled + int32_t disp; + +} x86mem_t; + +typedef struct X86Opnd +{ + // Operand type + uint8_t type; + + // Size in bits + uint16_t num_bits; + + union + { + // Register operand + x86reg_t reg; + + // Memory operand + x86mem_t mem; + + // Signed immediate value + int64_t imm; + + // Unsigned immediate value + uint64_t unsig_imm; + } as; + +} x86opnd_t; + +// Dummy none/null operand +static const x86opnd_t NO_OPND = { OPND_NONE, 0, .as.imm = 0 }; + +// Instruction pointer +static const x86opnd_t RIP = { OPND_REG, 64, .as.reg = { REG_IP, 5 }}; + +// 64-bit GP registers +static const x86opnd_t RAX = { OPND_REG, 64, .as.reg = { REG_GP, 0 }}; +static const x86opnd_t RCX = { OPND_REG, 64, .as.reg = { REG_GP, 1 }}; +static const x86opnd_t RDX = { OPND_REG, 64, .as.reg = { REG_GP, 2 }}; +static const x86opnd_t RBX = { OPND_REG, 64, .as.reg = { REG_GP, 3 }}; +static const x86opnd_t RSP = { OPND_REG, 64, .as.reg = { REG_GP, 4 }}; +static const x86opnd_t RBP = { OPND_REG, 64, .as.reg = { REG_GP, 5 }}; +static const x86opnd_t RSI = { OPND_REG, 64, .as.reg = { REG_GP, 6 }}; +static const x86opnd_t RDI = { OPND_REG, 64, .as.reg = { REG_GP, 7 }}; +static const x86opnd_t R8 = { OPND_REG, 64, .as.reg = { REG_GP, 8 }}; +static const x86opnd_t R9 = { OPND_REG, 64, .as.reg = { REG_GP, 9 }}; +static const x86opnd_t R10 = { OPND_REG, 64, .as.reg = { REG_GP, 10 }}; +static const x86opnd_t R11 = { OPND_REG, 64, .as.reg = { REG_GP, 11 }}; +static const x86opnd_t R12 = { OPND_REG, 64, .as.reg = { REG_GP, 12 }}; +static const x86opnd_t R13 = { OPND_REG, 64, .as.reg = { REG_GP, 13 }}; +static const x86opnd_t R14 = { OPND_REG, 64, .as.reg = { REG_GP, 14 }}; +static const x86opnd_t R15 = { OPND_REG, 64, .as.reg = { REG_GP, 15 }}; + +// 32-bit GP registers +static const x86opnd_t EAX = { OPND_REG, 32, .as.reg = { REG_GP, 0 }}; +static const x86opnd_t ECX = { OPND_REG, 32, .as.reg = { REG_GP, 1 }}; +static const x86opnd_t EDX = { OPND_REG, 32, .as.reg = { REG_GP, 2 }}; +static const x86opnd_t EBX = { OPND_REG, 32, .as.reg = { REG_GP, 3 }}; +static const x86opnd_t ESP = { OPND_REG, 32, .as.reg = { REG_GP, 4 }}; +static const x86opnd_t EBP = { OPND_REG, 32, .as.reg = { REG_GP, 5 }}; +static const x86opnd_t ESI = { OPND_REG, 32, .as.reg = { REG_GP, 6 }}; +static const x86opnd_t EDI = { OPND_REG, 32, .as.reg = { REG_GP, 7 }}; +static const x86opnd_t R8D = { OPND_REG, 32, .as.reg = { REG_GP, 8 }}; +static const x86opnd_t R9D = { OPND_REG, 32, .as.reg = { REG_GP, 9 }}; +static const x86opnd_t R10D = { OPND_REG, 32, .as.reg = { REG_GP, 10 }}; +static const x86opnd_t R11D = { OPND_REG, 32, .as.reg = { REG_GP, 11 }}; +static const x86opnd_t R12D = { OPND_REG, 32, .as.reg = { REG_GP, 12 }}; +static const x86opnd_t R13D = { OPND_REG, 32, .as.reg = { REG_GP, 13 }}; +static const x86opnd_t R14D = { OPND_REG, 32, .as.reg = { REG_GP, 14 }}; +static const x86opnd_t R15D = { OPND_REG, 32, .as.reg = { REG_GP, 15 }}; + +// 16-bit GP registers +static const x86opnd_t AX = { OPND_REG, 16, .as.reg = { REG_GP, 0 }}; +static const x86opnd_t CX = { OPND_REG, 16, .as.reg = { REG_GP, 1 }}; +static const x86opnd_t DX = { OPND_REG, 16, .as.reg = { REG_GP, 2 }}; +static const x86opnd_t BX = { OPND_REG, 16, .as.reg = { REG_GP, 3 }}; +static const x86opnd_t SP = { OPND_REG, 16, .as.reg = { REG_GP, 4 }}; +static const x86opnd_t BP = { OPND_REG, 16, .as.reg = { REG_GP, 5 }}; +static const x86opnd_t SI = { OPND_REG, 16, .as.reg = { REG_GP, 6 }}; +static const x86opnd_t DI = { OPND_REG, 16, .as.reg = { REG_GP, 7 }}; +static const x86opnd_t R8W = { OPND_REG, 16, .as.reg = { REG_GP, 8 }}; +static const x86opnd_t R9W = { OPND_REG, 16, .as.reg = { REG_GP, 9 }}; +static const x86opnd_t R10W = { OPND_REG, 16, .as.reg = { REG_GP, 10 }}; +static const x86opnd_t R11W = { OPND_REG, 16, .as.reg = { REG_GP, 11 }}; +static const x86opnd_t R12W = { OPND_REG, 16, .as.reg = { REG_GP, 12 }}; +static const x86opnd_t R13W = { OPND_REG, 16, .as.reg = { REG_GP, 13 }}; +static const x86opnd_t R14W = { OPND_REG, 16, .as.reg = { REG_GP, 14 }}; +static const x86opnd_t R15W = { OPND_REG, 16, .as.reg = { REG_GP, 15 }}; + +// 8-bit GP registers +static const x86opnd_t AL = { OPND_REG, 8, .as.reg = { REG_GP, 0 }}; +static const x86opnd_t CL = { OPND_REG, 8, .as.reg = { REG_GP, 1 }}; +static const x86opnd_t DL = { OPND_REG, 8, .as.reg = { REG_GP, 2 }}; +static const x86opnd_t BL = { OPND_REG, 8, .as.reg = { REG_GP, 3 }}; +static const x86opnd_t SPL = { OPND_REG, 8, .as.reg = { REG_GP, 4 }}; +static const x86opnd_t BPL = { OPND_REG, 8, .as.reg = { REG_GP, 5 }}; +static const x86opnd_t SIL = { OPND_REG, 8, .as.reg = { REG_GP, 6 }}; +static const x86opnd_t DIL = { OPND_REG, 8, .as.reg = { REG_GP, 7 }}; +static const x86opnd_t R8B = { OPND_REG, 8, .as.reg = { REG_GP, 8 }}; +static const x86opnd_t R9B = { OPND_REG, 8, .as.reg = { REG_GP, 9 }}; +static const x86opnd_t R10B = { OPND_REG, 8, .as.reg = { REG_GP, 10 }}; +static const x86opnd_t R11B = { OPND_REG, 8, .as.reg = { REG_GP, 11 }}; +static const x86opnd_t R12B = { OPND_REG, 8, .as.reg = { REG_GP, 12 }}; +static const x86opnd_t R13B = { OPND_REG, 8, .as.reg = { REG_GP, 13 }}; +static const x86opnd_t R14B = { OPND_REG, 8, .as.reg = { REG_GP, 14 }}; +static const x86opnd_t R15B = { OPND_REG, 8, .as.reg = { REG_GP, 15 }}; + +// C argument registers +#define NUM_C_ARG_REGS 6 +#define C_ARG_REGS ( (x86opnd_t[]){ RDI, RSI, RDX, RCX, R8, R9 } ) + +// Memory operand with base register and displacement/offset +x86opnd_t mem_opnd(uint32_t num_bits, x86opnd_t base_reg, int32_t disp); + +// Scale-index-base memory operand +x86opnd_t mem_opnd_sib(uint32_t num_bits, x86opnd_t base_reg, x86opnd_t index_reg, int32_t scale, int32_t disp); + +// Immediate number operand +x86opnd_t imm_opnd(int64_t val); + +// Constant pointer operand +x86opnd_t const_ptr_opnd(const void *ptr); + +// Struct member operand +#define member_opnd(base_reg, struct_type, member_name) mem_opnd( \ + 8 * sizeof(((struct_type*)0)->member_name), \ + base_reg, \ + offsetof(struct_type, member_name) \ +) + +// Struct member operand with an array index +#define member_opnd_idx(base_reg, struct_type, member_name, idx) mem_opnd( \ + 8 * sizeof(((struct_type*)0)->member_name[0]), \ + base_reg, \ + (offsetof(struct_type, member_name) + \ + sizeof(((struct_type*)0)->member_name[0]) * idx) \ +) + +// Code block methods +uint8_t* alloc_exec_mem(uint32_t mem_size); +void cb_init(codeblock_t* cb, uint8_t* mem_block, uint32_t mem_size); +void cb_align_pos(codeblock_t* cb, uint32_t multiple); +void cb_set_pos(codeblock_t* cb, uint32_t pos); +uint8_t* cb_get_ptr(codeblock_t* cb, uint32_t index); +void cb_write_byte(codeblock_t* cb, uint8_t byte); +void cb_write_bytes(codeblock_t* cb, uint32_t num_bytes, ...); +void cb_write_int(codeblock_t* cb, uint64_t val, uint32_t num_bits); +uint32_t cb_new_label(codeblock_t* cb, const char* name); +void cb_write_label(codeblock_t* cb, uint32_t label_idx); +void cb_label_ref(codeblock_t* cb, uint32_t label_idx); +void cb_link_labels(codeblock_t* cb); + +// Encode individual instructions into a code block +void add(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void and(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void call_ptr(codeblock_t* cb, x86opnd_t scratch_reg, uint8_t* dst_ptr); +void call_label(codeblock_t* cb, uint32_t label_idx); +void call(codeblock_t* cb, x86opnd_t opnd); +void cmova(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovae(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovb(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovbe(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovc(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmove(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovg(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovge(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovl(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovle(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovna(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnae(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnb(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnbe(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnc(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovne(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovng(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnge(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnl(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnle(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovno(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnp(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovns(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovnz(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovo(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovp(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovpe(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovpo(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovs(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmovz(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void cmp(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void cdq(codeblock_t* cb); +void cqo(codeblock_t* cb); +void int3(codeblock_t* cb); +void ja_label(codeblock_t* cb, uint32_t label_idx); +void jae_label(codeblock_t* cb, uint32_t label_idx); +void jb_label(codeblock_t* cb, uint32_t label_idx); +void jbe_label(codeblock_t* cb, uint32_t label_idx); +void jc_label(codeblock_t* cb, uint32_t label_idx); +void je_label(codeblock_t* cb, uint32_t label_idx); +void jg_label(codeblock_t* cb, uint32_t label_idx); +void jge_label(codeblock_t* cb, uint32_t label_idx); +void jl_label(codeblock_t* cb, uint32_t label_idx); +void jle_label(codeblock_t* cb, uint32_t label_idx); +void jna_label(codeblock_t* cb, uint32_t label_idx); +void jnae_label(codeblock_t* cb, uint32_t label_idx); +void jnb_label(codeblock_t* cb, uint32_t label_idx); +void jnbe_label(codeblock_t* cb, uint32_t label_idx); +void jnc_label(codeblock_t* cb, uint32_t label_idx); +void jne_label(codeblock_t* cb, uint32_t label_idx); +void jng_label(codeblock_t* cb, uint32_t label_idx); +void jnge_label(codeblock_t* cb, uint32_t label_idx); +void jnl_label(codeblock_t* cb, uint32_t label_idx); +void jnle_label(codeblock_t* cb, uint32_t label_idx); +void jno_label(codeblock_t* cb, uint32_t label_idx); +void jnp_label(codeblock_t* cb, uint32_t label_idx); +void jns_label(codeblock_t* cb, uint32_t label_idx); +void jnz_label(codeblock_t* cb, uint32_t label_idx); +void jo_label(codeblock_t* cb, uint32_t label_idx); +void jp_label(codeblock_t* cb, uint32_t label_idx); +void jpe_label(codeblock_t* cb, uint32_t label_idx); +void jpo_label(codeblock_t* cb, uint32_t label_idx); +void js_label(codeblock_t* cb, uint32_t label_idx); +void jz_label(codeblock_t* cb, uint32_t label_idx); +void ja_ptr(codeblock_t* cb, uint8_t* ptr); +void jae_ptr(codeblock_t* cb, uint8_t* ptr); +void jb_ptr(codeblock_t* cb, uint8_t* ptr); +void jbe_ptr(codeblock_t* cb, uint8_t* ptr); +void jc_ptr(codeblock_t* cb, uint8_t* ptr); +void je_ptr(codeblock_t* cb, uint8_t* ptr); +void jg_ptr(codeblock_t* cb, uint8_t* ptr); +void jge_ptr(codeblock_t* cb, uint8_t* ptr); +void jl_ptr(codeblock_t* cb, uint8_t* ptr); +void jle_ptr(codeblock_t* cb, uint8_t* ptr); +void jna_ptr(codeblock_t* cb, uint8_t* ptr); +void jnae_ptr(codeblock_t* cb, uint8_t* ptr); +void jnb_ptr(codeblock_t* cb, uint8_t* ptr); +void jnbe_ptr(codeblock_t* cb, uint8_t* ptr); +void jnc_ptr(codeblock_t* cb, uint8_t* ptr); +void jne_ptr(codeblock_t* cb, uint8_t* ptr); +void jng_ptr(codeblock_t* cb, uint8_t* ptr); +void jnge_ptr(codeblock_t* cb, uint8_t* ptr); +void jnl_ptr(codeblock_t* cb, uint8_t* ptr); +void jnle_ptr(codeblock_t* cb, uint8_t* ptr); +void jno_ptr(codeblock_t* cb, uint8_t* ptr); +void jnp_ptr(codeblock_t* cb, uint8_t* ptr); +void jns_ptr(codeblock_t* cb, uint8_t* ptr); +void jnz_ptr(codeblock_t* cb, uint8_t* ptr); +void jo_ptr(codeblock_t* cb, uint8_t* ptr); +void jp_ptr(codeblock_t* cb, uint8_t* ptr); +void jpe_ptr(codeblock_t* cb, uint8_t* ptr); +void jpo_ptr(codeblock_t* cb, uint8_t* ptr); +void js_ptr(codeblock_t* cb, uint8_t* ptr); +void jz_ptr(codeblock_t* cb, uint8_t* ptr); +void jmp_label(codeblock_t* cb, uint32_t label_idx); +void jmp_ptr(codeblock_t* cb, uint8_t* ptr); +void jmp_rm(codeblock_t* cb, x86opnd_t opnd); +void jmp32(codeblock_t* cb, int32_t offset); +void lea(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void mov(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void movsx(codeblock_t* cb, x86opnd_t dst, x86opnd_t src); +void neg(codeblock_t* cb, x86opnd_t opnd); +void nop(codeblock_t* cb, uint32_t length); +void not(codeblock_t* cb, x86opnd_t opnd); +void or(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void pop(codeblock_t* cb, x86opnd_t reg); +void popfq(codeblock_t* cb); +void push(codeblock_t* cb, x86opnd_t opnd); +void pushfq(codeblock_t* cb); +void ret(codeblock_t* cb); +void sal(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void sar(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void shl(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void shr(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void sub(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); +void test(codeblock_t* cb, x86opnd_t rm_opnd, x86opnd_t test_opnd); +void ud2(codeblock_t* cb); +void xor(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); + +void cb_write_lock_prefix(codeblock_t* cb); + +#endif |