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 }