kit

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

core.c (10021B)


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