kit

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

c_emit.h (10753B)


      1 #ifndef KIT_C_TARGET_C_EMIT_H
      2 #define KIT_C_TARGET_C_EMIT_H
      3 
      4 /* C-source emission core. See doc/CBACKEND.md.
      5  *
      6  * This target is selected when CodeOptions.emit_c_source is set. It writes
      7  * target-locked C source to CodeOptions.c_source_writer instead of object
      8  * bytes. Operates with semantic temporary locals minted by CG. */
      9 
     10 #include <kit/core.h>
     11 
     12 #include "cg/cgtarget.h"
     13 #include "core/core.h"
     14 
     15 typedef CGLocal CLocal;
     16 
     17 /* Heap-backed growable byte buffer. Used for the per-function declaration
     18  * and body buffers; CG needs decls at function top but doesn't surface them
     19  * before body emission, so we accumulate both and flush at func_end. */
     20 typedef struct CBuf {
     21   Heap* heap;
     22   u8* data;
     23   size_t len;
     24   size_t cap;
     25 } CBuf;
     26 
     27 void cbuf_init(CBuf* b, Heap* h);
     28 void cbuf_fini(CBuf* b);
     29 void cbuf_reset(CBuf* b);
     30 void cbuf_putc(CBuf* b, char c);
     31 void cbuf_puts(CBuf* b, const char* s);
     32 void cbuf_putn(CBuf* b, const char* s, size_t n);
     33 void cbuf_put_i64(CBuf* b, i64 v);
     34 void cbuf_put_u64(CBuf* b, u64 v);
     35 
     36 typedef struct CLocalStaticLabelEntry {
     37   Label label;
     38   i64 addend;
     39   u8 has_label;
     40   u8 pad[3];
     41 } CLocalStaticLabelEntry;
     42 
     43 typedef struct CTarget {
     44   Compiler* c;
     45   ObjBuilder* obj;
     46   KitWriter* w;
     47 
     48   /* TU prologue (e.g. #include <stdint.h>) emitted once, on first
     49    * function or finalize, whichever first. */
     50   u8 prologue_emitted;
     51   u8 finalized;
     52   u8 pad[2];
     53 
     54   /* TU-wide forward declarations: one `RetT name(params);` line per function
     55    * we've seen a definition or call for. Emitted just after the prologue so
     56    * callers defined earlier in the TU still see the prototype, and calls to
     57    * undefined-in-TU externs get a declaration too. */
     58   CBuf forwards;
     59   /* Forward-decl dedup: which ObjSymIds have we already declared. Lazily
     60    * grown bitmap indexed by ObjSymId. */
     61   u8* sym_forwarded;
     62   u32 sym_forwarded_cap;
     63 
     64   /* TU-wide typedefs (records, arrays, function pointers, opaque storage).
     65    * Emitted between prologue and forwards. */
     66   CBuf typedefs;
     67   /* TU-wide data definitions and extern data declarations. Emitted between
     68    * forwards and function bodies so functions can reference data symbols and
     69    * data initializers can reference function forward decls. Populated at
     70    * finalize by walking the ObjBuilder's data sections. */
     71   CBuf data_defs;
     72   /* Per-type id state: 0 = not seen, 1 = inflight, 2 = emitted. */
     73   u8* type_state;
     74   u32 type_state_cap;
     75   /* Tracks whether <stdarg.h> needs to be emitted in the prologue. Set when
     76    * c_typename first encounters VARARG_STATE. Flushed lazily at finalize. */
     77   u8 need_stdarg;
     78   u8 need_setjmp;
     79   u8 pad2[2];
     80 
     81   /* Per-function buffers. Reset on func_end. */
     82   CBuf decls;
     83   CBuf body;
     84 
     85   /* Function-local static data consumed from CG's narrow source-backend data
     86    * hook. These symbols are emitted inside the owning function and skipped by
     87    * the TU-wide object-data walker. */
     88   ObjSymId* local_static_syms;
     89   u32 local_static_nsyms;
     90   u32 local_static_syms_cap;
     91 
     92   CLocalStaticLabelEntry* local_static_entries;
     93   u32 local_static_nentries;
     94   u32 local_static_entries_cap;
     95   ObjSymId local_static_sym;
     96   KitCgTypeId local_static_type;
     97   u64 local_static_count;
     98   u64 local_static_offset;
     99   u32 local_static_ptr_width;
    100   u32 local_static_align;
    101   u8 local_static_active;
    102   u8 local_static_is_array;
    103   u8 local_static_readonly;
    104   u8 pad_local_static;
    105 
    106   /* Per-function local-decl tracking: for each local id seen, mark whether we
    107    * have already emitted a declaration into `decls`. Sized by local_cap.
    108    * Grown lazily as new local ids appear. */
    109   u8* local_declared;
    110   KitCgTypeId* local_type; /* declared type for each semantic local */
    111   u32 local_cap;
    112 
    113   /* Splice bookmark: byte offset into body where the current function's body
    114    * region starts (right after the open brace). func_end uses this to insert
    115    * the per-function declarations between the signature and the body. */
    116   size_t fn_body_start;
    117 
    118   const CGFuncDesc* cur_fn;
    119 
    120   /* Most recent source line directive emitted into the current function body.
    121    * Reset on func_begin; used by c_set_loc to avoid noisy duplicate #line
    122    * directives. */
    123   SrcLoc emitted_loc;
    124   u8 have_emitted_loc;
    125   u8 pad_cur_loc[3];
    126 
    127   /* Label minting: ids 1..next_label. 0 is reserved as LABEL_NONE. */
    128   u32 next_label;
    129   u32 next_local;
    130 
    131   /* Stack of active scopes. CGScope handles are (scope_index + 1). */
    132   struct CScopeInfo* scopes;
    133   u32 scopes_cap;
    134   u32 nscopes;
    135 
    136   /* Monotone counter for synthesizing unique temporary names within a
    137    * function (e.g. bitcast scratch). Reset on func_begin. */
    138   u32 next_tmp;
    139 
    140   /* Tracks whether the last emitted body statement was an unconditional
    141    * terminator (`return`, `goto`, etc.) with no intervening label. When
    142    * set, subsequent ret/jump/cmp_branch emissions are dropped — they're
    143    * unreachable, and emitting them produces dead C that distracts from
    144    * the live code. Reset on func_begin and label_place. */
    145   u8 last_was_terminator;
    146   u8 pad3[3];
    147 } CTarget;
    148 
    149 typedef struct CScopeInfo {
    150   u8 kind; /* ScopeKind */
    151   /* Set when the C target emitted a `for (;;) { ... }` wrapper around
    152    * this scope. Drives jump/cmp_branch's translation of break/continue
    153    * labels into C `break;`/`continue;` and scope_end's `}`. */
    154   u8 structured;
    155   u8 pad[2];
    156   Label break_label;
    157   Label continue_label;
    158 } CScopeInfo;
    159 
    160 void c_emit_target_init(CTarget* t, Compiler* c, ObjBuilder* o, KitWriter* w);
    161 CTarget* c_emit_target_new(Compiler* c, ObjBuilder* o, KitWriter* w);
    162 
    163 void c_emit_prologue(CTarget* t);
    164 /* Ensure local `r` (typed `type`) has been declared. */
    165 void c_ensure_local(CTarget* t, CLocal r, KitCgTypeId type);
    166 /* Get a stable C identifier for local r. Writes into caller-supplied buf. */
    167 void c_local_name(CLocal r, char* out, size_t cap);
    168 /* Write the C type for a CG int/float/ptr type to `b`. */
    169 void c_emit_type(CTarget* t, CBuf* b, KitCgTypeId type);
    170 /* Write operand expression to body (e.g. "v3", "(int32_t)42"). Supports
    171  * OPK_LOCAL / OPK_IMM / OPK_GLOBAL. INDIRECT is only valid in
    172  * lvalue positions and is emitted via load/store/addr_of paths. */
    173 void c_emit_operand(CTarget* t, Operand op);
    174 /* Like c_emit_operand but wraps in an explicit signed/unsigned cast of the
    175  * operand's type width. For integer ops where signedness affects semantics
    176  * (UDIV/UREM, SHR_U, unsigned compares). Falls back to c_emit_operand when
    177  * the operand is not integer-typed. */
    178 void c_emit_operand_signed(CTarget* t, Operand op, int signed_);
    179 
    180 /* Lookup the C linker name for an ObjSymId. Returns interned string. */
    181 const char* c_sym_name(CTarget* t, ObjSymId sym);
    182 
    183 /* Emit a forward declaration for `sym` (of function type `fn_type`) into
    184  * the TU forwards buffer if not already done. Idempotent per sym. */
    185 void c_ensure_forward_decl(CTarget* t, ObjSymId sym, KitCgTypeId fn_type);
    186 
    187 /* Write `n` bytes to t->w; panic on error. */
    188 void c_writer_write(CTarget* t, const void* data, size_t n);
    189 void c_writer_puts(CTarget* t, const char* s);
    190 
    191 void c_emit_func_begin(CTarget*, const CGFuncDesc*);
    192 void c_emit_func_end(CTarget*);
    193 void c_emit_alias(CTarget*, ObjSymId, ObjSymId, KitCgTypeId);
    194 /* Re-emit a file-scope `__asm__("...")` block verbatim at TU scope. */
    195 void c_emit_file_scope_asm(CTarget*, const char* src, size_t len);
    196 void c_emit_ret(CTarget*, CGLocal value);
    197 void c_emit_unreachable(CTarget*);
    198 void c_emit_load_imm(CTarget*, Operand, i64);
    199 void c_emit_load_const(CTarget*, Operand, ConstBytes);
    200 void c_emit_copy(CTarget*, Operand, Operand);
    201 void c_emit_binop(CTarget*, BinOp, Operand, Operand, Operand);
    202 void c_emit_unop(CTarget*, UnOp, Operand, Operand);
    203 void c_emit_cmp(CTarget*, CmpOp, Operand, Operand, Operand);
    204 void c_emit_convert(CTarget*, ConvKind, Operand, Operand);
    205 void c_emit_call(CTarget*, const CGCallDesc*);
    206 const char* c_emit_tail_call_unrealizable_reason(CTarget*, const CGCallDesc*);
    207 const char* c_emit_tail_call_unrealizable_reason_for(CTarget*,
    208                                                      const CGFuncDesc*,
    209                                                      const CGCallDesc*);
    210 void c_emit_load(CTarget*, Operand, Operand, MemAccess);
    211 void c_emit_store(CTarget*, Operand, Operand, MemAccess);
    212 void c_emit_addr_of(CTarget*, Operand, Operand);
    213 CGLocal c_emit_param(CTarget*, const CGParamDesc*);
    214 CGLocal c_emit_local(CTarget*, const CGLocalDesc*);
    215 void c_emit_param_bind(CTarget*, CGLocal, KitCgTypeId, u32);
    216 void c_emit_local_addr(CTarget*, Operand, const CGLocalDesc*, CGLocal);
    217 Label c_emit_label_new(CTarget*);
    218 void c_emit_label_place(CTarget*, Label);
    219 void c_emit_jump(CTarget*, Label);
    220 void c_emit_cmp_branch(CTarget*, CmpOp, Operand, Operand, Label);
    221 void c_emit_switch_(CTarget*, const CGSwitchDesc*);
    222 void c_emit_indirect_branch(CTarget*, Operand, const Label*, u32);
    223 void c_emit_load_label_addr(CTarget*, Operand, Label);
    224 int c_emit_local_static_data_begin(CTarget*, const CGLocalStaticDataDesc*);
    225 int c_emit_can_local_static_data(CTarget*, const CGLocalStaticDataDesc*);
    226 void c_emit_local_static_data_write(CTarget*, const u8*, u64);
    227 void c_emit_local_static_data_label_addr(CTarget*, Label, i64, u32, u32);
    228 void c_emit_local_static_data_end(CTarget*);
    229 CGScope c_emit_scope_begin(CTarget*, const CGScopeDesc*);
    230 void c_emit_scope_end(CTarget*, CGScope);
    231 void c_emit_break_to(CTarget*, CGScope);
    232 void c_emit_continue_to(CTarget*, CGScope);
    233 void c_emit_set_loc(CTarget*, SrcLoc);
    234 void c_emit_finalize(CTarget*);
    235 void c_emit_destroy(CTarget*);
    236 void c_emit_intrinsic(CTarget*, IntrinKind, Operand*, u32, const Operand*, u32);
    237 void c_emit_alloca(CTarget*, Operand, Operand, u32);
    238 void c_emit_va_start(CTarget*, Operand);
    239 void c_emit_va_arg(CTarget*, Operand, Operand, KitCgTypeId);
    240 void c_emit_va_end(CTarget*, Operand);
    241 void c_emit_va_copy(CTarget*, Operand, Operand);
    242 void c_emit_copy_bytes(CTarget*, Operand, Operand, AggregateAccess);
    243 void c_emit_set_bytes(CTarget*, Operand, Operand, AggregateAccess);
    244 void c_emit_asm_block(CTarget*, const char*, const AsmConstraint*, u32,
    245                       Operand*, const AsmConstraint*, u32, const Operand*,
    246                       const Sym*, u32);
    247 void c_emit_bitfield_load(CTarget*, Operand, Operand, BitFieldAccess);
    248 void c_emit_bitfield_store(CTarget*, Operand, Operand, BitFieldAccess);
    249 void c_emit_tls_addr_of(CTarget*, Operand, ObjSymId, i64);
    250 void c_emit_atomic_load(CTarget*, Operand, Operand, MemAccess, KitCgMemOrder);
    251 void c_emit_atomic_store(CTarget*, Operand, Operand, MemAccess, KitCgMemOrder);
    252 void c_emit_atomic_rmw(CTarget*, KitCgAtomicOp, Operand, Operand, Operand,
    253                        MemAccess, KitCgMemOrder);
    254 void c_emit_atomic_cas(CTarget*, Operand, Operand, Operand, Operand, Operand,
    255                        MemAccess, KitCgMemOrder, KitCgMemOrder);
    256 void c_emit_fence(CTarget*, KitCgMemOrder);
    257 
    258 #endif