Skip to content
Permalink
56a1220128
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
384 lines (331 sloc) 15.2 KB
#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