kit

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

build.c (14228B)


      1 /* Build orchestration API entries.
      2  *
      3  * The batch-compile and ordered-link tier over the public compile/link/cg
      4  * surface: kit_build_compile_one/kit_build_compile drive the per-source and
      5  * batched compile paths, and kit_build_link/kit_build_link_with_lto build a
      6  * link session, add inputs in command-line order, and emit. Every entry is
      7  * written purely against public kit_* calls. */
      8 
      9 #include <kit/build.h>
     10 
     11 #include <kit/asm_emit.h>
     12 #include <kit/cg.h>
     13 #include <string.h>
     14 
     15 static KitStatus build_compile_cg_run(KitCompiler* compiler,
     16                                       const KitCodeOptions* code,
     17                                       const KitDiagnosticOptions* diagnostics,
     18                                       const KitBuildSource* src, KitCg* cg) {
     19   KitCompileSessionOptions sopts;
     20   KitCompileSession* session = NULL;
     21   KitSourceInput sin;
     22   KitStatus st;
     23 
     24   if (!compiler || !code || !diagnostics || !src || !cg) return KIT_INVALID;
     25   memset(&sopts, 0, sizeof(sopts));
     26   sopts.lang = src->lang;
     27   sopts.compile.code = *code;
     28   sopts.compile.diagnostics = *diagnostics;
     29   if (src->pp) sopts.compile.preprocess = *src->pp;
     30   sopts.compile.language_options = src->lang_extra;
     31 
     32   memset(&sin, 0, sizeof(sin));
     33   sin.name = src->name;
     34   sin.bytes = src->bytes;
     35   sin.lang = src->lang;
     36 
     37   st = kit_compile_session_new(compiler, &sopts, &session);
     38   if (st == KIT_OK) st = kit_compile_session_compile_cg(session, &sin, cg);
     39   kit_compile_session_free(session);
     40   return st;
     41 }
     42 
     43 KitStatus kit_build_compile_one(KitCompiler* compiler, KitLanguage lang,
     44                                 const KitCodeOptions* code,
     45                                 const KitDiagnosticOptions* diagnostics,
     46                                 const KitPreprocessOptions* pp,
     47                                 const void* lang_extra, KitSlice name,
     48                                 const KitSlice* bytes, KitWriter* emit_out,
     49                                 KitObjBuilder** obj_out) {
     50   KitCompileSessionOptions sopts;
     51   KitCompileSession* session = NULL;
     52   KitSourceInput sin;
     53   KitObjBuilder* ob = NULL;
     54   KitCodeOptions code_copy = *code;
     55   KitStatus st;
     56 
     57   if (obj_out) *obj_out = NULL;
     58 
     59   /* For the in-CG emit modes the output writer is consumed during codegen, so
     60    * wire it onto the code options before the session runs. */
     61   if (emit_out && code_copy.emit_c_source) code_copy.c_source_writer = emit_out;
     62   if (emit_out && code_copy.emit_ir) code_copy.ir_dump_writer = emit_out;
     63 
     64   memset(&sopts, 0, sizeof(sopts));
     65   sopts.lang = lang;
     66   sopts.compile.code = code_copy;
     67   sopts.compile.diagnostics = *diagnostics;
     68   if (pp) sopts.compile.preprocess = *pp;
     69   sopts.compile.language_options = lang_extra;
     70 
     71   memset(&sin, 0, sizeof(sin));
     72   sin.name = name;
     73   sin.bytes = *bytes;
     74   sin.lang = lang;
     75 
     76   st = kit_compile_session_new(compiler, &sopts, &session);
     77   if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &ob);
     78   kit_compile_session_free(session);
     79   if (st != KIT_OK) return st;
     80 
     81   if (obj_out) {
     82     *obj_out = ob;
     83     return KIT_OK;
     84   }
     85 
     86   /* emit_out path: serialize by output mode. The in-CG modes already wrote
     87    * through the wired writer above. */
     88   if (code_copy.emit_c_source || code_copy.emit_ir) {
     89     /* nothing to serialize here */
     90   } else if (code_copy.emit_asm_source) {
     91     st = kit_obj_builder_emit_asm(ob, emit_out);
     92   } else {
     93     st = kit_obj_builder_emit(ob, emit_out);
     94   }
     95   kit_obj_builder_free(ob);
     96   return st;
     97 }
     98 
     99 static int build_compile_lto_enabled(const KitCodeOptions* code) {
    100   return code && code->lto && !code->check_only && !code->emit_c_source &&
    101          !code->emit_ir && !code->emit_asm_source;
    102 }
    103 
    104 static KitStatus build_start_lto(KitCompiler* compiler,
    105                                  const KitCodeOptions* code,
    106                                  KitObjBuilder** ob_out, KitCg** cg_out) {
    107   KitObjBuilder* ob = NULL;
    108   KitCg* cg = NULL;
    109   KitStatus st;
    110 
    111   if (ob_out) *ob_out = NULL;
    112   if (cg_out) *cg_out = NULL;
    113   if (!compiler || !code || !ob_out || !cg_out) return KIT_INVALID;
    114   st = kit_obj_builder_new(compiler, &ob);
    115   if (st == KIT_OK) st = kit_cg_new(compiler, &cg);
    116   if (st == KIT_OK) st = kit_cg_begin(cg, ob, code);
    117   if (st != KIT_OK) {
    118     kit_cg_free(cg);
    119     kit_obj_builder_free(ob);
    120     return st;
    121   }
    122   *ob_out = ob;
    123   *cg_out = cg;
    124   return KIT_OK;
    125 }
    126 
    127 KitStatus kit_build_lto_finish(KitBuildPendingLto* pending,
    128                                const KitBuildBatchOptions* batch,
    129                                const KitCgSym* preserved_symbols,
    130                                uint32_t npreserved_symbols) {
    131   KitCgFinishOptions finish;
    132   KitStatus st;
    133 
    134   if (!pending || !pending->active) return KIT_OK;
    135   if (!pending->obj || !pending->cg) {
    136     kit_build_lto_abort(pending);
    137     return KIT_INVALID;
    138   }
    139 
    140   memset(&finish, 0, sizeof finish);
    141   finish.output_kind = batch ? batch->output_kind : KIT_CG_OUTPUT_RELOCATABLE;
    142   finish.interposition_policy =
    143       batch ? batch->interposition_policy : KIT_CG_INTERPOSITION_DEFAULT;
    144   finish.preserved_symbols = preserved_symbols;
    145   finish.npreserved_symbols = npreserved_symbols;
    146 
    147   st = kit_cg_finish(pending->cg, &finish);
    148   if (st == KIT_OK) st = kit_cg_detach(pending->cg);
    149   if (st == KIT_OK) st = kit_obj_builder_finalize(pending->obj);
    150 
    151   kit_cg_free(pending->cg);
    152   pending->cg = NULL;
    153   pending->active = 0;
    154   return st;
    155 }
    156 
    157 void kit_build_lto_abort(KitBuildPendingLto* pending) {
    158   if (!pending || !pending->active) return;
    159   kit_cg_free(pending->cg);
    160   pending->cg = NULL;
    161   pending->active = 0;
    162 }
    163 
    164 KitStatus kit_build_compile(KitCompiler* compiler, const KitCodeOptions* code,
    165                             const KitDiagnosticOptions* diagnostics,
    166                             const KitBuildSource* sources, uint32_t nsources,
    167                             const KitBuildBatchOptions* batch,
    168                             KitBuildObjects* out) {
    169   KitBuildPendingLto pending_lto;
    170   int lto_order_emitted = 0;
    171   int lto_enabled = build_compile_lto_enabled(code);
    172   KitStatus st = KIT_OK;
    173 
    174   if (!compiler || !code || !diagnostics || (!sources && nsources) || !out ||
    175       !out->objs || !out->source_obj_index || !out->source_order_keep) {
    176     return KIT_INVALID;
    177   }
    178   memset(&pending_lto, 0, sizeof pending_lto);
    179   out->nobjs = 0;
    180   if (out->pending_lto) memset(out->pending_lto, 0, sizeof(*out->pending_lto));
    181   for (uint32_t i = 0; i < nsources; ++i) {
    182     out->source_obj_index[i] = (uint32_t)-1;
    183     out->source_order_keep[i] = 0;
    184   }
    185 
    186   for (uint32_t i = 0; i < nsources; ++i) {
    187     const KitBuildSource* src = &sources[i];
    188     KitFrontendCaps caps;
    189     int stage_cg = 0;
    190 
    191     memset(&caps, 0, sizeof caps);
    192     if (lto_enabled) {
    193       st = kit_frontend_caps(compiler, src->lang, &caps);
    194       if (st != KIT_OK) goto out;
    195       stage_cg = caps.lto_mode == KIT_FRONTEND_LTO_CG;
    196     }
    197 
    198     if (stage_cg) {
    199       if (!pending_lto.active) {
    200         st = build_start_lto(compiler, code, &pending_lto.obj, &pending_lto.cg);
    201         if (st != KIT_OK) goto out;
    202         pending_lto.obj_index = out->nobjs;
    203         pending_lto.active = 1;
    204         out->objs[out->nobjs++] = pending_lto.obj;
    205       }
    206       out->source_obj_index[i] = pending_lto.obj_index;
    207       if (!lto_order_emitted) {
    208         out->source_order_keep[i] = 1;
    209         lto_order_emitted = 1;
    210       }
    211       st = build_compile_cg_run(compiler, code, diagnostics, src,
    212                                 pending_lto.cg);
    213       if (st != KIT_OK) goto out;
    214       continue;
    215     }
    216 
    217     {
    218       KitObjBuilder* ob = NULL;
    219       st = kit_build_compile_one(compiler, src->lang, code, diagnostics,
    220                                  src->pp, src->lang_extra, src->name,
    221                                  &src->bytes, NULL, &ob);
    222       if (st != KIT_OK) goto out;
    223       out->source_obj_index[i] = out->nobjs;
    224       out->source_order_keep[i] = 1;
    225       out->objs[out->nobjs++] = ob;
    226     }
    227   }
    228 
    229   if (pending_lto.active) {
    230     if (batch && batch->defer_lto_finish) {
    231       if (!out->pending_lto) {
    232         st = KIT_INVALID;
    233         goto out;
    234       }
    235       *out->pending_lto = pending_lto;
    236       memset(&pending_lto, 0, sizeof pending_lto);
    237     } else {
    238       st = kit_build_lto_finish(&pending_lto, batch, NULL, 0);
    239       if (st != KIT_OK) goto out;
    240     }
    241   }
    242 
    243 out:
    244   if (pending_lto.active) kit_build_lto_abort(&pending_lto);
    245   return st;
    246 }
    247 
    248 KitStatus kit_build_emit_c(KitCompiler* compiler, const KitCodeOptions* code,
    249                            const KitDiagnosticOptions* diagnostics,
    250                            const KitBuildSource* sources, uint32_t nsources,
    251                            const KitBuildBatchOptions* batch, KitWriter* out) {
    252   KitCodeOptions emit_code;
    253   KitObjBuilder* ob = NULL;
    254   KitCg* cg = NULL;
    255   KitCgFinishOptions finish;
    256   KitStatus st = KIT_OK;
    257 
    258   if (!compiler || !code || !diagnostics || !sources || nsources == 0 ||
    259       !out || (batch && batch->defer_lto_finish))
    260     return KIT_INVALID;
    261 
    262   emit_code = *code;
    263   emit_code.check_only = false;
    264   emit_code.emit_asm_source = false;
    265   emit_code.emit_c_source = true;
    266   emit_code.emit_ir = false;
    267   emit_code.c_source_writer = out;
    268   emit_code.ir_dump_writer = NULL;
    269 
    270   for (uint32_t i = 0; i < nsources; ++i) {
    271     KitFrontendCaps caps;
    272     memset(&caps, 0, sizeof caps);
    273     st = kit_frontend_caps(compiler, sources[i].lang, &caps);
    274     if (st != KIT_OK) return st;
    275     if (caps.lto_mode != KIT_FRONTEND_LTO_CG) return KIT_UNSUPPORTED;
    276   }
    277 
    278   st = kit_obj_builder_new(compiler, &ob);
    279   if (st == KIT_OK) st = kit_cg_new(compiler, &cg);
    280   if (st == KIT_OK) st = kit_cg_begin(cg, ob, &emit_code);
    281 
    282   for (uint32_t i = 0; st == KIT_OK && i < nsources; ++i)
    283     st = build_compile_cg_run(compiler, &emit_code, diagnostics, &sources[i],
    284                               cg);
    285 
    286   if (st == KIT_OK) {
    287     memset(&finish, 0, sizeof finish);
    288     finish.output_kind =
    289         batch ? batch->output_kind : KIT_CG_OUTPUT_RELOCATABLE;
    290     finish.interposition_policy =
    291         batch ? batch->interposition_policy : KIT_CG_INTERPOSITION_DEFAULT;
    292     st = kit_cg_finish(cg, &finish);
    293   }
    294 
    295   kit_cg_free(cg);
    296   kit_obj_builder_free(ob);
    297   return st;
    298 }
    299 
    300 typedef struct BuildPreservedVec {
    301   KitHeap* heap;
    302   KitCgSym* syms;
    303   uint32_t nsyms;
    304   uint32_t cap;
    305   int oom;
    306 } BuildPreservedVec;
    307 
    308 static void build_preserved_vec_add(void* user, KitCgSym sym) {
    309   BuildPreservedVec* v = (BuildPreservedVec*)user;
    310   KitCgSym* ns;
    311   uint32_t ncap;
    312   if (!v || v->oom) return;
    313   if (v->nsyms == v->cap) {
    314     ncap = v->cap ? v->cap * 2u : 32u;
    315     ns = (KitCgSym*)v->heap->realloc(
    316         v->heap, v->syms, sizeof(*v->syms) * v->cap, sizeof(*v->syms) * ncap,
    317         _Alignof(KitCgSym));
    318     if (!ns) {
    319       v->oom = 1;
    320       return;
    321     }
    322     v->syms = ns;
    323     v->cap = ncap;
    324   }
    325   v->syms[v->nsyms++] = sym;
    326 }
    327 
    328 static KitStatus build_link_add_inputs(KitLinkSession* link,
    329                                        const KitLinkInputs* in) {
    330   KitStatus st = KIT_OK;
    331   uint32_t i;
    332   if (!link || !in) return KIT_INVALID;
    333 
    334   for (i = 0; i < in->norder && st == KIT_OK; ++i) {
    335     const KitLinkInputOrder* ord = &in->order[i];
    336     switch ((KitLinkInputOrderKind)ord->kind) {
    337       case KIT_LINK_INPUT_OBJ:
    338         st = kit_link_session_add_obj(link, in->objs[ord->index]);
    339         break;
    340       case KIT_LINK_INPUT_OBJ_BYTES:
    341         st = kit_link_session_add_obj_bytes(link, in->obj_names[ord->index],
    342                                             &in->obj_bytes[ord->index]);
    343         break;
    344       case KIT_LINK_INPUT_ARCHIVE:
    345         st =
    346             kit_link_session_add_archive_bytes(link, &in->archives[ord->index]);
    347         break;
    348       case KIT_LINK_INPUT_DSO:
    349         st = kit_link_session_add_dso_bytes(link, in->dso_names[ord->index],
    350                                             &in->dso_bytes[ord->index]);
    351         break;
    352     }
    353   }
    354   return st;
    355 }
    356 
    357 KitStatus kit_build_link_with_lto_report(
    358     KitCompiler* compiler, const KitLinkSessionOptions* lopts,
    359     const KitLinkInputs* in, KitBuildPendingLto* pending_lto,
    360     const KitBuildBatchOptions* batch, KitWriter* out,
    361     KitStatus (*on_linked)(void* user, KitLinkSession* link), void* user) {
    362   KitLinkSession* link = NULL;
    363   BuildPreservedVec preserved;
    364   KitStatus st;
    365 
    366   if (!compiler || !lopts || !in || !out) {
    367     if (pending_lto && pending_lto->active) kit_build_lto_abort(pending_lto);
    368     return KIT_INVALID;
    369   }
    370   memset(&preserved, 0, sizeof preserved);
    371   preserved.heap = kit_compiler_context(compiler)->heap;
    372   st = kit_link_session_new(compiler, lopts, &link);
    373   if (st == KIT_OK) st = build_link_add_inputs(link, in);
    374   if (st == KIT_OK && pending_lto && pending_lto->active) {
    375     st = kit_link_session_visit_lto_preserved(
    376         link, pending_lto->obj, pending_lto->cg, build_preserved_vec_add,
    377         &preserved);
    378     if (st == KIT_OK && preserved.oom) st = KIT_NOMEM;
    379     if (st == KIT_OK) {
    380       st = kit_build_lto_finish(pending_lto, batch, preserved.syms,
    381                                 preserved.nsyms);
    382     }
    383   }
    384   if (st == KIT_OK) st = kit_link_session_emit(link, out);
    385   /* Side reports (cref/memory-usage/map/symbols) need the resolved session, so
    386    * write them here while `link` is still live. */
    387   if (st == KIT_OK && on_linked) st = on_linked(user, link);
    388   kit_link_session_free(link);
    389   if (preserved.syms)
    390     preserved.heap->free(preserved.heap, preserved.syms,
    391                          sizeof(*preserved.syms) * preserved.cap);
    392   if (st != KIT_OK && pending_lto && pending_lto->active)
    393     kit_build_lto_abort(pending_lto);
    394   return st;
    395 }
    396 
    397 KitStatus kit_build_link_with_lto(KitCompiler* compiler,
    398                                   const KitLinkSessionOptions* lopts,
    399                                   const KitLinkInputs* in,
    400                                   KitBuildPendingLto* pending_lto,
    401                                   const KitBuildBatchOptions* batch,
    402                                   KitWriter* out) {
    403   return kit_build_link_with_lto_report(compiler, lopts, in, pending_lto, batch,
    404                                         out, NULL, NULL);
    405 }
    406 
    407 KitStatus kit_build_link(KitCompiler* compiler,
    408                          const KitLinkSessionOptions* lopts,
    409                          const KitLinkInputs* in, KitWriter* out) {
    410   return kit_build_link_with_lto(compiler, lopts, in, NULL, NULL, out);
    411 }