kit

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

decl.c (5537B)


      1 /* DeclTable โ€” C declaration semantics above the public CG API.
      2  *
      3  * Maps DeclId โ†’ Decl record. Allocates a KitCgSym for any non-typedef,
      4  * non-auto/register decl with linkage.
      5  *
      6  * Identifier *lookup* is not handled here โ€” that lives on the parser's
      7  * scope stack so block scopes and shadowing fall out naturally. DeclTable
      8  * is just the C-language layer above CG: storage class, linkage,
      9  * static-locals, tentative defs, and global initializers.
     10  *
     11  * v1 surface is intentionally minimal: just enough for the spine corpus
     12  * (functions; ints; static locals) plus the hooks DESIGN.md ยง5.3.1
     13  * commits to. Tentative-definition coalescing, COMDAT, and aliases are
     14  * stubs at the API edge; their full semantics arrive with the multi-TU
     15  * corpus. */
     16 
     17 #include "decl/decl.h"
     18 
     19 #include <string.h>
     20 
     21 struct DeclTable {
     22   Compiler* c;
     23   Pool* pool;
     24   KitCg* cg;
     25   Decl* slots; /* index 0 reserved as DECL_NONE */
     26   u32 nslots;
     27   u32 cap;
     28 };
     29 
     30 #define DECL_INITIAL_CAP 16u
     31 
     32 static void decls_grow(DeclTable* t, u32 want) {
     33   Heap* h = kit_compiler_context(t->c)->heap;
     34   u32 cap = t->cap;
     35   Decl* nb;
     36   if (cap >= want) return;
     37   while (cap < want) cap = cap ? cap * 2u : DECL_INITIAL_CAP;
     38   nb = (Decl*)h->alloc(h, sizeof(Decl) * cap, _Alignof(Decl));
     39   if (t->slots) {
     40     memcpy(nb, t->slots, sizeof(Decl) * t->nslots);
     41     h->free(h, t->slots, sizeof(Decl) * t->cap);
     42   }
     43   t->slots = nb;
     44   t->cap = cap;
     45 }
     46 
     47 DeclTable* decl_new(Compiler* c, Pool* pool, KitCg* cg) {
     48   Heap* h = kit_compiler_context(c)->heap;
     49   DeclTable* t =
     50       (DeclTable*)h->alloc(h, sizeof(DeclTable), _Alignof(DeclTable));
     51   memset(t, 0, sizeof *t);
     52   t->c = c;
     53   t->pool = pool;
     54   t->cg = cg;
     55   decls_grow(t, 1);
     56   memset(&t->slots[0], 0, sizeof(Decl));
     57   t->nslots = 1;
     58   return t;
     59 }
     60 
     61 void decl_free(DeclTable* t) {
     62   Heap* h;
     63   if (!t) return;
     64   h = kit_compiler_context(t->c)->heap;
     65   if (t->slots) h->free(h, t->slots, sizeof(Decl) * t->cap);
     66   h->free(h, t, sizeof(*t));
     67 }
     68 
     69 static KitCgSymbolAttrs decl_sym_attrs(const Decl* d) {
     70   KitCgSymbolAttrs a;
     71   memset(&a, 0, sizeof a);
     72   a.bind = (d->linkage == DL_EXTERNAL) ? KIT_SB_GLOBAL : KIT_SB_LOCAL;
     73   if (d->flags & DF_WEAK) a.bind = KIT_SB_WEAK;
     74   a.visibility = (KitCgVisibility)d->visibility;
     75   if (d->flags & DF_USED) a.flags |= KIT_CG_SYM_USED;
     76   return a;
     77 }
     78 
     79 static KitCgInlinePolicy decl_inline_policy(const Decl* d) {
     80   if (d->flags & DF_NOINLINE) return KIT_CG_INLINE_NEVER;
     81   if (d->flags & DF_ALWAYS_INLINE) return KIT_CG_INLINE_ALWAYS;
     82   if (d->flags & DF_INLINE) return KIT_CG_INLINE_HINT;
     83   return KIT_CG_INLINE_DEFAULT;
     84 }
     85 
     86 /* Build the public CG declaration for an already-validated Decl and emit it.
     87  * Returns the resulting KitCgSym. Emission is idempotent for a name that
     88  * already has a symbol: kit_cg_decl reuses the existing symbol and only
     89  * refreshes attributes (e.g. promoting a strong global to weak). */
     90 static ObjSymId decl_emit_cg_sym(DeclTable* t, const Decl* slot) {
     91   KitCgDecl decl;
     92   memset(&decl, 0, sizeof decl);
     93   decl.kind = (slot->type && slot->type->kind == TY_FUNC) ? KIT_CG_DECL_FUNC
     94                                                           : KIT_CG_DECL_OBJECT;
     95   decl.display_name = slot->name;
     96   decl.linkage_name = kit_cg_c_linkage_name(
     97       t->c, slot->asm_name ? slot->asm_name : slot->name);
     98   decl.type = type_cg_id_in_pool(t->c, t->pool, slot->type);
     99   decl.sym = decl_sym_attrs(slot);
    100   if (decl.kind == KIT_CG_DECL_FUNC) {
    101     if (slot->flags & DF_NORETURN) decl.as.func.flags |= KIT_CG_FUNC_NORETURN;
    102     decl.as.func.inline_policy = decl_inline_policy(slot);
    103     decl.as.func.section = slot->section_id;
    104     decl.as.func.wasm_import_module = slot->wasm_import_module;
    105     decl.as.func.wasm_import_name = slot->wasm_import_name;
    106   } else {
    107     if (slot->flags & DF_THREAD) decl.as.object.flags |= KIT_CG_OBJ_TLS;
    108     decl.as.object.section = slot->section_id;
    109     decl.as.object.align = slot->align;
    110   }
    111   return kit_cg_decl(t->cg, decl);
    112 }
    113 
    114 DeclId decl_declare(DeclTable* t, const Decl* in) {
    115   DeclId id;
    116   Decl* slot;
    117   decls_grow(t, t->nslots + 1);
    118   id = (DeclId)t->nslots++;
    119   slot = &t->slots[id];
    120   *slot = *in;
    121   slot->id = id;
    122   if (slot->obj_sym == OBJ_SYM_NONE && slot->name &&
    123       slot->storage != DS_TYPEDEF && slot->storage != DS_AUTO &&
    124       slot->storage != DS_REGISTER) {
    125     if (slot->flags & DF_WEAK) {
    126       if (slot->linkage != DL_EXTERNAL)
    127         compiler_panic(t->c, slot->loc,
    128                        "weak attribute requires external linkage");
    129     }
    130     slot->obj_sym = decl_emit_cg_sym(t, slot);
    131   }
    132   return id;
    133 }
    134 
    135 void decl_apply_redecl_flags(DeclTable* t, DeclId id, u32 new_flags) {
    136   Decl* slot;
    137   if (id == DECL_NONE || id >= t->nslots) return;
    138   slot = &t->slots[id];
    139   /* C lets the `weak` attribute appear on any declaration; if a later
    140    * redeclaration or the definition introduces it, the already-emitted symbol
    141    * must become weak too. Other redeclaration-merge flags don't affect the
    142    * emitted symbol, so weak is all we re-apply here. */
    143   if (!(new_flags & DF_WEAK) || (slot->flags & DF_WEAK)) return;
    144   if (slot->linkage != DL_EXTERNAL)
    145     compiler_panic(t->c, slot->loc, "weak attribute requires external linkage");
    146   slot->flags |= DF_WEAK;
    147   if (slot->obj_sym != OBJ_SYM_NONE) decl_emit_cg_sym(t, slot);
    148 }
    149 
    150 const Decl* decl_get(const DeclTable* t, DeclId id) {
    151   if (!t || id == DECL_NONE || id >= t->nslots) return NULL;
    152   return &t->slots[id];
    153 }
    154 
    155 ObjSymId decl_obj_sym(const DeclTable* t, DeclId id) {
    156   const Decl* d = decl_get(t, id);
    157   return d ? d->obj_sym : OBJ_SYM_NONE;
    158 }