kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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