kit

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

c.c (9519B)


      1 #include "c.h"
      2 
      3 #include "decl/decl.h"
      4 #include "lex/lex.h"
      5 #include "parse/parse.h"
      6 #include "pp/pp.h"
      7 
      8 #define C_PROFILE_SCOPE_SETUP \
      9   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 0u))
     10 #define C_PROFILE_SCOPE_POOL_NEW \
     11   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 1u))
     12 #define C_PROFILE_SCOPE_LEX_OPEN \
     13   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 2u))
     14 #define C_PROFILE_SCOPE_PP_NEW \
     15   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 3u))
     16 #define C_PROFILE_SCOPE_DECL_NEW \
     17   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 4u))
     18 #define C_PROFILE_SCOPE_PP_OPTIONS \
     19   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 5u))
     20 #define C_PROFILE_SCOPE_PP_PUSH_INPUT \
     21   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 6u))
     22 #define C_PROFILE_SCOPE_PARSE_CODEGEN \
     23   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 7u))
     24 #define C_PROFILE_SCOPE_CLEANUP \
     25   ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 8u))
     26 
     27 #define C_PROFILE_COUNTER_PP_INCLUDE_DIRS \
     28   ((KitProfileCounter)(KIT_PROFILE_COUNTER_LANG_FIRST + 0u))
     29 #define C_PROFILE_COUNTER_PP_SYSTEM_INCLUDE_DIRS \
     30   ((KitProfileCounter)(KIT_PROFILE_COUNTER_LANG_FIRST + 1u))
     31 #define C_PROFILE_COUNTER_PP_DEFINES \
     32   ((KitProfileCounter)(KIT_PROFILE_COUNTER_LANG_FIRST + 2u))
     33 #define C_PROFILE_COUNTER_PP_UNDEFINES \
     34   ((KitProfileCounter)(KIT_PROFILE_COUNTER_LANG_FIRST + 3u))
     35 
     36 static void c_profile_define(KitCompiler* c) {
     37   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_SETUP,
     38                                     "compile.c.setup");
     39   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_POOL_NEW,
     40                                     "compile.c.pool_new");
     41   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_LEX_OPEN,
     42                                     "compile.c.lex_open");
     43   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_PP_NEW,
     44                                     "compile.c.pp_new");
     45   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_DECL_NEW,
     46                                     "compile.c.decl_new");
     47   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_PP_OPTIONS,
     48                                     "compile.c.pp_options");
     49   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_PP_PUSH_INPUT,
     50                                     "compile.c.pp_push_input");
     51   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_PARSE_CODEGEN,
     52                                     "compile.c.parse_codegen");
     53   kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_CLEANUP,
     54                                     "compile.c.cleanup");
     55   kit_frontend_profile_define_counter(c, C_PROFILE_COUNTER_PP_INCLUDE_DIRS,
     56                                       "compile.c.pp_include_dirs");
     57   kit_frontend_profile_define_counter(c,
     58                                       C_PROFILE_COUNTER_PP_SYSTEM_INCLUDE_DIRS,
     59                                       "compile.c.pp_system_include_dirs");
     60   kit_frontend_profile_define_counter(c, C_PROFILE_COUNTER_PP_DEFINES,
     61                                       "compile.c.pp_defines");
     62   kit_frontend_profile_define_counter(c, C_PROFILE_COUNTER_PP_UNDEFINES,
     63                                       "compile.c.pp_undefines");
     64 }
     65 
     66 static SrcLoc c_no_loc(void) {
     67   SrcLoc loc;
     68   loc.file_id = 0;
     69   loc.line = 0;
     70   loc.col = 0;
     71   return loc;
     72 }
     73 
     74 static _Noreturn void c_bad_options(Compiler* c, const char* msg) {
     75   compiler_panic(c, c_no_loc(), "bad C frontend options: %.*s",
     76                  KIT_SLICE_ARG(kit_slice_cstr(msg)));
     77 }
     78 
     79 static void c_apply_pp_options(Pp* pp, const KitPreprocessOptions* opts) {
     80   u32 i;
     81 
     82   for (i = 0; i < opts->ninclude_dirs; ++i) {
     83     pp_add_include_dir(pp, opts->include_dirs[i], 0);
     84   }
     85   for (i = 0; i < opts->nsystem_include_dirs; ++i) {
     86     pp_add_include_dir(pp, opts->system_include_dirs[i], 1);
     87   }
     88   for (i = 0; i < opts->ndefines; ++i) {
     89     const char* body =
     90         opts->defines[i].body.len ? opts->defines[i].body.s : "1";
     91     pp_define(pp, opts->defines[i].name.s, body);
     92   }
     93   for (i = 0; i < opts->nundefines; ++i) {
     94     pp_undef(pp, opts->undefines[i].s);
     95   }
     96 }
     97 
     98 typedef struct CFrontend {
     99   KitCompiler* c;
    100 } CFrontend;
    101 
    102 static KitFrontendState* c_frontend_new(KitCompiler* c) {
    103   KitHeap* h;
    104   CFrontend* fe;
    105   if (!c) return NULL;
    106   h = kit_compiler_context(c)->heap;
    107   fe = (CFrontend*)h->alloc(h, sizeof(*fe), _Alignof(CFrontend));
    108   if (!fe) return NULL;
    109   fe->c = c;
    110   return (KitFrontendState*)fe;
    111 }
    112 
    113 static KitStatus c_frontend_compile_cg(KitFrontendState* frontend,
    114                                        const KitFrontendCompileOptions* fe_opts,
    115                                        const KitSourceInput* input, KitCg* cg) {
    116   CFrontend* fe = (CFrontend*)frontend;
    117   KitCompiler* c;
    118   /* Code, diagnostics, and preprocessor settings all arrive on the common
    119    * KitFrontendCompileOptions; the C frontend uses no language_options. */
    120   const KitSlice* bytes;
    121   Pool* pool;
    122   Pp* pp;
    123   DeclTable* decls;
    124   SourceSpec spec;
    125 
    126   if (!fe || !fe->c) return KIT_INVALID;
    127   c = fe->c;
    128   if (!fe_opts || !input || !cg) c_bad_options(c, "compile args missing");
    129   bytes = &input->bytes;
    130   c_profile_define(c);
    131 
    132   kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_SETUP);
    133   kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_POOL_NEW);
    134   pool = c_pool_new(c);
    135   kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_POOL_NEW);
    136   if (!pool) compiler_panic(c, c_no_loc(), "C compiler out of memory");
    137   kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_PP_NEW);
    138   pp = pp_new(c);
    139   kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_PP_NEW);
    140   if (!pp || !cg) compiler_panic(c, c_no_loc(), "C compiler out of memory");
    141   kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_DECL_NEW);
    142   decls = decl_new(c, pool, cg);
    143   kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_DECL_NEW);
    144   kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_SETUP);
    145 
    146   kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_PP_OPTIONS);
    147   kit_frontend_profile_count(c, C_PROFILE_COUNTER_PP_INCLUDE_DIRS,
    148                              fe_opts->preprocess.ninclude_dirs);
    149   kit_frontend_profile_count(c, C_PROFILE_COUNTER_PP_SYSTEM_INCLUDE_DIRS,
    150                              fe_opts->preprocess.nsystem_include_dirs);
    151   kit_frontend_profile_count(c, C_PROFILE_COUNTER_PP_DEFINES,
    152                              fe_opts->preprocess.ndefines);
    153   kit_frontend_profile_count(c, C_PROFILE_COUNTER_PP_UNDEFINES,
    154                              fe_opts->preprocess.nundefines);
    155   c_apply_pp_options(pp, &fe_opts->preprocess);
    156   kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_PP_OPTIONS);
    157   /* SRC_PARSER_FEED: the C parser drops preprocessor newlines, so non-directive
    158    * newline tokens are suppressed at every lexer (primary + #includes) — ~51%
    159    * of lexer outputs. Directive-terminating newlines are still emitted, so the
    160    * PP's directive handling is unaffected. SRC_PRIMARY enables shebang skip. */
    161   kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_PP_PUSH_INPUT);
    162   memset(&spec, 0, sizeof(spec));
    163   spec.name = kit_slice_cstr(input->name.s);
    164   spec.bytes = bytes->s;
    165   spec.len = (u32)bytes->len;
    166   spec.flags = SRC_PRIMARY | SRC_PARSER_FEED;
    167   pp_push_source(pp, &spec);
    168   kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_PP_PUSH_INPUT);
    169 
    170   /* Perf instrumentation: drain the preprocessed token stream to EOF without
    171    * parsing or codegen, to isolate lex+pp instructions (the parser-feed stream
    172    * matches -c exactly — newlines suppressed, no text serialization). */
    173   if (kit_debug_getenv("KIT_PP_DRAIN")) {
    174     Tok t;
    175     do {
    176       pp_next_parse(pp, &t);
    177     } while (t.kind != TOK_EOF);
    178     decl_free(decls);
    179     pp_free(pp);
    180     c_pool_free(pool);
    181     return KIT_OK;
    182   }
    183 
    184   kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_PARSE_CODEGEN);
    185   parse_c(c, pool, pp, decls, cg, (KitSymVis)fe_opts->code.default_visibility,
    186           (int)fe_opts->code.trivial_auto_var_init,
    187           (int)fe_opts->code.stack_protector,
    188           fe_opts->code.disabled_backend_features);
    189   kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_PARSE_CODEGEN);
    190 
    191   kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_CLEANUP);
    192   decl_free(decls);
    193   pp_free(pp);
    194   c_pool_free(pool);
    195   kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_CLEANUP);
    196   return KIT_OK;
    197 }
    198 
    199 static void c_frontend_free(KitFrontendState* frontend) {
    200   CFrontend* fe = (CFrontend*)frontend;
    201   KitHeap* h;
    202   if (!fe) return;
    203   h = kit_compiler_context(fe->c)->heap;
    204   h->free(h, fe, sizeof(*fe));
    205 }
    206 
    207 /* C is just another frontend: it claims its source/header extensions so the
    208  * language-for-path lookup resolves them by the same registry walk as every
    209  * other language, with no special fallback. */
    210 static const KitSlice c_extensions[] = {KIT_SLICE_LIT("c"), KIT_SLICE_LIT("h")};
    211 static const uint8_t c_extension_kinds[] = {KIT_FRONTEND_PATH_SOURCE,
    212                                             KIT_FRONTEND_PATH_HEADER};
    213 /* Canonical `-x` name; mirrors the driver's "c" spelling. */
    214 static const KitSlice c_names[] = {KIT_SLICE_LIT("c")};
    215 
    216 const KitFrontendVTable kit_c_frontend_vtable = {
    217     .new_frontend = c_frontend_new,
    218     .compile_cg = c_frontend_compile_cg,
    219     .compile_obj = NULL,
    220     .free_frontend = c_frontend_free,
    221     .extensions = c_extensions,
    222     .nextensions = (uint32_t)(sizeof c_extensions / sizeof c_extensions[0]),
    223     .extension_kinds = c_extension_kinds,
    224     .names = c_names,
    225     .nnames = (uint32_t)(sizeof c_names / sizeof c_names[0]),
    226     .commit = NULL,
    227     .abort = NULL,
    228     .caps = {true, KIT_FRONTEND_LTO_CG, false},
    229     .parse_options = NULL,
    230     .free_options = NULL,
    231 };