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 }