aboutsummaryrefslogtreecommitdiffstats
path: root/yjit_asm.h
diff options
context:
space:
mode:
Diffstat (limited to 'yjit_asm.h')
-rw-r--r--yjit_asm.h384
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