kit

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

compile.c (32809B)


      1 /* libkit's top-level compile entry points. Status-returning shapes
      2  * that drive the C, asm, and registered-frontend paths. */
      3 
      4 #include <kit/cg.h>
      5 #include <kit/compile.h>
      6 #include <kit/core.h>
      7 #include <stdint.h>
      8 #include <string.h>
      9 
     10 #include "api/lang_registry.h"
     11 #include "arch/arch.h"
     12 #include "asm/asm.h"
     13 #include "core/core.h"
     14 #include "core/heap.h"
     15 #include "core/metrics.h"
     16 #include "core/pool.h"
     17 #include "core/slice.h"
     18 #include "obj/obj.h"
     19 
     20 typedef struct AsmFrontend {
     21   Compiler* c;
     22 } AsmFrontend;
     23 
     24 struct KitFrontend {
     25   KitCompiler* c;
     26   KitLanguage lang;
     27   const KitFrontendVTable* vtable;
     28   KitFrontendState* state;
     29 };
     30 
     31 struct KitCompileSession {
     32   KitCompiler* c;
     33   KitLanguage lang;
     34   KitFrontend* frontend;
     35   KitFrontendCompileOptions opts;
     36 };
     37 
     38 struct KitFrontendRegistry {
     39   const KitContext* ctx;
     40   const KitFrontendVTable** frontends;
     41   uint32_t nfrontends;
     42   uint32_t cap;
     43 };
     44 
     45 static KitFrontendState* asm_frontend_new(KitCompiler* c);
     46 static KitStatus asm_frontend_compile(KitFrontendState* fe,
     47                                       const KitFrontendCompileOptions* opts,
     48                                       const KitSourceInput* input,
     49                                       KitObjBuilder* out);
     50 static void asm_frontend_free(KitFrontendState* fe);
     51 
     52 static const KitSlice asm_extensions[] = {KIT_SLICE_LIT("s")};
     53 /* Canonical `-x` name plus alias; mirrors the driver's "asm"/"s" spellings. */
     54 static const KitSlice asm_names[] = {KIT_SLICE_LIT("asm"), KIT_SLICE_LIT("s")};
     55 
     56 const KitFrontendVTable kit_asm_frontend_vtable = {
     57     .new_frontend = asm_frontend_new,
     58     .compile_cg = NULL, /* asm participates in LTO as an opaque object */
     59     .compile_obj = asm_frontend_compile,
     60     .free_frontend = asm_frontend_free,
     61     .extensions = asm_extensions,
     62     .nextensions = (uint32_t)(sizeof asm_extensions / sizeof asm_extensions[0]),
     63     .extension_kinds = NULL,
     64     .names = asm_names,
     65     .nnames = (uint32_t)(sizeof asm_names / sizeof asm_names[0]),
     66     .commit = NULL,
     67     .abort = NULL,
     68     .caps = {false, KIT_FRONTEND_LTO_OPAQUE, false},
     69     .parse_options = NULL,
     70     .free_options = NULL,
     71 };
     72 
     73 static _Noreturn void panic_bad_options(Compiler* c, const char* msg) {
     74   compiler_panic(c, SRCLOC_NONE, "bad kit options: %.*s",
     75                  SLICE_ARG(slice_from_cstr(msg)));
     76 }
     77 
     78 /* Compare `ext` to `pat` letter-for-letter, lowercasing ASCII A-Z in
     79  * the path side so `.S` matches asm's `"s"` entry. `ext` is a borrowed
     80  * slice over the path tail; `pat` is the frontend's extension slice.
     81  * Returns nonzero on full match. */
     82 static int ext_eq_ci(KitSlice ext, KitSlice pat) {
     83   size_t i;
     84   if (ext.len != pat.len) return 0;
     85   for (i = 0; i < ext.len; ++i) {
     86     char a = ext.s[i];
     87     char b = pat.s[i];
     88     if (a >= 'A' && a <= 'Z') a = (char)(a - 'A' + 'a');
     89     if (a != b) return 0;
     90   }
     91   return 1;
     92 }
     93 
     94 static KitStatus validate_frontend_vtable(const KitFrontendVTable* vtable) {
     95   if (vtable) {
     96     uint8_t mode = vtable->caps.lto_mode;
     97     uint32_t i;
     98     if (!vtable->new_frontend || !vtable->free_frontend ||
     99         mode > KIT_FRONTEND_LTO_OPAQUE) {
    100       return KIT_INVALID;
    101     }
    102     if (mode == KIT_FRONTEND_LTO_CG) {
    103       if (!vtable->compile_cg) return KIT_INVALID;
    104     } else if (!vtable->compile_obj) {
    105       return KIT_INVALID;
    106     }
    107     if (vtable->extension_kinds && vtable->nextensions && !vtable->extensions)
    108       return KIT_INVALID;
    109     for (i = 0; vtable->extension_kinds && i < vtable->nextensions; ++i) {
    110       uint8_t k = vtable->extension_kinds[i];
    111       if (k != KIT_FRONTEND_PATH_SOURCE && k != KIT_FRONTEND_PATH_HEADER)
    112         return KIT_INVALID;
    113     }
    114   }
    115   return KIT_OK;
    116 }
    117 
    118 static KitFrontendPathKind vtable_extension_kind(
    119     const KitFrontendVTable* v, uint32_t index) {
    120   if (!v || index >= v->nextensions) return KIT_FRONTEND_PATH_UNKNOWN;
    121   if (!v->extension_kinds) return KIT_FRONTEND_PATH_SOURCE;
    122   return (KitFrontendPathKind)v->extension_kinds[index];
    123 }
    124 
    125 static KitStatus registry_reserve(KitFrontendRegistry* r, uint32_t want) {
    126   KitHeap* h;
    127   const KitFrontendVTable** nv;
    128   uint32_t ncap;
    129   uint32_t i;
    130   if (!r || !r->ctx || !r->ctx->heap) return KIT_INVALID;
    131   if (want <= r->cap) return KIT_OK;
    132   h = r->ctx->heap;
    133   ncap = r->cap ? r->cap : 8u;
    134   while (ncap < want) {
    135     if (ncap > UINT32_MAX / 2u) {
    136       ncap = want;
    137       break;
    138     }
    139     ncap *= 2u;
    140   }
    141   if ((size_t)ncap > SIZE_MAX / sizeof(*r->frontends)) return KIT_NOMEM;
    142   if (r->frontends) {
    143     nv = (const KitFrontendVTable**)h->realloc(
    144         h, (void*)r->frontends, r->cap * sizeof(*r->frontends),
    145         ncap * sizeof(*r->frontends), _Alignof(const KitFrontendVTable*));
    146   } else {
    147     nv = (const KitFrontendVTable**)h->alloc(
    148         h, ncap * sizeof(*r->frontends), _Alignof(const KitFrontendVTable*));
    149   }
    150   if (!nv) return KIT_NOMEM;
    151   for (i = r->cap; i < ncap; ++i) nv[i] = NULL;
    152   r->frontends = nv;
    153   r->cap = ncap;
    154   return KIT_OK;
    155 }
    156 
    157 static KitStatus compiler_frontends_reserve(Compiler* c, uint32_t want) {
    158   Heap* h;
    159   const KitFrontendVTable** nv;
    160   uint32_t ncap;
    161   uint32_t i;
    162   if (!c || !c->ctx || !c->ctx->heap) return KIT_INVALID;
    163   if (want <= c->frontends_cap) return KIT_OK;
    164   h = (Heap*)c->ctx->heap;
    165   ncap = c->frontends_cap ? c->frontends_cap : 8u;
    166   while (ncap < want) {
    167     if (ncap > UINT32_MAX / 2u) {
    168       ncap = want;
    169       break;
    170     }
    171     ncap *= 2u;
    172   }
    173   if ((size_t)ncap > SIZE_MAX / sizeof(*c->frontends)) return KIT_NOMEM;
    174   if (c->frontends) {
    175     nv = (const KitFrontendVTable**)h->realloc(
    176         h, (void*)c->frontends, c->frontends_cap * sizeof(*c->frontends),
    177         ncap * sizeof(*c->frontends), _Alignof(const KitFrontendVTable*));
    178   } else {
    179     nv = (const KitFrontendVTable**)h->alloc(
    180         h, ncap * sizeof(*c->frontends), _Alignof(const KitFrontendVTable*));
    181   }
    182   if (!nv) return KIT_NOMEM;
    183   for (i = c->frontends_cap; i < ncap; ++i) nv[i] = NULL;
    184   c->frontends = nv;
    185   c->frontends_cap = ncap;
    186   return KIT_OK;
    187 }
    188 
    189 static KitStatus compiler_register_frontend(Compiler* c, KitLanguage lang,
    190                                             const KitFrontendVTable* vtable) {
    191   KitStatus st;
    192   if (!c || lang == KIT_LANG_UNKNOWN || lang == KIT_LANG_AUTO)
    193     return KIT_INVALID;
    194   st = validate_frontend_vtable(vtable);
    195   if (st != KIT_OK) return st;
    196   st = compiler_frontends_reserve(c, lang + 1u);
    197   if (st != KIT_OK) return st;
    198   c->frontends[lang] = vtable;
    199   if (c->nfrontends < lang + 1u) c->nfrontends = lang + 1u;
    200   return KIT_OK;
    201 }
    202 
    203 /* Resolve `lang`'s frontend vtable: from the compiler's per-instance table
    204  * when a compiler is supplied, else from the compile-time default registry so
    205  * the language resolvers work with c==NULL (e.g. at CLI arg-parse time, before
    206  * a KitCompiler exists). Out-of-range `lang` yields NULL via lang_registry. */
    207 static const KitFrontendVTable* frontend_for(KitCompiler* c, unsigned lang) {
    208   if (c) {
    209     if (lang >= ((Compiler*)c)->nfrontends) return NULL;
    210     return ((Compiler*)c)->frontends[lang];
    211   }
    212   return lang_registry_vtable((KitLanguage)lang);
    213 }
    214 
    215 static const KitFrontendVTable* registry_frontend_for(
    216     const KitFrontendRegistry* r, KitLanguage lang) {
    217   if (!r || lang >= r->nfrontends) return NULL;
    218   return r->frontends[lang];
    219 }
    220 
    221 static uint32_t frontend_count_for(KitCompiler* c) {
    222   if (c) return ((Compiler*)c)->nfrontends;
    223   return KIT_LANG_BUILTIN_COUNT;
    224 }
    225 
    226 static KitFrontendPathKind language_path_kind_common(
    227     KitCompiler* c, const KitFrontendRegistry* r, const char* path,
    228     KitLanguage* out_lang) {
    229   size_t len;
    230   size_t i;
    231   KitSlice ext = SLICE_NULL;
    232   int have_ext = 0;
    233   uint32_t lang;
    234   uint32_t nlangs;
    235 
    236   if (out_lang) *out_lang = KIT_LANG_UNKNOWN;
    237   if (!path) return KIT_FRONTEND_PATH_UNKNOWN;
    238   for (len = 0; path[len]; ++len) {
    239   }
    240   i = len;
    241   while (i > 0) {
    242     --i;
    243     if (path[i] == '/') break;
    244     if (path[i] == '.') {
    245       ext.s = path + i + 1;
    246       ext.len = len - (i + 1);
    247       have_ext = 1;
    248       break;
    249     }
    250   }
    251   if (!have_ext) return KIT_FRONTEND_PATH_UNKNOWN;
    252 
    253   nlangs = r ? r->nfrontends : frontend_count_for(c);
    254   for (lang = 0; lang < nlangs; ++lang) {
    255     const KitFrontendVTable* v =
    256         r ? registry_frontend_for(r, lang) : frontend_for(c, lang);
    257     uint32_t e;
    258     if (!v || !v->extensions) continue;
    259     for (e = 0; e < v->nextensions; ++e) {
    260       if (ext_eq_ci(ext, v->extensions[e])) {
    261         if (out_lang) *out_lang = (KitLanguage)lang;
    262         return vtable_extension_kind(v, e);
    263       }
    264     }
    265   }
    266   return KIT_FRONTEND_PATH_UNKNOWN;
    267 }
    268 
    269 KitLanguage kit_language_for_path(KitCompiler* c, const char* path) {
    270   KitLanguage lang = KIT_LANG_UNKNOWN;
    271   (void)language_path_kind_common(c, NULL, path, &lang);
    272   return lang;
    273 }
    274 
    275 KitFrontendPathKind kit_language_path_kind(KitCompiler* c, const char* path,
    276                                            KitLanguage* out_lang) {
    277   return language_path_kind_common(c, NULL, path, out_lang);
    278 }
    279 
    280 /* Case-sensitive trailing-substring match (mirrors the driver's exact suffix
    281  * test for object/archive/dso paths). */
    282 static int path_has_suffix(const char* s, const char* suffix) {
    283   size_t ls = 0, lf = 0;
    284   while (s[ls]) ++ls;
    285   while (suffix[lf]) ++lf;
    286   return ls >= lf && memcmp(s + ls - lf, suffix, lf) == 0;
    287 }
    288 
    289 KitInputKind kit_input_kind_for_path(KitCompiler* c, const char* path) {
    290   if (!path) return KIT_INPUT_UNKNOWN;
    291   /* A registered frontend's compilable-source extension wins first
    292    * (case-insensitive registry). Header/interface extensions are owned by a
    293    * language but are not standalone translation units. */
    294   if (kit_language_path_kind(c, path, NULL) == KIT_FRONTEND_PATH_SOURCE)
    295     return KIT_INPUT_SOURCE;
    296   if (path_has_suffix(path, ".o") || path_has_suffix(path, ".obj"))
    297     return KIT_INPUT_OBJECT;
    298   if (path_has_suffix(path, ".a")) return KIT_INPUT_ARCHIVE;
    299   if (path_has_suffix(path, ".so") || path_has_suffix(path, ".dylib") ||
    300       path_has_suffix(path, ".tbd"))
    301     return KIT_INPUT_DSO;
    302   return KIT_INPUT_UNKNOWN;
    303 }
    304 
    305 /* Compare a NUL-terminated name to a frontend's name slice, byte-for-byte
    306  * (case-sensitive, mirroring the driver's exact `-x` spellings). Returns
    307  * nonzero on a full match. */
    308 static int name_eq(const char* name, KitSlice pat) {
    309   size_t i;
    310   for (i = 0; i < pat.len; ++i) {
    311     if (name[i] == '\0' || name[i] != pat.s[i]) return 0;
    312   }
    313   return name[pat.len] == '\0';
    314 }
    315 
    316 KitLanguage kit_language_for_name(KitCompiler* c, const char* name) {
    317   uint32_t lang;
    318   uint32_t nlangs;
    319   if (!name) return KIT_LANG_UNKNOWN;
    320   nlangs = frontend_count_for(c);
    321   for (lang = 0; lang < nlangs; ++lang) {
    322     const KitFrontendVTable* v = frontend_for(c, lang);
    323     uint32_t n;
    324     if (!v || !v->names) continue;
    325     for (n = 0; n < v->nnames; ++n) {
    326       if (name_eq(name, v->names[n])) return (KitLanguage)lang;
    327     }
    328   }
    329   return KIT_LANG_UNKNOWN;
    330 }
    331 
    332 const char* kit_language_name(KitCompiler* c, KitLanguage lang) {
    333   const KitFrontendVTable* v;
    334   if (lang == KIT_LANG_UNKNOWN || lang == KIT_LANG_AUTO) return NULL;
    335   v = frontend_for(c, (unsigned)lang);
    336   if (!v || !v->names || v->nnames == 0) return NULL;
    337   /* The first name is the canonical one. Name tables are KIT_SLICE_LIT over
    338    * string literals, so the slice's bytes are NUL-terminated just past .len. */
    339   return v->names[0].s;
    340 }
    341 
    342 const char* kit_language_default_extension(KitCompiler* c, KitLanguage lang) {
    343   const KitFrontendVTable* v;
    344   if (lang == KIT_LANG_UNKNOWN || lang == KIT_LANG_AUTO) return NULL;
    345   v = frontend_for(c, (unsigned)lang);
    346   if (!v || !v->extensions || v->nextensions == 0) return NULL;
    347   /* The first extension is the canonical one. Extension tables are
    348    * KIT_SLICE_LIT over string literals, so the slice's bytes are
    349    * NUL-terminated just past .len. */
    350   return v->extensions[0].s;
    351 }
    352 
    353 KitStatus kit_register_frontend(KitCompiler* c, KitLanguage lang,
    354                                 const KitFrontendVTable* vtable) {
    355   return compiler_register_frontend((Compiler*)c, lang, vtable);
    356 }
    357 
    358 KitStatus kit_frontend_caps(KitCompiler* c, KitLanguage lang,
    359                             KitFrontendCaps* out) {
    360   const KitFrontendVTable* v;
    361   if (!c || !out || lang == KIT_LANG_UNKNOWN || lang == KIT_LANG_AUTO)
    362     return KIT_INVALID;
    363   v = frontend_for(c, lang);
    364   if (!v) return KIT_INVALID;
    365   *out = v->caps;
    366   return KIT_OK;
    367 }
    368 
    369 KitStatus kit_frontend_parse_options(KitCompiler* c, KitLanguage lang, int argc,
    370                                      char** argv, void** out_opts) {
    371   const KitFrontendVTable* v;
    372   if (out_opts) *out_opts = NULL;
    373   if (!c || !out_opts || lang == KIT_LANG_UNKNOWN || lang == KIT_LANG_AUTO)
    374     return KIT_INVALID;
    375   v = frontend_for(c, lang);
    376   if (!v || !v->parse_options) return KIT_INVALID;
    377   return v->parse_options(c, argc, argv, out_opts);
    378 }
    379 
    380 void kit_frontend_free_options(KitCompiler* c, KitLanguage lang, void* opts) {
    381   const KitFrontendVTable* v;
    382   if (!c || !opts || lang == KIT_LANG_UNKNOWN || lang == KIT_LANG_AUTO) return;
    383   v = frontend_for(c, lang);
    384   if (v && v->free_options) v->free_options(c, opts);
    385 }
    386 
    387 KitStatus kit_frontend_registry_new(const KitContext* ctx,
    388                                     KitFrontendRegistry** out) {
    389   KitHeap* h;
    390   KitFrontendRegistry* r;
    391   if (!out) return KIT_INVALID;
    392   *out = NULL;
    393   if (!ctx || !ctx->heap) return KIT_INVALID;
    394   h = ctx->heap;
    395   r = (KitFrontendRegistry*)h->alloc(h, sizeof(*r),
    396                                      _Alignof(KitFrontendRegistry));
    397   if (!r) return KIT_NOMEM;
    398   memset(r, 0, sizeof(*r));
    399   r->ctx = ctx;
    400   *out = r;
    401   return KIT_OK;
    402 }
    403 
    404 void kit_frontend_registry_free(KitFrontendRegistry* r) {
    405   KitHeap* h;
    406   if (!r || !r->ctx || !r->ctx->heap) return;
    407   h = r->ctx->heap;
    408   if (r->frontends)
    409     h->free(h, (void*)r->frontends, r->cap * sizeof(*r->frontends));
    410   h->free(h, r, sizeof(*r));
    411 }
    412 
    413 KitStatus kit_frontend_registry_add_builtin(KitFrontendRegistry* r) {
    414   KitStatus st;
    415   KitLanguage lang;
    416   if (!r) return KIT_INVALID;
    417   st = registry_reserve(r, KIT_LANG_BUILTIN_COUNT);
    418   if (st != KIT_OK) return st;
    419   for (lang = 0; lang < KIT_LANG_BUILTIN_COUNT; ++lang)
    420     r->frontends[lang] = lang_registry_vtable(lang);
    421   if (r->nfrontends < KIT_LANG_BUILTIN_COUNT)
    422     r->nfrontends = KIT_LANG_BUILTIN_COUNT;
    423   return KIT_OK;
    424 }
    425 
    426 KitStatus kit_frontend_registry_add(KitFrontendRegistry* r,
    427                                     const KitFrontendVTable* vtable,
    428                                     KitLanguage* out_lang) {
    429   KitStatus st;
    430   KitLanguage lang;
    431   if (out_lang) *out_lang = KIT_LANG_UNKNOWN;
    432   if (!r || !vtable) return KIT_INVALID;
    433   st = validate_frontend_vtable(vtable);
    434   if (st != KIT_OK) return st;
    435   lang = r->nfrontends;
    436   st = registry_reserve(r, lang + 1u);
    437   if (st != KIT_OK) return st;
    438   r->frontends[lang] = vtable;
    439   r->nfrontends = lang + 1u;
    440   if (out_lang) *out_lang = lang;
    441   return KIT_OK;
    442 }
    443 
    444 KitLanguage kit_frontend_registry_language_for_path(
    445     const KitFrontendRegistry* r, const char* path) {
    446   KitLanguage lang = KIT_LANG_UNKNOWN;
    447   (void)language_path_kind_common(NULL, r, path, &lang);
    448   return lang;
    449 }
    450 
    451 KitLanguage kit_frontend_registry_language_for_name(
    452     const KitFrontendRegistry* r, const char* name) {
    453   uint32_t lang;
    454   if (!r || !name) return KIT_LANG_UNKNOWN;
    455   for (lang = 0; lang < r->nfrontends; ++lang) {
    456     const KitFrontendVTable* v = registry_frontend_for(r, lang);
    457     uint32_t n;
    458     if (!v || !v->names) continue;
    459     for (n = 0; n < v->nnames; ++n) {
    460       if (name_eq(name, v->names[n])) return (KitLanguage)lang;
    461     }
    462   }
    463   return KIT_LANG_UNKNOWN;
    464 }
    465 
    466 KitFrontendPathKind kit_frontend_registry_path_kind(
    467     const KitFrontendRegistry* r, const char* path, KitLanguage* out_lang) {
    468   return language_path_kind_common(NULL, r, path, out_lang);
    469 }
    470 
    471 KitStatus kit_compiler_install_frontend_registry(
    472     KitCompiler* c, const KitFrontendRegistry* r) {
    473   Compiler* cc = (Compiler*)c;
    474   KitStatus st;
    475   uint32_t i;
    476   if (!cc || !r) return KIT_INVALID;
    477   st = compiler_frontends_reserve(cc, r->nfrontends);
    478   if (st != KIT_OK) return st;
    479   for (i = 0; i < r->nfrontends; ++i) cc->frontends[i] = r->frontends[i];
    480   for (i = r->nfrontends; i < cc->nfrontends; ++i) cc->frontends[i] = NULL;
    481   cc->nfrontends = r->nfrontends;
    482   return KIT_OK;
    483 }
    484 
    485 uint32_t kit_compiler_arch_predefines(KitCompiler* c,
    486                                       const KitPredefinedMacro** out) {
    487   const ArchImpl* arch;
    488   if (out) *out = NULL;
    489   if (!c) return 0;
    490   arch = arch_for_compiler((Compiler*)c);
    491   if (!arch || !arch->predefined_macros || arch->npredefined_macros == 0)
    492     return 0;
    493   if (out) *out = arch->predefined_macros;
    494   return arch->npredefined_macros;
    495 }
    496 
    497 uint32_t kit_compiler_arch_float_predefines(KitCompiler* c,
    498                                             const KitPredefinedMacro** out) {
    499   const ArchImpl* arch;
    500   KitTargetSpec spec;
    501   if (out) *out = NULL;
    502   if (!c) return 0;
    503   arch = arch_for_compiler((Compiler*)c);
    504   spec = kit_compiler_target_spec(c);
    505   return arch_float_predefines(arch, &spec, out);
    506 }
    507 
    508 uint32_t kit_compiler_arch_feature_predefines(KitCompiler* c,
    509                                               const KitPredefinedMacro** out) {
    510   const ArchImpl* arch;
    511   const KitTarget* tgt;
    512   KitTargetSpec spec;
    513   if (out) *out = NULL;
    514   if (!c) return 0;
    515   arch = arch_for_compiler((Compiler*)c);
    516   tgt = ((Compiler*)c)->target_ref;
    517   spec = kit_compiler_target_spec(c);
    518   return arch_feature_predefines(arch, &spec,
    519                                  tgt ? tgt->feature_words : NULL,
    520                                  tgt ? tgt->nfeature_words : 0, out);
    521 }
    522 
    523 static void validate_bytes(Compiler* c, const KitSourceInput* in) {
    524   if (!in->name.s) panic_bad_options(c, "input name is NULL");
    525   if (!in->bytes.data && in->bytes.len != 0) {
    526     panic_bad_options(c, "input data is NULL but len > 0");
    527   }
    528 }
    529 
    530 static const KitFrontendVTable* frontend_for_language(Compiler* c,
    531                                                       KitLanguage lang) {
    532   if (!c || lang == KIT_LANG_UNKNOWN || lang == KIT_LANG_AUTO ||
    533       lang >= c->nfrontends)
    534     return NULL;
    535   return c->frontends[lang];
    536 }
    537 
    538 static KitStatus compile_obj_finalize(Compiler* c, ObjBuilder* ob);
    539 static KitStatus compile_frontend_state_obj_into(
    540     Compiler* c, const KitFrontendVTable* vtable, KitFrontendState* frontend,
    541     const KitFrontendCompileOptions* opts, const KitSourceInput* input,
    542     ObjBuilder* ob);
    543 
    544 static KitStatus kit_frontend_new(KitCompiler* c, KitLanguage lang,
    545                                   KitFrontend** out) {
    546   const KitFrontendVTable* vtable;
    547   KitFrontendState* state;
    548   KitFrontend* frontend;
    549   Heap* h;
    550 
    551   if (!out) return KIT_INVALID;
    552   *out = NULL;
    553   if (!c || lang == KIT_LANG_UNKNOWN || lang == KIT_LANG_AUTO)
    554     return KIT_INVALID;
    555   vtable = frontend_for_language((Compiler*)c, lang);
    556   if (!vtable) return KIT_UNSUPPORTED;
    557   state = vtable->new_frontend(c);
    558   if (!state) return KIT_NOMEM;
    559   h = (Heap*)c->ctx->heap;
    560   frontend =
    561       (KitFrontend*)h->alloc(h, sizeof(*frontend), _Alignof(KitFrontend));
    562   if (!frontend) {
    563     vtable->free_frontend(state);
    564     return KIT_NOMEM;
    565   }
    566   frontend->c = c;
    567   frontend->lang = lang;
    568   frontend->vtable = vtable;
    569   frontend->state = state;
    570   *out = frontend;
    571   return KIT_OK;
    572 }
    573 
    574 static void kit_frontend_commit(KitFrontend* frontend) {
    575   if (frontend && frontend->vtable && frontend->vtable->commit) {
    576     frontend->vtable->commit(frontend->state);
    577   }
    578 }
    579 
    580 static void kit_frontend_abort(KitFrontend* frontend) {
    581   if (frontend && frontend->vtable && frontend->vtable->abort) {
    582     frontend->vtable->abort(frontend->state);
    583   }
    584 }
    585 
    586 static KitStatus kit_frontend_compile_obj(KitFrontend* frontend,
    587                                           const KitFrontendCompileOptions* opts,
    588                                           const KitSourceInput* input,
    589                                           KitObjBuilder* out) {
    590   Compiler* c;
    591   PanicFrame panic;
    592   KitStatus st;
    593 
    594   if (!frontend || !frontend->c || !frontend->vtable || !frontend->state ||
    595       !opts || !input || !out) {
    596     return KIT_INVALID;
    597   }
    598   if (input->lang != frontend->lang) return KIT_INVALID;
    599   if (!frontend->vtable->compile_obj) return KIT_UNSUPPORTED;
    600   c = (Compiler*)frontend->c;
    601   compiler_panic_push(c, &panic);
    602   if (setjmp(panic.env)) {
    603     /* A genuine internal panic (CG/backend) longjmp'd here. Run cleanups, then
    604      * roll back any durable frontend state staged during this compile, and
    605      * propagate as a soft error. Ordinary diagnostic failures do NOT take this
    606      * path: the frontend returns KIT_ERR below without panicking. */
    607     compiler_run_cleanups(c);
    608     kit_frontend_abort(frontend);
    609     compiler_panic_pop(c, &panic);
    610     return KIT_ERR;
    611   }
    612   validate_bytes(c, input);
    613   metrics_scope_begin(c, "compile.tu");
    614   metrics_count(c, "compile.input_bytes", (u64)input->bytes.len);
    615   st = compile_frontend_state_obj_into(c, frontend->vtable, frontend->state,
    616                                        opts, input, (ObjBuilder*)out);
    617   metrics_scope_end(c, "compile.tu");
    618   /* On a soft diagnostic failure, roll back the staged transaction here so the
    619    * frontend is left exactly as it was before this compile. On success the
    620    * transaction is left open for the caller to commit or abort. */
    621   if (st != KIT_OK) kit_frontend_abort(frontend);
    622   compiler_panic_pop(c, &panic);
    623   return st;
    624 }
    625 
    626 static KitStatus kit_frontend_compile_cg(KitFrontend* frontend,
    627                                          const KitFrontendCompileOptions* opts,
    628                                          const KitSourceInput* input,
    629                                          KitCg* cg) {
    630   Compiler* c;
    631   PanicFrame panic;
    632   KitStatus st;
    633 
    634   if (!frontend || !frontend->c || !frontend->vtable || !frontend->state ||
    635       !opts || !input || !cg) {
    636     return KIT_INVALID;
    637   }
    638   if (input->lang != frontend->lang) return KIT_INVALID;
    639   if (frontend->vtable->caps.lto_mode != KIT_FRONTEND_LTO_CG ||
    640       !frontend->vtable->compile_cg) {
    641     return KIT_UNSUPPORTED;
    642   }
    643   c = (Compiler*)frontend->c;
    644   compiler_panic_push(c, &panic);
    645   if (setjmp(panic.env)) {
    646     compiler_run_cleanups(c);
    647     kit_frontend_abort(frontend);
    648     compiler_panic_pop(c, &panic);
    649     return KIT_ERR;
    650   }
    651   validate_bytes(c, input);
    652   metrics_scope_begin(c, "compile.tu");
    653   metrics_count(c, "compile.input_bytes", (u64)input->bytes.len);
    654   metrics_scope_begin(c, "compile.frontend");
    655   st = frontend->vtable->compile_cg(frontend->state, opts, input, cg);
    656   metrics_scope_end(c, "compile.frontend");
    657   metrics_scope_end(c, "compile.tu");
    658   if (st != KIT_OK) kit_frontend_abort(frontend);
    659   compiler_panic_pop(c, &panic);
    660   return st;
    661 }
    662 
    663 static void kit_frontend_free(KitFrontend* frontend) {
    664   Heap* h;
    665   if (!frontend) return;
    666   if (frontend->vtable && frontend->state) {
    667     frontend->vtable->free_frontend(frontend->state);
    668   }
    669   h = (Heap*)frontend->c->ctx->heap;
    670   h->free(h, frontend, sizeof(*frontend));
    671 }
    672 
    673 KitStatus kit_compile_session_new(KitCompiler* c,
    674                                   const KitCompileSessionOptions* opts,
    675                                   KitCompileSession** out) {
    676   KitCompileSession* s;
    677   KitFrontend* frontend = NULL;
    678   KitStatus st;
    679   Heap* h;
    680 
    681   if (!out) return KIT_INVALID;
    682   *out = NULL;
    683   if (!c || !opts || opts->lang == KIT_LANG_UNKNOWN ||
    684       opts->lang == KIT_LANG_AUTO)
    685     return KIT_INVALID;
    686   st = kit_frontend_new(c, opts->lang, &frontend);
    687   if (st != KIT_OK) return st;
    688   h = (Heap*)c->ctx->heap;
    689   s = (KitCompileSession*)h->alloc(h, sizeof(*s), _Alignof(KitCompileSession));
    690   if (!s) {
    691     kit_frontend_free(frontend);
    692     return KIT_NOMEM;
    693   }
    694   memset(s, 0, sizeof(*s));
    695   s->c = c;
    696   s->lang = opts->lang;
    697   s->frontend = frontend;
    698   s->opts = opts->compile;
    699   *out = s;
    700   return KIT_OK;
    701 }
    702 
    703 /* Shared object-producing compile path. Opaque frontends compile directly into
    704  * the object builder; semantic frontends use the same borrowed KitCg lifecycle
    705  * as LTO with a single source unit. On failure the frontend transaction is
    706  * rolled back and *out is NULL. On success, when commit_on_success is set (the
    707  * batch path), the transaction is committed before returning; otherwise it is
    708  * left open for the caller to resolve. */
    709 static KitStatus compile_session_run(KitCompileSession* s,
    710                                      const KitSourceInput* input,
    711                                      KitObjBuilder** out,
    712                                      int commit_on_success) {
    713   ObjBuilder* ob;
    714   KitFrontendCompileOptions opts;
    715   KitStatus st;
    716 
    717   if (!out) return KIT_INVALID;
    718   *out = NULL;
    719   if (!s || !s->c || !s->frontend || !input) return KIT_INVALID;
    720   if (input->lang != s->lang) return KIT_INVALID;
    721   ob = obj_new((Compiler*)s->c);
    722   if (!ob) return KIT_NOMEM;
    723   opts = s->opts;
    724   opts.input_kind = input->input_kind;
    725   opts.repl_entry_name = input->repl_entry_name;
    726   if (s->frontend->vtable->caps.lto_mode == KIT_FRONTEND_LTO_CG) {
    727     KitCg* cg = NULL;
    728     KitCgUnitOptions uopts;
    729     st = kit_cg_new(s->c, &cg);
    730     if (st == KIT_OK) st = kit_cg_begin(cg, (KitObjBuilder*)ob, &opts.code);
    731     memset(&uopts, 0, sizeof uopts);
    732     uopts.source_name = input->name;
    733     if (st == KIT_OK) st = kit_cg_begin_unit(cg, &uopts);
    734     if (st == KIT_OK)
    735       st = kit_frontend_compile_cg(s->frontend, &opts, input, cg);
    736     if (st == KIT_OK) st = kit_cg_end_unit(cg);
    737     if (st == KIT_OK) st = kit_cg_finish(cg, NULL);
    738     if (st == KIT_OK) st = kit_cg_detach(cg);
    739     kit_cg_free(cg);
    740     if (st == KIT_OK) st = compile_obj_finalize((Compiler*)s->c, ob);
    741   } else {
    742     st =
    743         kit_frontend_compile_obj(s->frontend, &opts, input, (KitObjBuilder*)ob);
    744   }
    745   if (st != KIT_OK) {
    746     kit_frontend_abort(s->frontend);
    747     obj_free(ob);
    748     return st;
    749   }
    750   if (commit_on_success) kit_frontend_commit(s->frontend);
    751   *out = (KitObjBuilder*)ob;
    752   return KIT_OK;
    753 }
    754 
    755 KitStatus kit_compile_session_compile(KitCompileSession* s,
    756                                       const KitSourceInput* input,
    757                                       KitObjBuilder** out) {
    758   return compile_session_run(s, input, out, /*commit_on_success=*/1);
    759 }
    760 
    761 KitStatus kit_compile_session_compile_cg(KitCompileSession* s,
    762                                          const KitSourceInput* input,
    763                                          KitCg* cg) {
    764   KitFrontendCompileOptions opts;
    765   KitStatus st;
    766   int unit_open = 0;
    767 
    768   if (!s || !s->c || !s->frontend || !input || !cg) return KIT_INVALID;
    769   if (input->lang != s->lang) return KIT_INVALID;
    770   opts = s->opts;
    771   opts.input_kind = input->input_kind;
    772   opts.repl_entry_name = input->repl_entry_name;
    773   {
    774     KitCgUnitOptions uopts;
    775     memset(&uopts, 0, sizeof uopts);
    776     uopts.source_name = input->name;
    777     st = kit_cg_begin_unit(cg, &uopts);
    778   }
    779   if (st == KIT_OK) unit_open = 1;
    780   if (st == KIT_OK) st = kit_frontend_compile_cg(s->frontend, &opts, input, cg);
    781   if (st == KIT_OK) st = kit_cg_end_unit(cg);
    782   if (st == KIT_OK) {
    783     unit_open = 0;
    784     kit_frontend_commit(s->frontend);
    785   } else if (unit_open) {
    786     (void)kit_cg_detach(cg);
    787   }
    788   return st;
    789 }
    790 
    791 KitStatus kit_compile_session_stage(KitCompileSession* s,
    792                                     const KitSourceInput* input,
    793                                     KitObjBuilder** out) {
    794   return compile_session_run(s, input, out, /*commit_on_success=*/0);
    795 }
    796 
    797 void kit_compile_session_commit(KitCompileSession* s) {
    798   if (s && s->frontend) kit_frontend_commit(s->frontend);
    799 }
    800 
    801 void kit_compile_session_abort(KitCompileSession* s) {
    802   if (s && s->frontend) kit_frontend_abort(s->frontend);
    803 }
    804 
    805 void kit_compile_session_free(KitCompileSession* s) {
    806   Heap* h;
    807   if (!s) return;
    808   h = (Heap*)s->c->ctx->heap;
    809   kit_frontend_free(s->frontend);
    810   h->free(h, s, sizeof(*s));
    811 }
    812 
    813 static KitStatus compile_obj_finalize(Compiler* c, ObjBuilder* ob) {
    814   metrics_scope_begin(c, "compile.obj_finalize");
    815   obj_finalize(ob);
    816   metrics_scope_end(c, "compile.obj_finalize");
    817   metrics_count(c, "compile.obj_sections", obj_section_count(ob));
    818   metrics_count(c, "compile.obj_relocs", obj_reloc_total(ob));
    819   return KIT_OK;
    820 }
    821 
    822 static KitStatus compile_frontend_state_obj_into(
    823     Compiler* c, const KitFrontendVTable* vtable, KitFrontendState* frontend,
    824     const KitFrontendCompileOptions* opts, const KitSourceInput* input,
    825     ObjBuilder* ob) {
    826   KitStatus st;
    827 
    828   metrics_scope_begin(c, "compile.frontend");
    829   st = vtable->compile_obj(frontend, opts, input, ob);
    830   metrics_scope_end(c, "compile.frontend");
    831   /* Ordinary diagnostic failure: fail softly with the status the frontend
    832    * already reported. No synthetic fatal, and do not finalize a half-built
    833    * object. Genuine internal failures panic from inside compile_obj and
    834    * never reach here. */
    835   if (st != KIT_OK) return st;
    836   return compile_obj_finalize(c, ob);
    837 }
    838 
    839 /* ============================================================
    840  * Asm
    841  * ============================================================ */
    842 
    843 static KitFrontendState* asm_frontend_new(KitCompiler* c) {
    844   Heap* h;
    845   AsmFrontend* fe;
    846   if (!c) return NULL;
    847   h = (Heap*)c->ctx->heap;
    848   fe = (AsmFrontend*)h->alloc(h, sizeof(*fe), _Alignof(AsmFrontend));
    849   if (!fe) return NULL;
    850   fe->c = c;
    851   return (KitFrontendState*)fe;
    852 }
    853 
    854 static KitStatus asm_frontend_compile(KitFrontendState* frontend,
    855                                       const KitFrontendCompileOptions* opts,
    856                                       const KitSourceInput* input,
    857                                       KitObjBuilder* out) {
    858   AsmFrontend* fe = (AsmFrontend*)frontend;
    859   Compiler* c;
    860   AsmLexer* lex;
    861   MCEmitter* mc;
    862   KitDiagSink* diag;
    863   u32 errors0;
    864   (void)opts;
    865   if (!fe || !fe->c || !input || !out) return KIT_INVALID;
    866   c = fe->c;
    867   diag = c->ctx ? c->ctx->diag : NULL;
    868   errors0 = diag ? diag->errors : 0;
    869   metrics_scope_begin(c, "compile.asm.lex_open");
    870   lex = asm_lex_open_mem(c, input->name.s, input->bytes.s, input->bytes.len);
    871   metrics_scope_end(c, "compile.asm.lex_open");
    872   metrics_scope_begin(c, "compile.asm.mc_new");
    873   mc = mc_new(c, (ObjBuilder*)out);
    874   metrics_scope_end(c, "compile.asm.mc_new");
    875   if (!lex || !mc) {
    876     /* Allocation failed before we could parse anything. Release whichever
    877      * half we did get and report out-of-memory rather than a silent KIT_OK. */
    878     mc_free(mc);
    879     asm_lex_close(lex);
    880     return KIT_NOMEM;
    881   }
    882   metrics_scope_begin(c, "compile.asm.parse");
    883   asm_parse(c, lex, mc);
    884   metrics_scope_end(c, "compile.asm.parse");
    885   metrics_scope_begin(c, "compile.asm.mc_free");
    886   mc_free(mc);
    887   asm_lex_close(lex);
    888   metrics_scope_end(c, "compile.asm.mc_free");
    889   /* asm_parse reports hard errors via panic (longjmp to the compile-obj
    890    * setjmp frame, which yields KIT_ERR), so reaching here means the parse
    891    * completed; but propagate any soft diagnostics the sink recorded instead
    892    * of unconditionally claiming success. */
    893   if (diag && diag->errors > errors0) return KIT_ERR;
    894   return KIT_OK;
    895 }
    896 
    897 static void asm_frontend_free(KitFrontendState* frontend) {
    898   AsmFrontend* fe = (AsmFrontend*)frontend;
    899   Heap* h;
    900   if (!fe) return;
    901   h = fe->c->ctx->heap;
    902   h->free(h, fe, sizeof(*fe));
    903 }
    904 
    905 struct KitDepIter {
    906   Compiler* c;
    907   SourceDepIter* inner;
    908 };
    909 
    910 KitStatus kit_dep_iter_new(KitCompiler* c, KitDepIter** out) {
    911   Heap* h;
    912   KitDepIter* it;
    913   if (!out) return KIT_INVALID;
    914   if (!c || !c->sources) return KIT_INVALID;
    915   h = c->ctx->heap;
    916   it = (KitDepIter*)h->alloc(h, sizeof(*it), _Alignof(KitDepIter));
    917   if (!it) return KIT_NOMEM;
    918   it->c = c;
    919   it->inner = source_depiter_new(c->sources);
    920   if (!it->inner) {
    921     h->free(h, it, sizeof(*it));
    922     return KIT_NOMEM;
    923   }
    924   *out = it;
    925   return KIT_OK;
    926 }
    927 
    928 KitIterResult kit_dep_iter_next(KitDepIter* it, KitDepEdge* out) {
    929   const SourceInclude* edge;
    930   const SourceFile* includer;
    931   const SourceFile* included;
    932   if (!it || !out) return KIT_ITER_ERROR;
    933   edge = source_depiter_next(it->inner);
    934   if (!edge) return KIT_ITER_END;
    935   includer = source_file(it->c->sources, edge->includer_file_id);
    936   included = source_file(it->c->sources, edge->included_file_id);
    937   out->includer_name =
    938       includer ? pool_slice(it->c->global, includer->name) : KIT_SLICE_NULL;
    939   out->included_name =
    940       included ? pool_slice(it->c->global, included->name) : KIT_SLICE_NULL;
    941   out->include_loc = edge->include_loc;
    942   /* `bracketed` is the spelling form (<...> vs "..."); `from_system_path` is
    943    * the resolved-dir system flag (whether an -isystem dir satisfied the
    944    * header), threaded from find_and_open_include through
    945    * SourceInclude.resolved_system. They differ when a <...> include is resolved
    946    * via a plain -I dir. */
    947   out->bracketed = (uint8_t)(edge->system ? 1 : 0);
    948   out->from_system_path = (uint8_t)(edge->resolved_system ? 1 : 0);
    949   out->pad[0] = 0;
    950   out->pad[1] = 0;
    951   return KIT_ITER_ITEM;
    952 }
    953 
    954 void kit_dep_iter_free(KitDepIter* it) {
    955   Heap* h;
    956   if (!it) return;
    957   h = it->c->ctx->heap;
    958   if (it->inner) source_depiter_free(it->inner);
    959   h->free(h, it, sizeof(*it));
    960 }