kit

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

core.c (12007B)


      1 /* Public core API bridge. */
      2 
      3 #include "core/core.h"
      4 #include "api/lang_registry.h"
      5 
      6 #include <kit/core.h>
      7 #include <string.h>
      8 
      9 #include "arch/arch.h"
     10 #include "core/diag.h"
     11 #include "core/heap.h"
     12 #include "core/pool.h"
     13 #include "core/slice.h"
     14 
     15 static void bitset_set(u64* words, u32 nwords, u32 idx, int enabled) {
     16   u32 w = idx / 64u;
     17   u64 bit = 1ull << (idx % 64u);
     18   if (!words || w >= nwords) return;
     19   if (enabled)
     20     words[w] |= bit;
     21   else
     22     words[w] &= ~bit;
     23 }
     24 
     25 static int bitset_get(const u64* words, u32 nwords, u32 idx) {
     26   u32 w = idx / 64u;
     27   if (!words || w >= nwords) return 0;
     28   return (words[w] & (1ull << (idx % 64u))) != 0;
     29 }
     30 
     31 KitStatus kit_target_new(const KitContext* ctx, const KitTargetOptions* opts,
     32                          KitTarget** out) {
     33   const ArchImpl* arch;
     34   KitTarget* t;
     35   Heap* h;
     36   u32 nwords;
     37   u32 i;
     38 
     39   if (!out) return KIT_INVALID;
     40   *out = NULL;
     41   if (!ctx || !ctx->heap || !opts) return KIT_INVALID;
     42   arch = arch_lookup(opts->spec.arch);
     43   if (!arch) {
     44     kit_ctx_diagf(ctx, "unsupported target architecture: %u",
     45                   (unsigned)opts->spec.arch);
     46     return KIT_UNSUPPORTED;
     47   }
     48   if (opts->spec.arch == KIT_ARCH_WASM && opts->spec.ptr_size != 4u) {
     49     kit_ctx_diagf(ctx,
     50                   "wasm64 is not supported in v1; use a wasm32 target");
     51     return KIT_UNSUPPORTED;
     52   }
     53 
     54   h = ctx->heap;
     55   t = (KitTarget*)h->alloc(h, sizeof(*t), _Alignof(KitTarget));
     56   if (!t) return KIT_NOMEM;
     57   memset(t, 0, sizeof(*t));
     58   t->ctx = ctx;
     59   t->spec = opts->spec;
     60 
     61   /* Resolve the data-model / ABI properties once, here, from arch/os/ptr_size.
     62    * These mirror the predicates the frontend/backend used to re-derive by
     63    * identity (kit_target_uses_lp64, the Windows wchar width, the binary128
     64    * long-double psABI test, and the freestanding eh_frame gate). */
     65   /* #33 LP64 vs LLP64/ILP32: long is 8 bytes only for 64-bit non-Windows. */
     66   t->spec.long_size =
     67       (t->spec.ptr_size == 8u && t->spec.os != KIT_OS_WINDOWS) ? 8u : 4u;
     68   /* #32/#20 wchar_t: 2 bytes on Windows, 4 elsewhere. */
     69   t->spec.wchar_size = (t->spec.os == KIT_OS_WINDOWS) ? 2u : 4u;
     70   /* #3/#20 long double: binary128 on the quad-psABI targets (rv64, non-Apple/
     71    * non-Windows aarch64, wasm), else aliases double. Replicates
     72    * kit_target_long_double_is_binary128 exactly. */
     73   if (t->spec.arch == KIT_ARCH_RV64 ||
     74       (t->spec.arch == KIT_ARCH_ARM_64 && t->spec.obj != KIT_OBJ_MACHO &&
     75        t->spec.os != KIT_OS_WINDOWS) ||
     76       t->spec.arch == KIT_ARCH_WASM) {
     77     t->spec.long_double_format = (uint8_t)KIT_LDBL_BINARY128;
     78   } else {
     79     t->spec.long_double_format = (uint8_t)KIT_LDBL_DOUBLE;
     80   }
     81   /* #17 eh_frame: hosted ELF/COFF targets emit .eh_frame for the host
     82    * unwinder; freestanding does not (no unwinder, and it would orphan an
     83    * ALLOC section). Mach-O is also excluded: ld64 / ld64.lld reject kit's
     84    * raw __eh_frame — arm64 Mach-O has no pcrel-32 data relocation for the
     85    * FDE pc-begin, and ld64's legacy __eh_frame path is effectively unused
     86    * (clang emits __compact_unwind instead). kit's macOS backtrace walks
     87    * the frame-pointer chain, so dropping __eh_frame costs no capability
     88    * while making kit objects linkable by the system linker. */
     89   t->spec.emits_eh_frame =
     90       (t->spec.os != KIT_OS_FREESTANDING && t->spec.obj != KIT_OBJ_MACHO) ? 1u
     91                                                                           : 0u;
     92 
     93   nwords = (arch->ntarget_features + 63u) / 64u;
     94   if (nwords) {
     95     t->feature_words =
     96         (u64*)h->alloc(h, sizeof(*t->feature_words) * nwords, _Alignof(u64));
     97     if (!t->feature_words) {
     98       h->free(h, t, sizeof(*t));
     99       return KIT_NOMEM;
    100     }
    101     memset(t->feature_words, 0, sizeof(*t->feature_words) * nwords);
    102     t->nfeature_words = nwords;
    103     arch_target_feature_defaults(arch, &t->spec, t->feature_words, nwords);
    104   }
    105 
    106   if (opts->isa.s && opts->isa.len) {
    107     KitStatus st = arch_target_feature_apply_isa(
    108         arch, &t->spec, opts->isa, t->feature_words, t->nfeature_words);
    109     if (st != KIT_OK) {
    110       kit_ctx_diagf(ctx, "unsupported ISA/profile for %s: %.*s", arch->name,
    111                     KIT_SLICE_ARG(opts->isa));
    112       kit_target_free(t);
    113       return st == KIT_UNSUPPORTED ? KIT_INVALID : st;
    114     }
    115   }
    116 
    117   /* -mcpu= after -march= so a CPU selector refines (or, for ARM, re-pins) the
    118    * ISA profile; explicit -mattr/-m<feature> overrides come last. */
    119   if (opts->cpu.s && opts->cpu.len) {
    120     KitStatus st = arch_target_feature_apply_cpu(
    121         arch, &t->spec, opts->cpu, t->feature_words, t->nfeature_words);
    122     if (st != KIT_OK) {
    123       kit_ctx_diagf(ctx, "unsupported CPU for %s: %.*s", arch->name,
    124                     KIT_SLICE_ARG(opts->cpu));
    125       kit_target_free(t);
    126       return st == KIT_UNSUPPORTED ? KIT_INVALID : st;
    127     }
    128   }
    129 
    130   for (i = 0; i < opts->nfeatures; ++i) {
    131     u32 idx;
    132     KitSlice name = opts->features[i].name;
    133     if (!arch_target_feature_index(arch, name, &idx)) {
    134       kit_ctx_diagf(ctx, "unknown target feature for %s: %.*s", arch->name,
    135                     KIT_SLICE_ARG(name));
    136       kit_target_free(t);
    137       return KIT_INVALID;
    138     }
    139     bitset_set(t->feature_words, t->nfeature_words, idx,
    140                opts->features[i].enabled);
    141   }
    142 
    143   /* Resolve & validate the float ABI by arch capability. Arches with no
    144    * float-ABI axis (everything but RISC-V) leave float_abi at
    145    * KIT_FLOAT_ABI_DEFAULT via the no-op hook. The RISC-V hook produces the
    146    * same byte-identical diagnostics the old inline block emitted. */
    147   {
    148     char errbuf[256];
    149     errbuf[0] = '\0';
    150     if (arch_resolve_float_abi(arch, &t->spec, t->feature_words,
    151                                t->nfeature_words, opts->abi, errbuf,
    152                                sizeof errbuf) == KIT_INVALID) {
    153       kit_ctx_diagf(ctx, "%s", errbuf);
    154       kit_target_free(t);
    155       return KIT_INVALID;
    156     }
    157   }
    158 
    159   *out = t;
    160   return KIT_OK;
    161 }
    162 
    163 void kit_target_free(KitTarget* t) {
    164   Heap* h;
    165   if (!t) return;
    166   h = t->ctx ? t->ctx->heap : NULL;
    167   if (!h) return;
    168   if (t->feature_words)
    169     h->free(h, t->feature_words, sizeof(*t->feature_words) * t->nfeature_words);
    170   h->free(h, t, sizeof(*t));
    171 }
    172 
    173 KitTargetSpec kit_target_spec(const KitTarget* t) {
    174   KitTargetSpec spec;
    175   memset(&spec, 0, sizeof spec);
    176   return t ? t->spec : spec;
    177 }
    178 
    179 int kit_target_has_feature(const KitTarget* t, KitSlice name) {
    180   const ArchImpl* arch;
    181   u32 idx;
    182   if (!t) return 0;
    183   arch = arch_lookup(t->spec.arch);
    184   if (!arch_target_feature_index(arch, name, &idx)) return 0;
    185   return bitset_get(t->feature_words, t->nfeature_words, idx);
    186 }
    187 
    188 KitStatus kit_compiler_new(const KitTarget* target, const KitContext* ctx,
    189                            KitCompiler** out) {
    190   return kit_compiler_new_ex(target, ctx, NULL, out);
    191 }
    192 
    193 KitStatus kit_compiler_new_ex(const KitTarget* target, const KitContext* ctx,
    194                               const KitCompilerOptions* opts,
    195                               KitCompiler** out) {
    196   Heap* h;
    197   Compiler* c;
    198   KitStatus st;
    199 
    200   if (!out) return KIT_INVALID;
    201   if (!target || !ctx || !ctx->heap) return KIT_INVALID;
    202   h = ctx->heap;
    203   c = h->alloc(h, sizeof(*c), _Alignof(Compiler));
    204   if (!c) return KIT_NOMEM;
    205   st = compiler_init(c, target, ctx);
    206   if (st != KIT_OK) {
    207     h->free(h, c, sizeof(*c));
    208     return st;
    209   }
    210   if (opts && opts->frontends) {
    211     st = kit_compiler_install_frontend_registry(c, opts->frontends);
    212     if (st != KIT_OK) {
    213       compiler_fini(c);
    214       h->free(h, c, sizeof(*c));
    215       if (out) *out = NULL;
    216       return st;
    217     }
    218   }
    219   *out = c;
    220   return KIT_OK;
    221 }
    222 
    223 void kit_compiler_free(KitCompiler* c) {
    224   Heap* h;
    225   if (!c) return;
    226   h = c->ctx->heap;
    227   compiler_fini(c);
    228   h->free(h, c, sizeof(*c));
    229 }
    230 
    231 const KitTarget* kit_compiler_target(KitCompiler* c) {
    232   return c ? c->target_ref : NULL;
    233 }
    234 
    235 KitTargetSpec kit_compiler_target_spec(KitCompiler* c) {
    236   KitTargetSpec t;
    237   memset(&t, 0, sizeof t);
    238   if (!c) return t;
    239   return c->target;
    240 }
    241 
    242 const KitContext* kit_compiler_context(KitCompiler* c) {
    243   return (c && c->ctx) ? c->ctx : NULL;
    244 }
    245 
    246 KitSlice kit_compiler_file_name(KitCompiler* c, uint32_t file_id) {
    247   const SourceFile* f;
    248   if (!c) return SLICE_NULL;
    249   f = source_file(c->sources, file_id);
    250   if (!f) return SLICE_NULL;
    251   return pool_slice(c->global, f->name);
    252 }
    253 
    254 KitSym kit_sym_intern(KitCompiler* c, KitSlice s) {
    255   if (!c) return 0;
    256   return pool_intern_slice(c->global, s);
    257 }
    258 
    259 KitSlice kit_sym_str(KitCompiler* c, KitSym sym) {
    260   if (!c) return SLICE_NULL;
    261   return pool_slice(c->global, (Sym)sym);
    262 }
    263 
    264 KitSym kit_cg_c_linkage_name(KitCompiler* c, KitSym source_name) {
    265   const char* name;
    266   size_t len;
    267   char* buf;
    268   char stackbuf[256]; /* C linkage names are short identifiers; this covers
    269                        * all but pathological cases without touching the heap.
    270                        * Called once per declared symbol, so a per-call malloc
    271                        * here scales with declaration count -- avoid it. */
    272   int heaped;
    273   KitSym out;
    274   Heap* h;
    275   Slice nslice;
    276 
    277   if (!c || !source_name) return 0;
    278   nslice = pool_slice(c->global, (Sym)source_name);
    279   name = nslice.s;
    280   len = nslice.len;
    281   if (!name) return 0;
    282   if (c->target.obj != KIT_OBJ_MACHO) return source_name;
    283 
    284   h = c->ctx->heap;
    285   heaped = len + 2u > sizeof stackbuf;
    286   buf = heaped ? (char*)h->alloc(h, len + 2u, 1) : stackbuf;
    287   if (!buf) return 0;
    288   buf[0] = '_';
    289   if (len) memcpy(buf + 1, name, len);
    290   buf[len + 1u] = '\0';
    291   out = pool_intern_slice(c->global, (Slice){.s = buf, .len = (u32)(len + 1u)});
    292   if (heaped) h->free(h, buf, len + 2u);
    293   return out;
    294 }
    295 
    296 typedef struct MemWriter {
    297   KitWriter base;
    298   Heap* heap;
    299   u8* data;
    300   size_t cap;
    301   size_t len;
    302   size_t pos;
    303   KitStatus status;
    304 } MemWriter;
    305 
    306 static KitStatus mw_grow(MemWriter* mw, size_t needed) {
    307   size_t new_cap;
    308   u8* p;
    309 
    310   if (needed <= mw->cap) return KIT_OK;
    311   new_cap = mw->cap ? mw->cap : 64;
    312   while (new_cap < needed) {
    313     size_t doubled = new_cap * 2;
    314     if (doubled <= new_cap) {
    315       mw->status = KIT_NOMEM;
    316       return KIT_NOMEM;
    317     }
    318     new_cap = doubled;
    319   }
    320 
    321   p = (u8*)mw->heap->realloc(mw->heap, mw->data, mw->cap, new_cap, 1);
    322   if (!p) {
    323     mw->status = KIT_NOMEM;
    324     return KIT_NOMEM;
    325   }
    326   if (new_cap > mw->cap) memset(p + mw->cap, 0, new_cap - mw->cap);
    327   mw->data = p;
    328   mw->cap = new_cap;
    329   return KIT_OK;
    330 }
    331 
    332 static KitStatus mw_write(KitWriter* w, const void* data, size_t n) {
    333   MemWriter* mw = (MemWriter*)w;
    334   size_t end;
    335   KitStatus st;
    336 
    337   if (mw->status != KIT_OK) return mw->status;
    338   if (n == 0) return KIT_OK;
    339   end = mw->pos + n;
    340   if (end < mw->pos) {
    341     mw->status = KIT_NOMEM;
    342     return KIT_NOMEM;
    343   }
    344   st = mw_grow(mw, end);
    345   if (st != KIT_OK) return st;
    346   memcpy(mw->data + mw->pos, data, n);
    347   mw->pos = end;
    348   if (mw->pos > mw->len) mw->len = mw->pos;
    349   return KIT_OK;
    350 }
    351 
    352 static KitStatus mw_seek(KitWriter* w, uint64_t off) {
    353   MemWriter* mw = (MemWriter*)w;
    354   if (mw->status != KIT_OK) return mw->status;
    355   mw->pos = (size_t)off;
    356   return KIT_OK;
    357 }
    358 
    359 static uint64_t mw_tell(KitWriter* w) { return ((MemWriter*)w)->pos; }
    360 
    361 static KitStatus mw_status(KitWriter* w) { return ((MemWriter*)w)->status; }
    362 
    363 static void mw_close(KitWriter* w) {
    364   MemWriter* mw = (MemWriter*)w;
    365   Heap* h = mw->heap;
    366   if (mw->data) h->free(h, mw->data, mw->cap);
    367   h->free(h, mw, sizeof(*mw));
    368 }
    369 
    370 KitStatus kit_writer_mem(KitHeap* heap, KitWriter** out) {
    371   MemWriter* mw;
    372   if (!out) return KIT_INVALID;
    373   if (!heap) return KIT_INVALID;
    374   mw = (MemWriter*)heap->alloc(heap, sizeof(*mw), _Alignof(MemWriter));
    375   if (!mw) return KIT_NOMEM;
    376   mw->base.write = mw_write;
    377   mw->base.seek = mw_seek;
    378   mw->base.tell = mw_tell;
    379   mw->base.status = mw_status;
    380   mw->base.close = mw_close;
    381   mw->heap = heap;
    382   mw->data = NULL;
    383   mw->cap = 0;
    384   mw->len = 0;
    385   mw->pos = 0;
    386   mw->status = KIT_OK;
    387   *out = &mw->base;
    388   return KIT_OK;
    389 }
    390 
    391 const uint8_t* kit_writer_mem_bytes(KitWriter* w, size_t* len_out) {
    392   MemWriter* mw = (MemWriter*)w;
    393   if (len_out) *len_out = mw ? mw->len : 0;
    394   return mw ? mw->data : NULL;
    395 }