mc.h (9615B)
1 #ifndef KIT_INTERNAL_ARCH_MC_H 2 #define KIT_INTERNAL_ARCH_MC_H 3 4 #include <kit/compile.h> 5 6 #include "cg/cgir.h" 7 #include "core/core.h" 8 #include "obj/obj.h" 9 10 /* Machine-code / object emission interface. One generic implementation in 11 * src/arch/mc.c serves every machine-code arch; arch-specific behavior enters 12 * only via ArchImpl.apply_label_fixup (label reloc encoding) and the 13 * ArchImpl.cfi_* constants (eh_frame CIE defaults). Pulled out of arch.h so 14 * the many emission-only consumers (per-arch emit/ops/alloc TUs, the 15 * assembler, the Debug producer) don't transitively depend on the 16 * decode/disasm/emu/dbg surfaces. */ 17 18 /* Forward-declared so CgTarget can carry an optional Debug* without 19 * pulling debug/debug.h into every translation unit that includes this 20 * header. Per doc/DWARF.md §3.2 the backend gets exactly one new dependency 21 * on Debug: this forward decl plus debug_emit_row (declared by the few 22 * backend TUs that actually emit line rows). */ 23 typedef struct Debug Debug; 24 /* mc.h speaks the CG operand vocabulary (cgir.h) and only passes an opaque 25 * CgTarget* through arch_lower_indexed, so it forward-declares the contract 26 * rather than depending on cgtarget.h. */ 27 typedef struct CgTarget CgTarget; 28 29 /* Native-only register id. The semantic CgTarget surface uses CGLocal; this 30 * remains here for MC/native helpers and disabled native backends. */ 31 typedef u32 Reg; 32 #define REG_NONE 0xffffffffu 33 34 typedef u32 MCLabel; 35 #define MC_LABEL_NONE 0u 36 37 typedef struct ArchLabelFixup { 38 ObjBuilder* obj; 39 u32 sec_id; 40 u32 offset; 41 u32 width; 42 RelocKind kind; 43 i64 disp; 44 ObjSymId cur_func_sym; 45 u32 cur_func_start; 46 } ArchLabelFixup; 47 48 typedef struct MCEmitter MCEmitter; 49 struct MCEmitter { 50 /* Machine/object emission context. Subclasses extend. */ 51 Compiler* c; 52 ObjBuilder* obj; 53 u32 section_id; 54 /* Byte buffer of the active section, resolved once per set_section so the 55 * per-instruction emit_bytes path skips obj_write's Sections_at deref + 56 * nobits branch. NULL when the active section is NOBITS/.bss (or none): emit 57 * then falls back to obj_write so bss_size accounting still runs. The pointer 58 * is stable across emits (SegVec elements don't move); only set_section 59 * re-points it. */ 60 Buf* cur_bytes; 61 62 /* Typed-store fast-path cursor into the active section's tail chunk. The 63 * per-instruction emit_word path (mc_emit32) writes a fixed-width word 64 * straight through `cur` and bumps `cur_chunk->used` + `cur_bytes->total` 65 * inline, so the Buf stays coherent at all times — no deferred sync, no 66 * libc memcpy call. `cur` always equals `cur_chunk->data + cur_chunk->used` 67 * and `cur_end` is `cur_chunk->data + cur_chunk->cap`; the cursor is 68 * (re)pointed from cur_bytes->tail by mc_cursor_repoint() at set_section and 69 * after any non-cursor write (mc_emit_bytes / fills) that may have grown or 70 * replaced the tail chunk. All three are NULL/empty when the active section 71 * is NOBITS/.bss (or none): emit then falls to obj_write via mc_emit_bytes. 72 * Because used/total stay coherent, every random-access reader (obj_pos, 73 * buf_patch, mc_pos, arch-direct obj_pos/obj_patch) sees the live frontier 74 * without any explicit sync. */ 75 BufChunk* cur_chunk; 76 u8* cur; 77 u8* cur_end; 78 79 /* Pending source location, updated by set_loc. Promoted to the base so 80 * arch backends' emit-bytes choke point can read it without reaching 81 * into the per-arch impl (used to feed debug_emit_row). */ 82 SrcLoc loc; 83 84 /* Optional Debug producer. NULL means -g is off and the per-instruction 85 * line-row fanout is skipped. Set after construction by cg_new (or by 86 * the cg_test harness, which is the parser stand-in). Per doc/DWARF.md 87 * §3.2 this is the backend's only new dependency on Debug. */ 88 Debug* debug; 89 90 /* Currently active function. Backends manage these via the 91 * mc_begin_function / mc_end_function helpers from their func_begin / 92 * func_end once they've computed the post-alignment function start 93 * position. emit_label_data_reloc reads them to compute reloc 94 * addends that resolve to the runtime address of an intra-function 95 * label. */ 96 ObjSymId cur_func_sym; 97 u32 cur_func_section; 98 u32 cur_func_start; 99 }; 100 101 /* MCEmitter has exactly one implementation (this file), so its operations are 102 * plain extern functions, not a per-instance vtable: the arch backends call 103 * these mc_* functions directly. (They are deliberately NOT `static inline`: 104 * inlining the hot emit_bytes/pos into the per-arch leaf emitters bloats them 105 * enough to break the inliner's own cascade — measured a net +21M instructions 106 * on sqlite -c — so a direct call to an out-of-line body is the win, removing 107 * the indirect call + fn-ptr load without disturbing leaf inlining.) */ 108 109 /* Construct the right target/emitter pair for c->target. */ 110 MCEmitter* mc_new(Compiler*, ObjBuilder*); 111 void mc_free(MCEmitter*); 112 113 /* Append machine-code bytes to the active section (the hot emit path). */ 114 void mc_emit_bytes(MCEmitter*, const u8* data, size_t n); 115 /* Append one little-endian 4-byte instruction word to the active section. 116 * Typed-store fast path: const-width store straight through the section 117 * cursor (no u8[4] staging, no out-of-line memcpy call). Fixed-width-insn 118 * arches (aarch64, riscv64) call this from their leaf emitter instead of 119 * staging a word into u8[4] + mc_emit_bytes. Variable-width arches (x86-64) 120 * keep using mc_emit_bytes. Keeps the Buf coherent, so any random-access 121 * reader still sees the live frontier. Falls to the buf_write path when the 122 * tail chunk can't hold the word or the section is NOBITS. */ 123 void mc_emit32(MCEmitter*, u32 word); 124 /* Current byte offset within the active section. */ 125 u32 mc_pos(MCEmitter*); 126 /* Stamp the pending source location read by the per-arch emit choke point. */ 127 void mc_set_loc(MCEmitter*, SrcLoc); 128 129 void mc_set_section(MCEmitter*, u32 section_id); 130 MCLabel mc_label_new(MCEmitter*); 131 void mc_label_place(MCEmitter*, MCLabel); 132 void mc_emit_fill(MCEmitter*, size_t n, u8 byte); 133 void mc_emit_align(MCEmitter*, u32 align, u8 fill); 134 void mc_emit_reloc(MCEmitter*, RelocKind, ObjSymId, i64 addend); 135 void mc_emit_reloc_at(MCEmitter*, u32 section_id, u32 offset, RelocKind, ObjSymId, 136 i64 addend, int explicit_addend, int pair); 137 void mc_emit_label_ref(MCEmitter*, MCLabel, RelocKind, u32 width, i64 addend); 138 /* Emit a relocation at (data_sec, data_offset) that resolves at link time to 139 * the runtime address of `label` (an intra-function code label). Generated 140 * against the active function symbol; emitted immediately if `label` is placed, 141 * else queued and emitted at label_place. Requires an active function. */ 142 void mc_emit_label_data_reloc(MCEmitter*, u32 data_sec, u32 data_offset, 143 MCLabel label, RelocKind kind, u32 width, 144 i64 extra_addend); 145 /* ---- CFI / unwind ---- buffered per-function, emitted into .eh_frame at TU 146 * finalize; byte-position-bound so they live on MCEmitter. Discarded when the 147 * CG was constructed with Debug=NULL. */ 148 void mc_cfi_startproc(MCEmitter*); 149 void mc_cfi_endproc(MCEmitter*); 150 void mc_cfi_def_cfa(MCEmitter*, u32 reg, i32 ofs); 151 void mc_cfi_offset(MCEmitter*, u32 reg, i32 ofs); 152 /* Override the PC offset used by the *next* cfi_* directive (sticky until 153 * cfi_endproc) — for backends that emit the CFI batch in func_end. */ 154 void mc_cfi_set_next_pc_offset(MCEmitter*, u32 pc_offset); 155 156 /* Lazily mint (and return) a per-label SB_LOCAL symbol defined at `label`'s 157 * placement. Backends use this to reference a code location relocatably — 158 * `&&label` address-takes emit a PC-relative reloc against it instead of baking 159 * a fixed displacement, so a re-encoding assembler (clang) recomputes the right 160 * address. Forward-ref safe: if `label` is not yet placed the symbol is created 161 * undefined and defined in label_place. */ 162 ObjSymId mc_label_symbol(MCEmitter*, MCLabel label); 163 164 /* Per-function context helpers. Backends call mc_begin_function from 165 * their CgTarget func_begin (after computing the post-alignment function 166 * start) and mc_end_function from func_end. The pair sets / clears 167 * MCEmitter.cur_func_* — the metadata that emit_label_data_reloc reads 168 * to resolve deferred intra-function label fixups in data sections. */ 169 void mc_begin_function(MCEmitter*, ObjSymId sym, u32 section_id, 170 u32 start_offset); 171 void mc_end_function(MCEmitter*); 172 173 /* Flush buffered CFI state into a .eh_frame section in the ObjBuilder. 174 * No-op when no functions called cfi_startproc. Idempotent. */ 175 void mc_emit_eh_frame(MCEmitter*); 176 177 /* Construct the MCEmitter + (optionally) Debug pair that a machine-code 178 * CGBackend's `make` typically needs. On success, sets *out_mc to a fresh 179 * MCEmitter; sets *out_debug to a Debug producer (and wires mc->debug) when 180 * opts->debug_info is true, else NULL. On allocation failure returns 181 * KIT_NOMEM with both outputs left NULL and any partial state cleaned up. 182 * c_target's backend ignores this and does not create either. */ 183 KitStatus cg_mc_debug_new(Compiler*, ObjBuilder*, const KitCodeOptions*, 184 MCEmitter** out_mc, Debug** out_debug); 185 186 /* Helper for backends without a native indexed addressing mode. If addr has 187 * an index (addr.v.ind.index != REG_NONE), materializes 188 * base + (index << log2_scale) into `scratch` and returns a plain 189 * OPK_INDIRECT(scratch, ofs). Otherwise returns `addr` unchanged. The caller 190 * supplies the scratch register from its scratch pool. */ 191 Operand arch_lower_indexed(CgTarget*, Operand addr, Reg scratch); 192 193 #endif