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 };