emit.h (6469B)
1 /* arch/x64/emit.h — shared x86-64 byte-level encoders, ABI tables, and type 2 * helpers. Used by emit.c (definitions), the standalone assembler (asm.c), and 3 * the NativeTarget codegen (native.c). Carries no codegen state (XImpl lives in 4 * native.c). */ 5 #ifndef KIT_ARCH_X64_EMIT_H 6 #define KIT_ARCH_X64_EMIT_H 7 8 #include <kit/cg.h> 9 #include <kit/compile.h> 10 11 #include "abi/abi.h" 12 #include "arch/mc.h" 13 #include "arch/x64/isa.h" 14 #include "core/core.h" 15 #include "core/slice.h" 16 #include "obj/obj.h" 17 18 /* ---- prologue placeholder budgets / Win64 constants ---- 19 * X64_PROLOGUE_BYTES / _WIN64 are the worst-case buffer sizes (optimizer path: 20 * up to 7 int + 10 fp callee-saves). X64_NDT_PROLOGUE_BYTES / _WIN64 are the 21 * smaller *single-pass (-O0)* reservation: the NDT only ever caches in its 22 * allocable pool's callee-saved subset (3 int r13-r15; on Win64 also 6 fp 23 * xmm6-11), so its prologue is bounded to push+mov(4) + sub/chkstk(7/13) + 24 * sret(7) + 3*int-spill(21) [+ 6*fp-spill(54)] = 39 (SysV) / 99 (Win64). */ 25 #define X64_PROLOGUE_BYTES 96u 26 #define X64_PROLOGUE_BYTES_WIN64 192u 27 #define X64_NDT_PROLOGUE_BYTES 48u 28 #define X64_NDT_PROLOGUE_BYTES_WIN64 112u 29 #define X64_PROLOGUE_BASE_BYTES 11u 30 #define X64_WIN64_SHADOW_SPACE 32u 31 #define X64_MAX_CS_INT_REGS 7u 32 33 /* ---- per-OS ABI register layout (SysV vs Win64) ---- */ 34 typedef struct X64ABIRegs { 35 const u32* int_args; /* size = n_int_args */ 36 u32 n_int_args; /* 6 (SysV) / 4 (Win64) */ 37 u32 n_fp_args; /* 8 (SysV) / 4 (Win64) */ 38 int slot_shared_int_fp; /* 1 (Win64): arg slot index shared int/xmm */ 39 u32 shadow_space; /* 0 (SysV) / 32 (Win64) */ 40 int emit_sysv_vararg_save; /* 1 (SysV): emit 176B reg-save area */ 41 int vararg_fp_dup_to_gpr; /* 1 (Win64): variadic FP arg duped to GPR */ 42 u64 cs_int_mask; /* callee-saved GPRs */ 43 u64 cs_fp_mask; /* callee-saved XMMs */ 44 } X64ABIRegs; 45 46 const X64ABIRegs* x64_abi_for_os(KitOSKind os); 47 48 /* Per-instruction debug line rows. Declared here (mc.h only forward-declares 49 * Debug) so emit.c's encoders and native.c's lifecycle can both record rows 50 * without taking a full dependency on debug/debug.h. */ 51 extern void debug_emit_row(Debug*, ObjSecId text_section, u32 offset, SrcLoc); 52 extern void debug_func_pc_range(Debug*, ObjSecId text_section, u32 begin_ofs, 53 u32 end_ofs); 54 55 /* ---- type helpers ---- */ 56 #define CG_BUILTIN_ID(k) ((KitCgTypeId)((1u << 6) | (u32)(k))) 57 static inline int type_is_64(KitCgTypeId t) { 58 return t == CG_BUILTIN_ID(KIT_CG_BUILTIN_I64) || 59 t == CG_BUILTIN_ID(KIT_CG_BUILTIN_F64) || t >= (KitCgTypeId)(2u << 6); 60 } 61 static inline int type_is_fp_double(KitCgTypeId t) { 62 return t == CG_BUILTIN_ID(KIT_CG_BUILTIN_F64); 63 } 64 static inline u32 type_byte_size(KitCgTypeId t) { 65 if (t == CG_BUILTIN_ID(KIT_CG_BUILTIN_I8) || 66 t == CG_BUILTIN_ID(KIT_CG_BUILTIN_BOOL)) 67 return 1; 68 if (t == CG_BUILTIN_ID(KIT_CG_BUILTIN_I16)) return 2; 69 if (t == CG_BUILTIN_ID(KIT_CG_BUILTIN_I32) || 70 t == CG_BUILTIN_ID(KIT_CG_BUILTIN_F32)) 71 return 4; 72 if (t == CG_BUILTIN_ID(KIT_CG_BUILTIN_F128)) return 16; 73 return 8; 74 } 75 76 static inline void x64_abi_direct_reg_need(const ABIArgInfo* ai, u32* need_int, 77 u32* need_fp) { 78 *need_int = 0; 79 *need_fp = 0; 80 if (!ai || ai->kind != ABI_ARG_DIRECT) return; 81 for (u32 i = 0; i < ai->nparts; ++i) { 82 const ABIArgPart* p = &ai->parts[i]; 83 if (p->cls == ABI_CLASS_FP) 84 ++*need_fp; 85 else if (p->cls == ABI_CLASS_INT) 86 ++*need_int; 87 } 88 } 89 90 /* ---- byte-level encoders (defined in emit.c) ---- */ 91 void emit1(MCEmitter* mc, u8 b); 92 void emit_leave(MCEmitter* mc); 93 void emit_u32le(MCEmitter* mc, u32 v); 94 void emit_rex(MCEmitter* mc, int w, u32 reg, u32 index, u32 rm); 95 void emit_rex_force(MCEmitter* mc, int w, u32 reg, u32 index, u32 rm); 96 u8 modrm(u32 mod, u32 reg, u32 rm); 97 u8 sib(u32 scale, u32 index, u32 base); 98 void emit_mem_operand(MCEmitter* mc, u32 reg, u32 base, i32 disp); 99 void emit_rm_reg(MCEmitter* mc, u32 reg, u32 rm); 100 void emit_mov_rr(MCEmitter* mc, int w, u32 dst, u32 src); 101 void emit_mov_load(MCEmitter* mc, u32 size, int signed_ext, u32 dst, u32 base, 102 i32 disp); 103 void emit_mov_store(MCEmitter* mc, u32 size, u32 src, u32 base, i32 disp); 104 void emit_lea(MCEmitter* mc, u32 dst, u32 base, i32 disp); 105 void emit_mov_load_idx(MCEmitter* mc, u32 size, int signed_ext, u32 dst, 106 u32 base, u32 index, u32 log2_scale, i32 disp); 107 void emit_mov_store_idx(MCEmitter* mc, u32 size, u32 src, u32 base, u32 index, 108 u32 log2_scale, i32 disp); 109 void emit_ret(MCEmitter* mc); 110 void x64_emit_load_imm(MCEmitter* mc, int is64, u32 dst, i64 imm); 111 void emit_alu_rr(MCEmitter* mc, int w, u8 op, u32 dst, u32 src); 112 void emit_imul_rr(MCEmitter* mc, int w, u32 dst, u32 src); 113 void emit_f7_rm(MCEmitter* mc, int w, u32 sub, u32 reg); 114 void emit_shift_cl(MCEmitter* mc, int w, u32 sub, u32 reg); 115 void emit_shift_imm(MCEmitter* mc, int w, u32 sub, u32 reg, u8 imm); 116 void emit_cqo_or_cdq(MCEmitter* mc, int w); 117 void emit_xor_self(MCEmitter* mc, int w, u32 r); 118 void emit_cmp_imm8(MCEmitter* mc, int w, u32 reg, i8 imm); 119 void emit_alu_imm8(MCEmitter* mc, int w, u32 sub, u32 reg, i8 imm); 120 void emit_alu_imm32(MCEmitter* mc, int w, u32 sub, u32 reg, i32 imm); 121 void emit_imul_imm8(MCEmitter* mc, int w, u32 dst, u32 src, i8 imm); 122 void emit_imul_imm32(MCEmitter* mc, int w, u32 dst, u32 src, i32 imm); 123 int imm_fits_i8(i64 imm); 124 int imm_fits_i32(i64 imm); 125 void emit_test_self(MCEmitter* mc, int w, u32 reg); 126 void emit_setcc(MCEmitter* mc, u32 cc, u32 reg); 127 void emit_movzx_r32_r8(MCEmitter* mc, u32 dst, u32 src); 128 void emit_extend_rr(MCEmitter* mc, int w, int signed_ext, u32 src_size, u32 dst, 129 u32 src); 130 void emit_sse_rr(MCEmitter* mc, u8 prefix, u8 opcode, u32 dst, u32 src); 131 void emit_sse_load(MCEmitter* mc, u8 prefix, u8 opcode, u32 dst, u32 base, 132 i32 disp); 133 void emit_sse_store(MCEmitter* mc, u8 prefix, u8 opcode, u32 src, u32 base, 134 i32 disp); 135 void emit_sse_load_idx(MCEmitter* mc, u8 prefix, u8 opcode, u32 dst, u32 base, 136 u32 index, u32 log2_scale, i32 disp); 137 void emit_sse_store_idx(MCEmitter* mc, u8 prefix, u8 opcode, u32 src, u32 base, 138 u32 index, u32 log2_scale, i32 disp); 139 void emit_sse_rr_w(MCEmitter* mc, u8 prefix, u8 opcode, int w, u32 dst, 140 u32 src); 141 142 #endif