c_emit.c (147437B)
1 /* C-source emission core. See doc/CBACKEND.md. 2 * 3 * Output strategy 4 * --------------- 5 * Each function buffers two CBufs while CG walks the body: 6 * decls — variable declarations: " long long v3;\n" 7 * body — TU-wide running output; we accumulate signature/body/closing-brace 8 * across all functions; func_end splices decls in after the open 9 * brace using the recorded fn_body_start bookmark. 10 * 11 * c_emit_finalize flushes a tiny prologue + body to the writer. 12 * 13 * Local declaration is lazy: every operand emit goes through c_ensure_local, 14 * which appends one declaration for each semantic local. */ 15 16 #include "arch/c_target/c_emit.h" 17 18 #include <stdio.h> 19 #include <string.h> 20 21 #include "cg/type.h" 22 #include "core/arena.h" 23 #include "core/core.h" 24 #include "core/heap.h" 25 #include "core/pool.h" 26 #include "core/slice.h" 27 #include "core/vec.h" 28 #include "obj/format.h" 29 #include "obj/obj.h" 30 31 /* Forward decls. */ 32 static void c_ensure_typedef(CTarget* t, KitCgTypeId tid); 33 static const char* c_typedef_name(CTarget* t, KitCgTypeId tid); 34 static const char* c_typename(CTarget* t, KitCgTypeId type); 35 static KitCgTypeId c_local_type_or_panic(CTarget* t, CGLocal local); 36 static Operand c_op_local(CGLocal local, KitCgTypeId type); 37 static int c_type_is_aggregate(CTarget* t, KitCgTypeId type); 38 static int c_type_is_bool(CTarget* t, KitCgTypeId type); 39 static int c_type_is_ptr(CTarget* t, KitCgTypeId type); 40 static int c_operand_is_ptr_typed(CTarget* t, Operand op); 41 static void c_emit_addr_deref(CTarget* t, Operand addr, 42 KitCgTypeId access_type); 43 static void c_emit_copy_addr(CTarget* t, Operand addr); 44 CGLocal c_emit_local(CTarget* t, const CGLocalDesc* d); 45 /* Private accessor on ObjBuilder (defined in obj/obj.c, not in obj.h). 46 * Same forward-decl trick as obj_tls.c uses. */ 47 ObjSymId obj_tlv_bootstrap_get(const ObjBuilder*); 48 49 /* === Growable-array helpers === 50 * 51 * The C target's growable tables are heap-backed (allocated from 52 * t->c->ctx->heap and freed in c_emit_destroy), so they route through 53 * core/vec.h's VEC_GROW rather than hand-rolling the doubling realloc. 54 * 55 * c_vec_grow_or_panic: ensure capacity >= want, panicking on OOM. Used by 56 * append-style tables (scopes, local_static_*) where the live region is 57 * tracked by a separate count and the grown tail is never read before being 58 * written. 59 * 60 * c_vec_grow_zeroed: same, but zero-fills the newly grown tail. Used by 61 * index-addressed tables (type_state, local_*, sym_forwarded) that are read 62 * at arbitrary indices and rely on a zero default. VEC_GROW does not zero, 63 * so we capture the pre-grow cap and clear [old_cap, new_cap). 64 * 65 * Both are macros so VEC_GROW can derive element size/alignment from *ptr. */ 66 #define c_vec_grow_or_panic(t, ptr, cap, want) \ 67 do { \ 68 if (VEC_GROW((t)->c->ctx->heap, (ptr), (cap), (want))) { \ 69 compiler_panic((t)->c, (SrcLoc){0, 0, 0}, "C target: out of memory"); \ 70 } \ 71 } while (0) 72 73 #define c_vec_grow_zeroed(t, ptr, cap, want) \ 74 do { \ 75 u32 c_vgz_old_ = (cap); \ 76 c_vec_grow_or_panic((t), (ptr), (cap), (want)); \ 77 if ((cap) > c_vgz_old_) { \ 78 memset((ptr) + c_vgz_old_, 0, \ 79 ((size_t)((cap) - c_vgz_old_)) * sizeof(*(ptr))); \ 80 } \ 81 } while (0) 82 83 /* === Target state === */ 84 85 void c_emit_target_init(CTarget* t, Compiler* c, ObjBuilder* o, KitWriter* w) { 86 memset(t, 0, sizeof *t); 87 t->c = c; 88 t->obj = o; 89 t->w = w; 90 cbuf_init(&t->forwards, c->ctx->heap); 91 cbuf_init(&t->typedefs, c->ctx->heap); 92 cbuf_init(&t->data_defs, c->ctx->heap); 93 cbuf_init(&t->decls, c->ctx->heap); 94 cbuf_init(&t->body, c->ctx->heap); 95 } 96 97 CTarget* c_emit_target_new(Compiler* c, ObjBuilder* o, KitWriter* w) { 98 CTarget* t = arena_new(c->tu, CTarget); 99 if (!t) return NULL; 100 c_emit_target_init(t, c, o, w); 101 return t; 102 } 103 104 /* === Writer helpers === */ 105 106 void c_writer_write(CTarget* t, const void* data, size_t n) { 107 KitStatus st = kit_writer_write(t->w, data, n); 108 if (st != KIT_OK) { 109 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 110 compiler_panic(t->c, loc, "C target: writer error %d", (int)st); 111 } 112 } 113 114 void c_writer_puts(CTarget* t, const char* s) { 115 size_t n = 0; 116 while (s[n]) ++n; 117 c_writer_write(t, s, n); 118 } 119 120 /* === CLocal / type emission === */ 121 122 static const char* c_int_type_name_for_width(u32 width, int signed_) { 123 switch (width) { 124 case 1: 125 case 8: 126 return signed_ ? "int8_t" : "uint8_t"; 127 case 16: 128 return signed_ ? "int16_t" : "uint16_t"; 129 case 32: 130 return signed_ ? "int32_t" : "uint32_t"; 131 case 64: 132 return signed_ ? "int64_t" : "uint64_t"; 133 case 128: 134 return signed_ ? "__int128" : "unsigned __int128"; 135 default: 136 return NULL; 137 } 138 } 139 140 /* Returns the integer width for sign-aware emission. 0 if the type isn't a 141 * fixed-width integer (float, ptr, void, aggregate). */ 142 static u32 c_int_width_for_signedness(CTarget* t, KitCgTypeId type) { 143 if (type == KIT_CG_TYPE_NONE) return 0; 144 const CgType* ty = cg_type_get(t->c, type); 145 if (!ty) return 0; 146 if (ty->kind == KIT_CG_TYPE_INT) return ty->integer.width; 147 if (ty->kind == KIT_CG_TYPE_BOOL) return 32; /* bool maps to int32_t */ 148 return 0; 149 } 150 151 /* === Typedef machinery === 152 * 153 * Composite types (records, arrays, function types) are emitted as opaque 154 * byte-storage typedefs in a TU-wide typedefs section. The typedef name is 155 * `__ty_<id>` keyed on the unaliased type id; this is stable for the 156 * compiler instance. 157 * 158 * For records and arrays the typedef wraps a single `_Alignas(A) uint8_t 159 * raw[N];` member, so all field/element access is mediated by the existing 160 * `(*(T*)((char*)addr + ofs))` path. This sidesteps any ABI ambiguity (C 161 * bitfield rules, array decay, packed/aligned attribute interactions) and 162 * keeps types orthogonal to access patterns. 163 * 164 * For function types we emit a function-pointer typedef `R (*__ty_N)(...)`, 165 * used for indirect calls and function-pointer-typed values. */ 166 167 static void c_grow_type_state(CTarget* t, u32 needed) { 168 c_vec_grow_zeroed(t, t->type_state, t->type_state_cap, needed); 169 } 170 171 static const char* c_typedef_name(CTarget* t, KitCgTypeId tid) { 172 char buf[32]; 173 int n = snprintf(buf, sizeof buf, "__ty_%u", (unsigned)tid); 174 Sym s = pool_intern_slice(t->c->global, (Slice){.s = buf, .len = (size_t)n}); 175 return pool_slice(t->c->global, s).s; 176 } 177 178 /* Forward decl. */ 179 static void c_emit_typedef_for_func(CTarget* t, KitCgTypeId tid, 180 const CgType* ty); 181 182 static void c_ensure_typedef(CTarget* t, KitCgTypeId tid) { 183 KitCgTypeId u = tid; 184 if ((u32)u >= t->type_state_cap) c_grow_type_state(t, (u32)u + 1u); 185 if (t->type_state[u] >= 2) return; 186 if (t->type_state[u] == 1) return; /* cyclic — emit forward-only */ 187 t->type_state[u] = 1; 188 const CgType* ty = cg_type_get(t->c, u); 189 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 190 if (!ty) 191 compiler_panic(t->c, loc, "C target: unknown type id %u", (unsigned)u); 192 switch (ty->kind) { 193 case KIT_CG_TYPE_FUNC: 194 c_emit_typedef_for_func(t, u, ty); 195 break; 196 case KIT_CG_TYPE_RECORD: { 197 /* Recurse on field types so any composite-typed field has its 198 * typedef emitted first. (Records-by-value are accessed only via 199 * pointer arithmetic in kit CG, but emitting deps first keeps the 200 * output readable and stable.) */ 201 for (u32 i = 0; i < ty->record.nfields; ++i) { 202 if (!(ty->record.fields[i].flags & KIT_CG_FIELD_BITFIELD)) { 203 KitCgTypeId ft = ty->record.fields[i].type; 204 KitCgTypeId ftu = ft; 205 const CgType* fty = cg_type_get(t->c, ftu); 206 if (fty && (fty->kind == KIT_CG_TYPE_RECORD || 207 fty->kind == KIT_CG_TYPE_ARRAY || 208 fty->kind == KIT_CG_TYPE_FUNC)) { 209 c_ensure_typedef(t, ftu); 210 } 211 } 212 } 213 cbuf_puts(&t->typedefs, "typedef struct { _Alignas("); 214 cbuf_put_u64(&t->typedefs, (u64)cg_type_align(t->c, u)); 215 cbuf_puts(&t->typedefs, ") uint8_t raw["); 216 cbuf_put_u64(&t->typedefs, cg_type_size(t->c, u)); 217 cbuf_puts(&t->typedefs, "]; } __ty_"); 218 cbuf_put_u64(&t->typedefs, (u64)u); 219 cbuf_puts(&t->typedefs, ";\n"); 220 break; 221 } 222 case KIT_CG_TYPE_ARRAY: { 223 KitCgTypeId eu = ty->array.elem; 224 const CgType* ety = cg_type_get(t->c, eu); 225 if (ety && 226 (ety->kind == KIT_CG_TYPE_RECORD || ety->kind == KIT_CG_TYPE_ARRAY || 227 ety->kind == KIT_CG_TYPE_FUNC)) { 228 c_ensure_typedef(t, eu); 229 } 230 cbuf_puts(&t->typedefs, "typedef struct { _Alignas("); 231 cbuf_put_u64(&t->typedefs, (u64)cg_type_align(t->c, u)); 232 cbuf_puts(&t->typedefs, ") uint8_t raw["); 233 cbuf_put_u64(&t->typedefs, cg_type_size(t->c, u)); 234 cbuf_puts(&t->typedefs, "]; } __ty_"); 235 cbuf_put_u64(&t->typedefs, (u64)u); 236 cbuf_puts(&t->typedefs, ";\n"); 237 break; 238 } 239 default: 240 compiler_panic(t->c, loc, 241 "C target: c_ensure_typedef on non-composite kind %d", 242 (int)ty->kind); 243 } 244 t->type_state[u] = 2; 245 } 246 247 static void c_emit_typedef_for_func(CTarget* t, KitCgTypeId tid, 248 const CgType* ty) { 249 /* Emit recursively for return and param types if they're composites. */ 250 KitCgTypeId ret = cg_func_ret_type(ty); 251 const CgType* rty = cg_type_get(t->c, ret); 252 if (rty && 253 (rty->kind == KIT_CG_TYPE_RECORD || rty->kind == KIT_CG_TYPE_ARRAY || 254 rty->kind == KIT_CG_TYPE_FUNC)) { 255 c_ensure_typedef(t, ret); 256 } 257 for (u32 i = 0; i < ty->func.nparams; ++i) { 258 KitCgTypeId pt = ty->func.params[i].type; 259 const CgType* pty = cg_type_get(t->c, pt); 260 if (pty && 261 (pty->kind == KIT_CG_TYPE_RECORD || pty->kind == KIT_CG_TYPE_ARRAY || 262 pty->kind == KIT_CG_TYPE_FUNC)) { 263 c_ensure_typedef(t, pt); 264 } 265 } 266 cbuf_puts(&t->typedefs, "typedef "); 267 cbuf_puts(&t->typedefs, c_typename(t, cg_func_ret_type(ty))); 268 cbuf_puts(&t->typedefs, " (*__ty_"); 269 cbuf_put_u64(&t->typedefs, (u64)tid); 270 cbuf_puts(&t->typedefs, ")("); 271 if (ty->func.nparams == 0 && !ty->func.abi_variadic) { 272 cbuf_puts(&t->typedefs, "void"); 273 } else { 274 for (u32 i = 0; i < ty->func.nparams; ++i) { 275 if (i > 0) cbuf_puts(&t->typedefs, ", "); 276 cbuf_puts(&t->typedefs, c_typename(t, ty->func.params[i].type)); 277 } 278 if (ty->func.abi_variadic) { 279 if (ty->func.nparams > 0) cbuf_puts(&t->typedefs, ", "); 280 cbuf_puts(&t->typedefs, "..."); 281 } 282 } 283 cbuf_puts(&t->typedefs, ");\n"); 284 } 285 286 static const char* c_int_type_for_width_panic(CTarget* t, u32 width, 287 int signed_) { 288 const char* s = c_int_type_name_for_width(width, signed_); 289 if (!s) { 290 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 291 compiler_panic(t->c, loc, "C target: int width %u not yet supported", 292 (unsigned)width); 293 } 294 return s; 295 } 296 297 static const char* c_float_type_name(u32 width) { 298 switch (width) { 299 case 32: 300 return "float"; 301 case 64: 302 return "double"; 303 case 80: 304 case 128: 305 return "long double"; 306 default: 307 return NULL; 308 } 309 } 310 311 /* Returns the C type name for a CG type id. Scalars map to fixed-width 312 * <stdint.h> types or float/double/long double; pointers collapse to void*; 313 * composites (records/arrays/funcs) emit an opaque-storage typedef on first 314 * sighting and return the typedef name. */ 315 static const char* c_typename(CTarget* t, KitCgTypeId type) { 316 KitCgTypeId resolved = type; 317 const CgType* ty = cg_type_get(t->c, resolved); 318 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 319 if (!ty) { 320 compiler_panic(t->c, loc, "C target: unknown type id %u", (unsigned)type); 321 } 322 switch (ty->kind) { 323 case KIT_CG_TYPE_VOID: 324 return "void"; 325 case KIT_CG_TYPE_BOOL: 326 return "int32_t"; 327 case KIT_CG_TYPE_INT: 328 return c_int_type_for_width_panic(t, ty->integer.width, 1); 329 case KIT_CG_TYPE_FLOAT: { 330 const char* s = c_float_type_name(ty->fp.width); 331 if (!s) { 332 compiler_panic(t->c, loc, "C target: fp width %u not yet supported", 333 (unsigned)ty->fp.width); 334 } 335 return s; 336 } 337 case KIT_CG_TYPE_PTR: 338 return "void*"; 339 case KIT_CG_TYPE_ENUM: 340 /* CG enums are width-only; treat as their underlying integer base. */ 341 return c_typename(t, ty->enum_.base); 342 case KIT_CG_TYPE_VARARG_STATE: 343 t->need_stdarg = 1; 344 return "va_list"; 345 case KIT_CG_TYPE_RECORD: 346 case KIT_CG_TYPE_ARRAY: 347 case KIT_CG_TYPE_FUNC: 348 c_ensure_typedef(t, resolved); 349 return c_typedef_name(t, resolved); 350 default: 351 compiler_panic(t->c, loc, "C target: type kind %d not yet supported", 352 (int)ty->kind); 353 } 354 } 355 356 void c_emit_type(CTarget* t, CBuf* b, KitCgTypeId type) { 357 cbuf_puts(b, c_typename(t, type)); 358 } 359 360 static KitCgTypeId c_local_type_or_panic(CTarget* t, CGLocal local) { 361 if ((u32)local < t->local_cap && t->local_declared[local] && 362 t->local_type[local]) { 363 return t->local_type[local]; 364 } 365 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 366 "C target: unknown local type for v%u", (unsigned)local); 367 return KIT_CG_TYPE_NONE; 368 } 369 370 static Operand c_op_local(CGLocal local, KitCgTypeId type) { 371 Operand op; 372 memset(&op, 0, sizeof op); 373 op.kind = OPK_LOCAL; 374 op.type = type; 375 op.v.local = local; 376 return op; 377 } 378 379 void c_local_name(CLocal r, char* out, size_t cap) { 380 size_t i = 0; 381 if (cap == 0) return; 382 if (cap > 1) out[i++] = 'v'; 383 char tmp[16]; 384 size_t n = 0; 385 u32 v = (u32)r; 386 if (v == 0) { 387 tmp[n++] = '0'; 388 } else { 389 while (v) { 390 tmp[n++] = (char)('0' + (v % 10)); 391 v /= 10; 392 } 393 } 394 while (n && i + 1 < cap) out[i++] = tmp[--n]; 395 out[i] = '\0'; 396 } 397 398 static void c_grow_local_table(CTarget* t, u32 needed) { 399 /* Two parallel arrays kept at a single shared local_cap. Grow each from the 400 * same old cap to the same new cap via independent cap trackers, then commit 401 * the shared cap once. (They always grow together, so both reach the same 402 * VEC_GROW-derived capacity.) */ 403 u32 declared_cap = t->local_cap; 404 u32 type_cap = t->local_cap; 405 c_vec_grow_zeroed(t, t->local_declared, declared_cap, needed); 406 c_vec_grow_zeroed(t, t->local_type, type_cap, needed); 407 t->local_cap = declared_cap; 408 } 409 410 /* Emit the trailing `__attribute__((unused)) = INIT;` for a local decl of 411 * type `ty`. Scalars get `= 0` (readable); aggregates get `= {0}` (the only 412 * form that compiles for record/array). va_list also takes `= {0}`: the host's 413 * <stdarg.h> va_list is an aggregate (struct/array) on common ABIs (aarch64, 414 * x86-64 SysV) where `= 0` is invalid, and `= {0}` is also valid for the 415 * pointer form (e.g. Apple), so it is the portable choice. */ 416 static void c_emit_zero_init(CTarget* t, KitCgTypeId ty) { 417 const CgType* cgt = ty ? cg_type_get(t->c, ty) : NULL; 418 int braced = cgt && (cgt->kind == KIT_CG_TYPE_RECORD || 419 cgt->kind == KIT_CG_TYPE_ARRAY || 420 cgt->kind == KIT_CG_TYPE_VARARG_STATE); 421 cbuf_puts(&t->decls, braced ? " __attribute__((unused)) = {0};\n" 422 : " __attribute__((unused)) = 0;\n"); 423 } 424 425 void c_ensure_local(CTarget* t, CLocal r, KitCgTypeId type) { 426 if (r == (CLocal)CG_LOCAL_NONE) { 427 compiler_panic(t->c, (SrcLoc){0, 0, 0}, 428 "C target: CG_LOCAL_NONE reached emission"); 429 } 430 if ((u32)r >= t->local_cap) c_grow_local_table(t, (u32)r + 1u); 431 if (t->local_declared[r]) { 432 if (type && t->local_type[r] != type) { 433 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 434 "C target: local v%u used with inconsistent type " 435 "(declared %u, used %u)", 436 (unsigned)r, (unsigned)t->local_type[r], (unsigned)type); 437 } 438 return; 439 } 440 t->local_declared[r] = 1; 441 t->local_type[r] = type; 442 cbuf_puts(&t->decls, " "); 443 c_emit_type(t, &t->decls, type); 444 cbuf_puts(&t->decls, " "); 445 char buf[24]; 446 c_local_name(r, buf, sizeof buf); 447 cbuf_puts(&t->decls, buf); 448 /* Zero-init kills -Wsometimes-uninitialized for control flow clang can't 449 * reason through; the host C compiler DSEs the init when a real 450 * assignment dominates. Scalars get `= 0`, aggregates `= {0}`. */ 451 c_emit_zero_init(t, type); 452 } 453 454 /* Emit a signed-int64 literal. INT64_MIN can't be written directly: clang 455 * treats `-9223372036854775808` as `-(9223372036854775808)` with the inner 456 * literal too large for any signed type, which trips 457 * -Wimplicitly-unsigned-literal. The standard workaround is 458 * `(-9223372036854775807LL - 1)`. */ 459 static void c_emit_imm_literal(CTarget* t, i64 v) { 460 if (v == (i64)((u64)1u << 63u)) { 461 cbuf_puts(&t->body, "(-9223372036854775807LL - 1)"); 462 return; 463 } 464 cbuf_put_i64(&t->body, v); 465 } 466 467 /* Address-mode tuple decoded from an OPK_INDIRECT operand. Mirrors the 468 * `addr_mode` helper in the machine-code backends so all targets share a 469 * single in-backend view of `base [+ index << log2_scale] + ofs`. */ 470 typedef struct CAddrMode { 471 CLocal base; 472 CLocal index; /* CG_LOCAL_NONE when no index operand */ 473 u8 log2_scale; /* meaningful only when index != CG_LOCAL_NONE */ 474 i32 ofs; 475 } CAddrMode; 476 477 static CAddrMode c_addr_mode(Operand addr) { 478 CAddrMode m; 479 m.base = addr.v.ind.base; 480 m.index = addr.v.ind.index; 481 m.log2_scale = addr.v.ind.log2_scale; 482 m.ofs = addr.v.ind.ofs; 483 return m; 484 } 485 486 /* Emit `(char*)base [+ (uintptr_t)index * (1u << log2_scale)] [+ ofs]` into 487 * the body, with each optional term suppressed when absent. Used by every 488 * OPK_INDIRECT renderer; the caller wraps it with the appropriate 489 * `(*(T*)(...))` or `((T)(...))` cast. */ 490 static void c_emit_indirect_addr_expr(CTarget* t, CAddrMode m) { 491 char rbuf[24]; 492 cbuf_puts(&t->body, "(char*)"); 493 c_local_name(m.base, rbuf, sizeof rbuf); 494 cbuf_puts(&t->body, rbuf); 495 if (m.index != CG_LOCAL_NONE) { 496 cbuf_puts(&t->body, " + (uintptr_t)"); 497 c_local_name(m.index, rbuf, sizeof rbuf); 498 cbuf_puts(&t->body, rbuf); 499 cbuf_puts(&t->body, " * "); 500 /* Spell as the explicit 1/2/4/8 literal corresponding to log2_scale. 501 * log2_scale is normalized to {0,1,2,3} by cg. */ 502 cbuf_put_u64(&t->body, (u64)(1u << m.log2_scale)); 503 } 504 if (m.ofs != 0) { 505 cbuf_puts(&t->body, " + "); 506 cbuf_put_i64(&t->body, (i64)m.ofs); 507 } 508 } 509 510 /* Assert that `addr`, if OPK_INDIRECT, has no index operand. Used by paths 511 * the cg layer guarantees never carry the indexed shape (bitfield, atomics, 512 * copy_bytes/set_bytes, inline asm). */ 513 static void c_assert_no_index(CTarget* t, Operand addr, const char* where) { 514 if (addr.kind != OPK_INDIRECT) return; 515 if (addr.v.ind.index == CG_LOCAL_NONE) return; 516 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 517 compiler_panic(t->c, loc, 518 "C target: %.*s: indexed OPK_INDIRECT not allowed here", 519 SLICE_ARG(slice_from_cstr(where))); 520 } 521 522 void c_emit_operand(CTarget* t, Operand op) { 523 char buf[24]; 524 switch (op.kind) { 525 case OPK_IMM: 526 if (op.type == KIT_CG_TYPE_NONE) { 527 /* Untyped IMM (e.g. memset byte value): emit the literal raw. */ 528 cbuf_putc(&t->body, '('); 529 c_emit_imm_literal(t, op.v.imm); 530 cbuf_putc(&t->body, ')'); 531 } else { 532 cbuf_puts(&t->body, "(("); 533 c_emit_type(t, &t->body, op.type); 534 cbuf_puts(&t->body, ")"); 535 c_emit_imm_literal(t, op.v.imm); 536 cbuf_puts(&t->body, ")"); 537 } 538 return; 539 case OPK_LOCAL: { 540 c_ensure_local(t, op.v.local, op.type); 541 c_local_name(op.v.local, buf, sizeof buf); 542 cbuf_puts(&t->body, buf); 543 return; 544 } 545 case OPK_INDIRECT: { 546 /* Used by call paths to pass aggregates by-address: the operand's type 547 * is the aggregate, the storage is `base + index*scale + ofs`. Emit the 548 * deref as a value expression. */ 549 cbuf_puts(&t->body, "(*("); 550 c_emit_type(t, &t->body, op.type); 551 cbuf_puts(&t->body, "*)("); 552 c_emit_indirect_addr_expr(t, c_addr_mode(op)); 553 cbuf_puts(&t->body, "))"); 554 return; 555 } 556 case OPK_GLOBAL: { 557 /* OPK_GLOBAL carries `&sym + addend`. How we spell it depends on 558 * op.type: 559 * - pointer/scalar/void: the value IS the address, so cast through 560 * `((T)((char*)sym + addend))`. 561 * - aggregate (RECORD/ARRAY): the symbol's storage is an aggregate 562 * value; emit `(*(T*)((char*)sym + addend))` so the deref reads 563 * the aggregate value (used by call args that pass struct 564 * by-value via a global initialized buffer). */ 565 obj_sym_mark_referenced(t->obj, op.v.global.sym); 566 const char* nm = c_sym_name(t, op.v.global.sym); 567 const CgType* gty = 568 (op.type != KIT_CG_TYPE_NONE) ? cg_type_get(t->c, op.type) : NULL; 569 int is_aggregate = gty && (gty->kind == KIT_CG_TYPE_RECORD || 570 gty->kind == KIT_CG_TYPE_ARRAY); 571 if (is_aggregate) { 572 cbuf_puts(&t->body, "(*("); 573 c_emit_type(t, &t->body, op.type); 574 cbuf_puts(&t->body, "*)((char*)&"); 575 cbuf_puts(&t->body, nm); 576 if (op.v.global.addend != 0) { 577 cbuf_puts(&t->body, " + "); 578 cbuf_put_i64(&t->body, op.v.global.addend); 579 } 580 cbuf_puts(&t->body, "))"); 581 } else { 582 cbuf_puts(&t->body, "(("); 583 if (op.type != KIT_CG_TYPE_NONE) { 584 c_emit_type(t, &t->body, op.type); 585 } else { 586 cbuf_puts(&t->body, "void*"); 587 } 588 cbuf_puts(&t->body, ")((char*)&"); 589 cbuf_puts(&t->body, nm); 590 if (op.v.global.addend != 0) { 591 cbuf_puts(&t->body, " + "); 592 cbuf_put_i64(&t->body, op.v.global.addend); 593 } 594 cbuf_puts(&t->body, "))"); 595 } 596 return; 597 } 598 default: { 599 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 600 compiler_panic(t->c, loc, "C target: operand kind %d not yet supported", 601 (int)op.kind); 602 } 603 } 604 } 605 606 static int c_type_is_float(CTarget* t, KitCgTypeId type) { 607 if (type == KIT_CG_TYPE_NONE) return 0; 608 const CgType* ty = cg_type_get(t->c, type); 609 return ty && ty->kind == KIT_CG_TYPE_FLOAT; 610 } 611 612 /* True iff a and b name the same CG type. */ 613 static int c_types_equiv(CTarget* t, KitCgTypeId a, KitCgTypeId b) { 614 (void)t; 615 if (a == 0 || b == 0) return 0; 616 return a == b; 617 } 618 619 /* Emit " vN = " plus any cast needed for a C assignment expression. 620 * Caller must then emit the RHS expression and call c_emit_local_assign_close. 621 * 622 * `rhs_ty` is the CG type the RHS expression will produce (or 0 if unknown). 623 * Pointer/int crossings bridge through uintptr_t to keep host-C diagnostics 624 * quiet. The outer `(...)` parens are kept so the closer's `);` stays 625 * balanced. */ 626 static void c_emit_local_assign_open(CTarget* t, CLocal r, KitCgTypeId rhs_ty) { 627 if ((u32)r >= t->local_cap || !t->local_declared[r]) { 628 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 629 "C target: assign to undeclared local v%u", (unsigned)r); 630 } 631 KitCgTypeId decl = t->local_type[r]; 632 char buf[24]; 633 c_local_name(r, buf, sizeof buf); 634 cbuf_puts(&t->body, " "); 635 cbuf_puts(&t->body, buf); 636 cbuf_puts(&t->body, " = "); 637 if (!c_types_equiv(t, rhs_ty, decl)) { 638 cbuf_putc(&t->body, '('); 639 c_emit_type(t, &t->body, decl); 640 cbuf_putc(&t->body, ')'); 641 if (!c_type_is_float(t, decl) && 642 (!rhs_ty || c_type_is_ptr(t, decl) || c_type_is_ptr(t, rhs_ty))) { 643 cbuf_puts(&t->body, "(uintptr_t)"); 644 } 645 } 646 cbuf_puts(&t->body, "("); 647 } 648 649 static void c_emit_local_assign_close(CTarget* t) { 650 cbuf_puts(&t->body, ");\n"); 651 } 652 653 void c_emit_operand_signed(CTarget* t, Operand op, int signed_) { 654 u32 w = c_int_width_for_signedness(t, op.type); 655 if (w == 0) { 656 /* Not an integer — emit without sign cast. */ 657 c_emit_operand(t, op); 658 return; 659 } 660 const char* tn = c_int_type_name_for_width(w, signed_); 661 if (!tn) { 662 c_emit_operand(t, op); 663 return; 664 } 665 int via_uptr = c_operand_is_ptr_typed(t, op); 666 /* CG ints are width-only; the C target declares every int local/IMM 667 * as the signed `int{W}_t` of its width. So when `signed_` is true and 668 * the operand's emit-width matches `w`, the explicit cast is redundant 669 * with what c_emit_operand already produces. Skipping it cuts the 670 * ubiquitous `((int32_t)((int32_t)23))` double-cast down to one. */ 671 if (!via_uptr && signed_) { 672 KitCgTypeId et = op.type; 673 if (c_int_width_for_signedness(t, et) == w) { 674 c_emit_operand(t, op); 675 return; 676 } 677 } 678 cbuf_puts(&t->body, "(("); 679 cbuf_puts(&t->body, tn); 680 cbuf_puts(&t->body, ")"); 681 if (via_uptr) { 682 cbuf_puts(&t->body, "(uintptr_t)"); 683 } 684 c_emit_operand(t, op); 685 cbuf_puts(&t->body, ")"); 686 } 687 688 /* Returns 1 if `type` is a pointer (or void*). */ 689 static int c_type_is_ptr(CTarget* t, KitCgTypeId type) { 690 if (type == KIT_CG_TYPE_NONE) return 0; 691 const CgType* ty = cg_type_get(t->c, type); 692 return ty && ty->kind == KIT_CG_TYPE_PTR; 693 } 694 695 static int c_type_is_bool(CTarget* t, KitCgTypeId type) { 696 if (type == KIT_CG_TYPE_NONE) return 0; 697 const CgType* ty = cg_type_get(t->c, type); 698 return ty && ty->kind == KIT_CG_TYPE_BOOL; 699 } 700 701 static int c_type_is_aggregate(CTarget* t, KitCgTypeId type) { 702 if (type == KIT_CG_TYPE_NONE) return 0; 703 const CgType* ty = cg_type_get(t->c, type); 704 return ty && 705 (ty->kind == KIT_CG_TYPE_RECORD || ty->kind == KIT_CG_TYPE_ARRAY); 706 } 707 708 static int c_operand_is_ptr_typed(CTarget* t, Operand op) { 709 if (c_type_is_ptr(t, op.type)) return 1; 710 return 0; 711 } 712 713 /* Emit `(target_ty)(uintptr_t)(op)` (or `(target_ty)(op)` for float 714 * target_ty). Used when the caller needs a specific C expression type. 715 * Pointer/int crossings bridge through uintptr_t. */ 716 static void c_emit_operand_as(CTarget* t, Operand op, KitCgTypeId target_ty) { 717 if (c_types_equiv(t, op.type, target_ty)) { 718 c_emit_operand(t, op); 719 return; 720 } 721 cbuf_puts(&t->body, "("); 722 c_emit_type(t, &t->body, target_ty); 723 cbuf_puts(&t->body, ")"); 724 if (!c_type_is_float(t, target_ty) && 725 (!op.type || c_type_is_ptr(t, op.type) || c_type_is_ptr(t, target_ty))) { 726 cbuf_puts(&t->body, "(uintptr_t)"); 727 } 728 cbuf_puts(&t->body, "("); 729 c_emit_operand(t, op); 730 cbuf_puts(&t->body, ")"); 731 } 732 733 /* Emit an operand for use in a C binary arithmetic expression. Pointer-typed 734 * operands are cast to uintptr_t so C arithmetic semantics apply uniformly 735 * (kit IR carries byte offsets, not C-pointer-arith scaled indices). */ 736 static void c_emit_operand_arith(CTarget* t, Operand op) { 737 if (c_operand_is_ptr_typed(t, op)) { 738 cbuf_puts(&t->body, "((uintptr_t)"); 739 if (op.kind == OPK_IMM) { 740 c_emit_imm_literal(t, op.v.imm); 741 } else { 742 c_emit_operand(t, op); 743 } 744 cbuf_puts(&t->body, ")"); 745 return; 746 } 747 c_emit_operand(t, op); 748 } 749 750 /* Same, but applies the requested signedness when the operand is an integer 751 * (used for SDIV/UDIV/SREM/UREM/SHR_S/SHR_U). Pointer operands always go 752 * through the uintptr_t cast regardless of the requested signedness. */ 753 static void c_emit_operand_arith_signed(CTarget* t, Operand op, int signed_) { 754 if (c_operand_is_ptr_typed(t, op)) { 755 cbuf_puts(&t->body, "((uintptr_t)"); 756 if (op.kind == OPK_IMM) { 757 c_emit_imm_literal(t, op.v.imm); 758 } else { 759 c_emit_operand(t, op); 760 } 761 cbuf_puts(&t->body, ")"); 762 return; 763 } 764 c_emit_operand_signed(t, op, signed_); 765 } 766 767 /* Emit a C lvalue expression for an addr operand (OPK_LOCAL / OPK_GLOBAL / 768 * OPK_INDIRECT) using `access_type` as the access type. The result is the 769 * full `*(T*)(...)` dereference, or the C variable directly when the access 770 * type matches the underlying local/global object. */ 771 static void c_emit_addr_deref(CTarget* t, Operand addr, 772 KitCgTypeId access_type) { 773 char buf[24]; 774 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 775 switch (addr.kind) { 776 case OPK_LOCAL: { 777 c_ensure_local(t, addr.v.local, addr.type); 778 c_local_name(addr.v.local, buf, sizeof buf); 779 if (access_type == 0 || addr.type == 0 || access_type == addr.type) { 780 cbuf_puts(&t->body, buf); 781 } else { 782 cbuf_puts(&t->body, "(*("); 783 c_emit_type(t, &t->body, access_type); 784 cbuf_puts(&t->body, "*)&"); 785 cbuf_puts(&t->body, buf); 786 cbuf_puts(&t->body, ")"); 787 } 788 return; 789 } 790 case OPK_GLOBAL: { 791 obj_sym_mark_referenced(t->obj, addr.v.global.sym); 792 const char* nm = c_sym_name(t, addr.v.global.sym); 793 cbuf_puts(&t->body, "(*("); 794 c_emit_type(t, &t->body, access_type); 795 cbuf_puts(&t->body, "*)((char*)&"); 796 cbuf_puts(&t->body, nm); 797 if (addr.v.global.addend != 0) { 798 cbuf_puts(&t->body, " + "); 799 cbuf_put_i64(&t->body, addr.v.global.addend); 800 } 801 cbuf_puts(&t->body, "))"); 802 return; 803 } 804 case OPK_INDIRECT: { 805 CAddrMode m = c_addr_mode(addr); 806 if ((u32)m.base >= t->local_cap || !t->local_declared[m.base]) { 807 compiler_panic(t->c, loc, 808 "C target: indirect on undeclared base local v%u", 809 (unsigned)m.base); 810 } 811 if (m.index != CG_LOCAL_NONE && 812 ((u32)m.index >= t->local_cap || !t->local_declared[m.index])) { 813 compiler_panic(t->c, loc, 814 "C target: indirect on undeclared index local v%u", 815 (unsigned)m.index); 816 } 817 cbuf_puts(&t->body, "(*("); 818 c_emit_type(t, &t->body, access_type); 819 cbuf_puts(&t->body, "*)("); 820 c_emit_indirect_addr_expr(t, m); 821 cbuf_puts(&t->body, "))"); 822 return; 823 } 824 default: 825 compiler_panic(t->c, loc, 826 "C target: addr-deref on operand kind %d not supported", 827 (int)addr.kind); 828 } 829 } 830 831 /* Emit a C address-of expression for a lvalue operand. Output is a pointer 832 * value (cast to dst_type). */ 833 static void c_emit_lvalue_addr(CTarget* t, Operand lv, KitCgTypeId dst_type) { 834 char buf[24]; 835 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 836 switch (lv.kind) { 837 case OPK_LOCAL: 838 cbuf_puts(&t->body, "(("); 839 c_emit_type(t, &t->body, dst_type); 840 cbuf_puts(&t->body, ")"); 841 cbuf_puts(&t->body, "&"); 842 c_ensure_local(t, lv.v.local, lv.type); 843 c_local_name(lv.v.local, buf, sizeof buf); 844 cbuf_puts(&t->body, buf); 845 cbuf_puts(&t->body, ")"); 846 return; 847 case OPK_GLOBAL: { 848 obj_sym_mark_referenced(t->obj, lv.v.global.sym); 849 const char* nm = c_sym_name(t, lv.v.global.sym); 850 cbuf_puts(&t->body, "(("); 851 c_emit_type(t, &t->body, dst_type); 852 cbuf_puts(&t->body, ")((char*)&"); 853 cbuf_puts(&t->body, nm); 854 if (lv.v.global.addend != 0) { 855 cbuf_puts(&t->body, " + "); 856 cbuf_put_i64(&t->body, lv.v.global.addend); 857 } 858 cbuf_puts(&t->body, ")"); 859 cbuf_puts(&t->body, ")"); 860 return; 861 } 862 case OPK_INDIRECT: { 863 cbuf_puts(&t->body, "(("); 864 c_emit_type(t, &t->body, dst_type); 865 cbuf_puts(&t->body, ")("); 866 c_emit_indirect_addr_expr(t, c_addr_mode(lv)); 867 cbuf_puts(&t->body, "))"); 868 return; 869 } 870 default: 871 compiler_panic(t->c, loc, 872 "C target: addr-of on operand kind %d not supported", 873 (int)lv.kind); 874 } 875 } 876 877 /* === Symbol name lookup === */ 878 879 const char* c_sym_name(CTarget* t, ObjSymId sym) { 880 const ObjSym* os = obj_symbol_get(t->obj, sym); 881 if (!os) { 882 compiler_panic(t->c, (SrcLoc){0, 0, 0}, "C target: unknown ObjSymId %u", 883 (unsigned)sym); 884 } 885 Slice nm = pool_slice(t->c->global, os->name); 886 const char* s = nm.s; 887 size_t n = nm.len; 888 /* Linker symbols carry the active object format's C-mangle prefix (a leading 889 * underscore on Mach-O); the host C compiler will re-add it on its own, so 890 * strip when re-emitting source. */ 891 obj_format_demangle_c(t->c, &s, &n); 892 /* Sanitize for C identifier rules: assemblers accept '.', '$', etc. in 893 * symbol names; C does not. Replace each illegal byte with '_' and prepend 894 * '_' if the first char isn't alpha/underscore. Local syms (SB_LOCAL) also 895 * get an ObjSymId prefix: one C emit session may contain several original 896 * source units, each of which may legally define the same internal-linkage 897 * name. Globals are assumed to come in with C-safe names; if they don't, we 898 * still rewrite — the resulting symbol won't link against other TUs that use 899 * the asm spelling, but kit-produced code uses it consistently. */ 900 int is_local = os->bind == SB_LOCAL; 901 int needs_rewrite = is_local; 902 if (n == 0 && !is_local) { 903 return s; 904 } 905 if (n != 0 && !is_local) { 906 if (!((s[0] >= 'a' && s[0] <= 'z') || (s[0] >= 'A' && s[0] <= 'Z') || 907 s[0] == '_')) { 908 needs_rewrite = 1; 909 } 910 for (size_t i = 0; i < n; ++i) { 911 char ch = s[i]; 912 if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 913 (ch >= '0' && ch <= '9') || ch == '_')) { 914 needs_rewrite = 1; 915 break; 916 } 917 } 918 } 919 if (!needs_rewrite) return s; 920 char buf[256]; 921 size_t cap = sizeof(buf) - 1u; 922 size_t out = 0; 923 if (is_local) { 924 static const char prefix[] = "__kit_local_"; 925 char digits[16]; 926 size_t ndigits = 0; 927 u32 value = (u32)sym; 928 for (size_t i = 0; i + 1u < sizeof prefix && out < cap; ++i) 929 buf[out++] = prefix[i]; 930 do { 931 digits[ndigits++] = (char)('0' + value % 10u); 932 value /= 10u; 933 } while (value != 0 && ndigits < sizeof digits); 934 while (ndigits != 0 && out < cap) buf[out++] = digits[--ndigits]; 935 if (out < cap) buf[out++] = '_'; 936 } else { 937 int first_alpha = (s[0] >= 'a' && s[0] <= 'z') || 938 (s[0] >= 'A' && s[0] <= 'Z') || s[0] == '_'; 939 if (!first_alpha && out < cap) buf[out++] = '_'; 940 } 941 for (size_t i = 0; i < n && out < cap; ++i) { 942 char ch = s[i]; 943 int ok = (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 944 (ch >= '0' && ch <= '9') || ch == '_'; 945 buf[out++] = ok ? ch : '_'; 946 } 947 buf[out] = '\0'; 948 Sym interned = pool_intern_slice(t->c->global, (Slice){.s = buf, .len = out}); 949 return pool_slice(t->c->global, interned).s; 950 } 951 952 /* === Prologue / finalize === */ 953 954 void c_emit_prologue(CTarget* t) { 955 if (t->prologue_emitted) return; 956 t->prologue_emitted = 1; 957 c_writer_puts(t, 958 "/* generated by kit --emit=c */\n" 959 "#include <stdint.h>\n" 960 "#include <stdalign.h>\n"); 961 /* Other headers are decided at finalize so include lines remain 962 * deterministic regardless of when the type was first referenced. 963 * Writer flushes are not stream-buffered, so we keep prologue compact and 964 * tack the rest on at c_emit_finalize. */ 965 c_writer_puts(t, "\n"); 966 } 967 968 /* === func_begin / func_end === */ 969 970 /* Write `RetT name(P0, P1, ...)` (without trailing `;` or `{`) to `b`. */ 971 static void c_emit_func_signature(CTarget* t, CBuf* b, const char* name, 972 KitCgTypeId fn_type) { 973 KitCgTypeId ret_type = cg_type_func_ret_id(t->c, fn_type); 974 const CgType* fty = cg_type_get(t->c, fn_type); 975 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 976 if (!fty || fty->kind != KIT_CG_TYPE_FUNC) { 977 compiler_panic(t->c, loc, "C target: fn_type is not a function type"); 978 } 979 if (cg_type_is_void(t->c, ret_type)) { 980 cbuf_puts(b, "void"); 981 } else { 982 c_emit_type(t, b, ret_type); 983 } 984 cbuf_puts(b, " "); 985 cbuf_puts(b, name); 986 cbuf_puts(b, "("); 987 if (fty->func.nparams == 0 && !fty->func.abi_variadic) { 988 cbuf_puts(b, "void"); 989 } else { 990 for (u32 i = 0; i < fty->func.nparams; ++i) { 991 if (i > 0) cbuf_puts(b, ", "); 992 c_emit_type(t, b, fty->func.params[i].type); 993 cbuf_puts(b, " p"); 994 cbuf_put_u64(b, (u64)i); 995 } 996 if (fty->func.abi_variadic) { 997 if (fty->func.nparams > 0) cbuf_puts(b, ", "); 998 cbuf_puts(b, "..."); 999 } 1000 } 1001 cbuf_puts(b, ")"); 1002 } 1003 1004 void c_emit_func_begin(CTarget* t, const CGFuncDesc* fd) { 1005 c_emit_prologue(t); 1006 1007 t->cur_fn = fd; 1008 cbuf_reset(&t->decls); 1009 for (u32 i = 0; i < t->local_cap; ++i) { 1010 t->local_declared[i] = 0; 1011 t->local_type[i] = 0; 1012 } 1013 t->next_label = 0; 1014 t->next_local = 0; 1015 t->next_tmp = 0; 1016 t->nscopes = 0; 1017 t->last_was_terminator = 0; 1018 t->have_emitted_loc = 0; 1019 t->emitted_loc = (SrcLoc){0, 0, 0}; 1020 1021 const char* name = c_sym_name(t, fd->sym); 1022 1023 /* Forward-declare so out-of-order callers and same-TU references find the 1024 * prototype regardless of definition order. */ 1025 c_ensure_forward_decl(t, fd->sym, fd->fn_type); 1026 1027 { 1028 const ObjSym* os = obj_symbol_get(t->obj, fd->sym); 1029 if (os && os->bind == SB_LOCAL) cbuf_puts(&t->body, "static "); 1030 } 1031 c_emit_func_signature(t, &t->body, name, fd->fn_type); 1032 cbuf_puts(&t->body, " {\n"); 1033 t->fn_body_start = t->body.len; 1034 } 1035 1036 /* Test-and-set on the sym_forwarded bitmap, growing it as needed. Returns 1 if 1037 * `sym` was already marked (caller should skip re-emitting its forward decl), 1038 * 0 after marking it for the first time. Shared by c_ensure_forward_decl and 1039 * c_emit_alias, which both emit a decl that doubles as a forward prototype. */ 1040 static int c_sym_forwarded_test_and_set(CTarget* t, ObjSymId sym) { 1041 c_vec_grow_zeroed(t, t->sym_forwarded, t->sym_forwarded_cap, (u32)sym + 1u); 1042 if (t->sym_forwarded[sym]) return 1; 1043 t->sym_forwarded[sym] = 1; 1044 return 0; 1045 } 1046 1047 void c_ensure_forward_decl(CTarget* t, ObjSymId sym, KitCgTypeId fn_type) { 1048 if (c_sym_forwarded_test_and_set(t, sym)) return; 1049 const char* name = c_sym_name(t, sym); 1050 const ObjSym* os = obj_symbol_get(t->obj, sym); 1051 if ((os && (os->kind == SK_FUNC || os->kind == SK_IFUNC)) || fn_type != 0) { 1052 if (os && os->bind == SB_LOCAL) cbuf_puts(&t->forwards, "static "); 1053 c_emit_func_signature(t, &t->forwards, name, fn_type); 1054 cbuf_puts(&t->forwards, ";\n"); 1055 } else { 1056 if (os && os->bind == SB_LOCAL) 1057 cbuf_puts(&t->forwards, "static "); 1058 else 1059 cbuf_puts(&t->forwards, "extern "); 1060 if (os && os->section_id != OBJ_SEC_NONE) { 1061 const Section* sec = obj_section_get(t->obj, os->section_id); 1062 if (sec->kind == SEC_RODATA) cbuf_puts(&t->forwards, "const "); 1063 } 1064 cbuf_puts(&t->forwards, "struct __kit_data_"); 1065 cbuf_puts(&t->forwards, name); 1066 cbuf_puts(&t->forwards, " "); 1067 cbuf_puts(&t->forwards, name); 1068 cbuf_puts(&t->forwards, ";\n"); 1069 } 1070 } 1071 1072 void c_emit_func_end(CTarget* t) { 1073 size_t splice_at = t->fn_body_start; 1074 size_t body_after = t->body.len; 1075 size_t fn_body_len = body_after - splice_at; 1076 Heap* h = t->c->ctx->heap; 1077 1078 u8* tmp = NULL; 1079 if (fn_body_len) { 1080 tmp = (u8*)h->alloc(h, fn_body_len, 1); 1081 if (!tmp) { 1082 compiler_panic(t->c, t->cur_fn->loc, "C target: out of memory"); 1083 } 1084 for (size_t i = 0; i < fn_body_len; ++i) { 1085 tmp[i] = t->body.data[splice_at + i]; 1086 } 1087 } 1088 1089 t->body.len = splice_at; 1090 if (t->decls.len) 1091 cbuf_putn(&t->body, (const char*)t->decls.data, t->decls.len); 1092 if (tmp) { 1093 cbuf_putn(&t->body, (const char*)tmp, fn_body_len); 1094 h->free(h, tmp, fn_body_len); 1095 } 1096 cbuf_puts(&t->body, "}\n\n"); 1097 1098 t->cur_fn = NULL; 1099 } 1100 1101 /* === locals, params === */ 1102 1103 void c_emit_param_bind(CTarget* t, CGLocal local, KitCgTypeId type, u32 index) { 1104 char buf[24]; 1105 c_ensure_local(t, local, type); 1106 c_local_name(local, buf, sizeof buf); 1107 cbuf_puts(&t->body, " "); 1108 cbuf_puts(&t->body, buf); 1109 cbuf_puts(&t->body, " = p"); 1110 cbuf_put_u64(&t->body, (u64)index); 1111 cbuf_puts(&t->body, ";\n"); 1112 } 1113 1114 CGLocal c_emit_param(CTarget* t, const CGParamDesc* pd) { 1115 CGLocalDesc d; 1116 memset(&d, 0, sizeof d); 1117 d.type = pd->type; 1118 d.name = pd->name; 1119 d.loc = pd->loc; 1120 d.size = pd->size; 1121 d.align = pd->align; 1122 d.flags = pd->flags; 1123 CGLocal local = c_emit_local(t, &d); 1124 c_emit_param_bind(t, local, pd->type, pd->index); 1125 return local; 1126 } 1127 1128 /* === load_imm, copy, binop === */ 1129 1130 void c_emit_load_imm(CTarget* t, Operand dst, i64 imm) { 1131 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1132 if (dst.kind != OPK_LOCAL) { 1133 compiler_panic(t->c, loc, "C target: load_imm dst must be LOCAL"); 1134 } 1135 c_ensure_local(t, dst.v.local, dst.type); 1136 /* The literal is emitted bare; its C type is `long long`. We can drop 1137 * the bridge cast iff the bare assignment compiles cleanly: 1138 * - integer dst: imm must fit in dst's signed range (else 1139 * -Wconstant-conversion). 64-bit dst always fits. 1140 * - pointer dst: only `0` (null pointer constant) is safe; any other 1141 * literal trips -Wint-conversion. 1142 * Otherwise keep the bridge. */ 1143 u32 w = c_int_width_for_signedness(t, dst.type); 1144 int can_drop_bridge; 1145 if (w > 0) { 1146 can_drop_bridge = (w >= 64) || (imm >= -((i64)1 << (w - 1)) && 1147 imm <= (((i64)1 << (w - 1)) - 1)); 1148 } else if (c_type_is_ptr(t, dst.type)) { 1149 can_drop_bridge = (imm == 0); 1150 } else { 1151 can_drop_bridge = 0; 1152 } 1153 c_emit_local_assign_open(t, dst.v.local, 1154 can_drop_bridge ? dst.type : (KitCgTypeId)0); 1155 c_emit_imm_literal(t, imm); 1156 c_emit_local_assign_close(t); 1157 } 1158 1159 void c_emit_copy(CTarget* t, Operand dst, Operand src) { 1160 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1161 if (dst.kind != OPK_LOCAL) { 1162 compiler_panic(t->c, loc, "C target: copy dst must be LOCAL"); 1163 } 1164 c_ensure_local(t, dst.v.local, dst.type); 1165 c_emit_local_assign_open(t, dst.v.local, src.type); 1166 c_emit_operand(t, src); 1167 c_emit_local_assign_close(t); 1168 } 1169 1170 static const char* binop_to_c(BinOp op) { 1171 switch (op) { 1172 case BO_IADD: 1173 case BO_FADD: 1174 return "+"; 1175 case BO_ISUB: 1176 case BO_FSUB: 1177 return "-"; 1178 case BO_IMUL: 1179 case BO_FMUL: 1180 return "*"; 1181 case BO_SDIV: 1182 case BO_UDIV: 1183 case BO_FDIV: 1184 return "/"; 1185 case BO_SREM: 1186 case BO_UREM: 1187 return "%"; 1188 case BO_AND: 1189 return "&"; 1190 case BO_OR: 1191 return "|"; 1192 case BO_XOR: 1193 return "^"; 1194 case BO_SHL: 1195 return "<<"; 1196 case BO_SHR_S: 1197 case BO_SHR_U: 1198 return ">>"; 1199 } 1200 return NULL; 1201 } 1202 1203 /* For BinOp `op`, decide how to sign-cast the operands. Returns 0 for "no 1204 * cast", 1 for "cast both to signed", 2 for "cast both to unsigned", 3 for 1205 * "cast lhs only (signedness `lhs_signed`)" (used for shifts). */ 1206 typedef enum { BSC_NONE, BSC_SIGNED, BSC_UNSIGNED, BSC_SHIFT_LHS } BinSignCast; 1207 1208 static BinSignCast binop_sign_kind(BinOp op, int* lhs_signed_out) { 1209 *lhs_signed_out = 1; 1210 switch (op) { 1211 case BO_SDIV: 1212 case BO_SREM: 1213 return BSC_SIGNED; 1214 case BO_UDIV: 1215 case BO_UREM: 1216 return BSC_UNSIGNED; 1217 case BO_SHR_S: 1218 *lhs_signed_out = 1; 1219 return BSC_SHIFT_LHS; 1220 case BO_SHR_U: 1221 *lhs_signed_out = 0; 1222 return BSC_SHIFT_LHS; 1223 default: 1224 return BSC_NONE; 1225 } 1226 } 1227 1228 void c_emit_binop(CTarget* t, BinOp op, Operand dst, Operand a, Operand b) { 1229 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1230 const char* sym = binop_to_c(op); 1231 if (!sym) { 1232 compiler_panic(t->c, loc, "C target: unknown binop %d", (int)op); 1233 } 1234 if (dst.kind != OPK_LOCAL) { 1235 compiler_panic(t->c, loc, "C target: binop dst must be LOCAL"); 1236 } 1237 c_ensure_local(t, dst.v.local, dst.type); 1238 /* Pointer operands get cast to uintptr_t inside c_emit_operand_arith, 1239 * so the binop's C result type is `uintptr_t`, not the original pointer 1240 * type. Keep the bridge when dst or either operand is pointer-typed so 1241 * the assignment back to a pointer dst doesn't trip -Wint-conversion. */ 1242 int has_ptr = c_operand_is_ptr_typed(t, dst) || 1243 c_operand_is_ptr_typed(t, a) || c_operand_is_ptr_typed(t, b); 1244 c_emit_local_assign_open(t, dst.v.local, has_ptr ? (KitCgTypeId)0 : dst.type); 1245 int lhs_signed = 1; 1246 BinSignCast bsc = binop_sign_kind(op, &lhs_signed); 1247 switch (bsc) { 1248 case BSC_NONE: 1249 c_emit_operand_arith(t, a); 1250 cbuf_puts(&t->body, " "); 1251 cbuf_puts(&t->body, sym); 1252 cbuf_puts(&t->body, " "); 1253 c_emit_operand_arith(t, b); 1254 break; 1255 case BSC_SIGNED: 1256 c_emit_operand_arith_signed(t, a, 1); 1257 cbuf_puts(&t->body, " "); 1258 cbuf_puts(&t->body, sym); 1259 cbuf_puts(&t->body, " "); 1260 c_emit_operand_arith_signed(t, b, 1); 1261 break; 1262 case BSC_UNSIGNED: 1263 c_emit_operand_arith_signed(t, a, 0); 1264 cbuf_puts(&t->body, " "); 1265 cbuf_puts(&t->body, sym); 1266 cbuf_puts(&t->body, " "); 1267 c_emit_operand_arith_signed(t, b, 0); 1268 break; 1269 case BSC_SHIFT_LHS: 1270 c_emit_operand_arith_signed(t, a, lhs_signed); 1271 cbuf_puts(&t->body, " "); 1272 cbuf_puts(&t->body, sym); 1273 cbuf_puts(&t->body, " "); 1274 c_emit_operand(t, b); 1275 break; 1276 } 1277 c_emit_local_assign_close(t); 1278 } 1279 1280 /* ===== unop ===== */ 1281 1282 void c_emit_unop(CTarget* t, UnOp op, Operand dst, Operand a) { 1283 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1284 if (dst.kind != OPK_LOCAL) { 1285 compiler_panic(t->c, loc, "C target: unop dst must be LOCAL"); 1286 } 1287 c_ensure_local(t, dst.v.local, dst.type); 1288 const char* sym = NULL; 1289 switch (op) { 1290 case UO_NEG: 1291 case UO_FNEG: 1292 sym = "-"; 1293 break; 1294 case UO_NOT: 1295 sym = "!"; 1296 break; 1297 case UO_BNOT: 1298 sym = "~"; 1299 break; 1300 default: 1301 compiler_panic(t->c, loc, "C target: unknown unop %d", (int)op); 1302 } 1303 c_emit_local_assign_open(t, dst.v.local, dst.type); 1304 cbuf_puts(&t->body, sym); 1305 c_emit_operand(t, a); 1306 c_emit_local_assign_close(t); 1307 } 1308 1309 /* ===== compare ops ===== */ 1310 1311 /* The single C operator for ops that lower to one relational/equality 1312 * expression: all integer ops, plus the FP predicates whose plain C operator 1313 * already has the right NaN behavior (<,<=,>,>= and == are ordered: false on 1314 * NaN; != is unordered: true on NaN). The remaining FP predicates need a 1315 * compound expression and are handled in c_emit_cmp_operands; they return NULL 1316 * here. No `default:` so -Wswitch flags any unhandled enumerator. */ 1317 static const char* cmp_to_c(CmpOp op) { 1318 switch (op) { 1319 case CMP_EQ: 1320 case CMP_OEQ_F: 1321 return "=="; 1322 case CMP_NE: 1323 case CMP_UNE_F: 1324 return "!="; 1325 case CMP_LT_S: 1326 case CMP_LT_U: 1327 case CMP_OLT_F: 1328 return "<"; 1329 case CMP_LE_S: 1330 case CMP_LE_U: 1331 case CMP_OLE_F: 1332 return "<="; 1333 case CMP_GT_S: 1334 case CMP_GT_U: 1335 case CMP_OGT_F: 1336 return ">"; 1337 case CMP_GE_S: 1338 case CMP_GE_U: 1339 case CMP_OGE_F: 1340 return ">="; 1341 /* Compound FP predicates — no single C operator (see c_emit_cmp_operands). 1342 */ 1343 case CMP_ONE_F: 1344 case CMP_UEQ_F: 1345 case CMP_ULT_F: 1346 case CMP_ULE_F: 1347 case CMP_UGT_F: 1348 case CMP_UGE_F: 1349 return NULL; 1350 } 1351 return NULL; 1352 } 1353 1354 /* The 6 FP predicates with no single C operator: built from compound ordered 1355 * comparisons (no isnan(); host must not be built with -ffast-math). */ 1356 static int cmp_is_fp_compound(CmpOp op) { 1357 return op == CMP_ONE_F || op == CMP_UEQ_F || op == CMP_ULT_F || 1358 op == CMP_ULE_F || op == CMP_UGT_F || op == CMP_UGE_F; 1359 } 1360 1361 /* Returns 1 if cmp op needs unsigned operand cast. -1 if signed. 0 if no cast 1362 * (EQ/NE — sign doesn't matter for integer equality at the same width — and 1363 * float compares). */ 1364 static int cmp_signedness(CmpOp op) { 1365 switch (op) { 1366 case CMP_LT_S: 1367 case CMP_LE_S: 1368 case CMP_GT_S: 1369 case CMP_GE_S: 1370 return -1; 1371 case CMP_LT_U: 1372 case CMP_LE_U: 1373 case CMP_GT_U: 1374 case CMP_GE_U: 1375 return 1; 1376 default: 1377 return 0; 1378 } 1379 } 1380 1381 /* Emit one ordered comparison `<a> opstr <b>` (no signedness cast — FP). */ 1382 static void c_emit_fp_rel(CTarget* t, Operand a, const char* opstr, Operand b) { 1383 c_emit_operand_arith(t, a); 1384 cbuf_puts(&t->body, " "); 1385 cbuf_puts(&t->body, opstr); 1386 cbuf_puts(&t->body, " "); 1387 c_emit_operand_arith(t, b); 1388 } 1389 1390 static void c_emit_cmp_operands(CTarget* t, CmpOp op, Operand a, Operand b) { 1391 /* The 6 FP predicates without a single C operator. Composed from ordered 1392 * comparisons via unordered-R == !(ordered-not-R); ONE/UEQ from a<b / a>b. 1393 * Each `!(...)` / `(...)` wraps the full cast-bearing comparison. */ 1394 switch (op) { 1395 case CMP_UGE_F: /* !(OLT) */ 1396 cbuf_puts(&t->body, "!("); 1397 c_emit_fp_rel(t, a, "<", b); 1398 cbuf_puts(&t->body, ")"); 1399 return; 1400 case CMP_UGT_F: /* !(OLE) */ 1401 cbuf_puts(&t->body, "!("); 1402 c_emit_fp_rel(t, a, "<=", b); 1403 cbuf_puts(&t->body, ")"); 1404 return; 1405 case CMP_ULE_F: /* !(OGT) */ 1406 cbuf_puts(&t->body, "!("); 1407 c_emit_fp_rel(t, a, ">", b); 1408 cbuf_puts(&t->body, ")"); 1409 return; 1410 case CMP_ULT_F: /* !(OGE) */ 1411 cbuf_puts(&t->body, "!("); 1412 c_emit_fp_rel(t, a, ">=", b); 1413 cbuf_puts(&t->body, ")"); 1414 return; 1415 case CMP_ONE_F: /* ordered & !=: a<b || a>b */ 1416 cbuf_puts(&t->body, "("); 1417 c_emit_fp_rel(t, a, "<", b); 1418 cbuf_puts(&t->body, " || "); 1419 c_emit_fp_rel(t, a, ">", b); 1420 cbuf_puts(&t->body, ")"); 1421 return; 1422 case CMP_UEQ_F: /* unordered | ==: !(a<b) && !(a>b) */ 1423 cbuf_puts(&t->body, "(!("); 1424 c_emit_fp_rel(t, a, "<", b); 1425 cbuf_puts(&t->body, ") && !("); 1426 c_emit_fp_rel(t, a, ">", b); 1427 cbuf_puts(&t->body, "))"); 1428 return; 1429 default: 1430 break; /* integer ops + single-operator FP fall through */ 1431 } 1432 int sg = cmp_signedness(op); 1433 if (sg == 0) { 1434 c_emit_operand_arith(t, a); 1435 cbuf_puts(&t->body, " "); 1436 cbuf_puts(&t->body, cmp_to_c(op)); 1437 cbuf_puts(&t->body, " "); 1438 c_emit_operand_arith(t, b); 1439 } else { 1440 int signed_ = (sg < 0); 1441 c_emit_operand_arith_signed(t, a, signed_); 1442 cbuf_puts(&t->body, " "); 1443 cbuf_puts(&t->body, cmp_to_c(op)); 1444 cbuf_puts(&t->body, " "); 1445 c_emit_operand_arith_signed(t, b, signed_); 1446 } 1447 } 1448 1449 void c_emit_cmp(CTarget* t, CmpOp op, Operand dst, Operand a, Operand b) { 1450 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1451 if (dst.kind != OPK_LOCAL) { 1452 compiler_panic(t->c, loc, "C target: cmp dst must be LOCAL"); 1453 } 1454 if (!cmp_to_c(op) && !cmp_is_fp_compound(op)) { 1455 compiler_panic(t->c, loc, "C target: unknown cmp %d", (int)op); 1456 } 1457 c_ensure_local(t, dst.v.local, dst.type); 1458 /* Compare result is C `int` (0/1); assigning to integer dst.type narrows 1459 * implicitly without -Wall complaint. The result of a `!(...)` / `||` / `&&` 1460 * compound FP predicate is already an int 0/1. */ 1461 c_emit_local_assign_open(t, dst.v.local, dst.type); 1462 c_emit_cmp_operands(t, op, a, b); 1463 c_emit_local_assign_close(t); 1464 } 1465 1466 /* ===== labels, jump, cmp_branch ===== */ 1467 1468 static void c_label_name(Label l, char* out, size_t cap) { 1469 size_t i = 0; 1470 if (cap == 0) return; 1471 const char* p = "L"; 1472 while (*p && i + 1 < cap) out[i++] = *p++; 1473 char tmp[16]; 1474 size_t n = 0; 1475 u32 v = (u32)l; 1476 if (v == 0) { 1477 tmp[n++] = '0'; 1478 } else { 1479 while (v) { 1480 tmp[n++] = (char)('0' + (v % 10)); 1481 v /= 10; 1482 } 1483 } 1484 while (n && i + 1 < cap) out[i++] = tmp[--n]; 1485 out[i] = '\0'; 1486 } 1487 1488 Label c_emit_label_new(CTarget* t) { 1489 t->next_label += 1; 1490 return (Label)t->next_label; 1491 } 1492 1493 void c_emit_label_place(CTarget* t, Label l) { 1494 char buf[24]; 1495 c_label_name(l, buf, sizeof buf); 1496 /* `Lk: __attribute__((unused));` — empty stmt keeps it valid at end-of-block, 1497 * and the attribute silences -Wunused-label when the goto got folded away. */ 1498 cbuf_puts(&t->body, " "); 1499 cbuf_puts(&t->body, buf); 1500 cbuf_puts(&t->body, ": __attribute__((unused));\n"); 1501 t->last_was_terminator = 0; 1502 } 1503 1504 /* If `l` is the innermost structured scope's break/continue label, return 1505 * the C keyword that exits/iterates that scope (a literal `break` or 1506 * `continue`). NULL means "fall back to goto." Matches only the innermost 1507 * scope because C `break`/`continue` only escape the nearest enclosing 1508 * loop/switch — outer-scope targets must stay as goto. */ 1509 static const char* c_scope_kw_for_label(CTarget* t, Label l) { 1510 if (t->nscopes == 0) return NULL; 1511 const CScopeInfo* s = &t->scopes[t->nscopes - 1u]; 1512 if (!s->structured) return NULL; 1513 if (l == s->break_label) return "break"; 1514 if (l == s->continue_label) return "continue"; 1515 return NULL; 1516 } 1517 1518 void c_emit_jump(CTarget* t, Label l) { 1519 if (t->last_was_terminator) return; 1520 const char* kw = c_scope_kw_for_label(t, l); 1521 if (kw) { 1522 cbuf_puts(&t->body, " "); 1523 cbuf_puts(&t->body, kw); 1524 cbuf_puts(&t->body, ";\n"); 1525 } else { 1526 char buf[24]; 1527 c_label_name(l, buf, sizeof buf); 1528 cbuf_puts(&t->body, " goto "); 1529 cbuf_puts(&t->body, buf); 1530 cbuf_puts(&t->body, ";\n"); 1531 } 1532 t->last_was_terminator = 1; 1533 } 1534 1535 void c_emit_cmp_branch(CTarget* t, CmpOp op, Operand a, Operand b, Label l) { 1536 if (t->last_was_terminator) return; 1537 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1538 if (!cmp_to_c(op) && !cmp_is_fp_compound(op)) { 1539 compiler_panic(t->c, loc, "C target: unknown cmp %d", (int)op); 1540 } 1541 const char* kw = c_scope_kw_for_label(t, l); 1542 cbuf_puts(&t->body, " if ("); 1543 c_emit_cmp_operands(t, op, a, b); 1544 if (kw) { 1545 cbuf_puts(&t->body, ") "); 1546 cbuf_puts(&t->body, kw); 1547 cbuf_puts(&t->body, ";\n"); 1548 } else { 1549 char buf[24]; 1550 c_label_name(l, buf, sizeof buf); 1551 cbuf_puts(&t->body, ") goto "); 1552 cbuf_puts(&t->body, buf); 1553 cbuf_puts(&t->body, ";\n"); 1554 } 1555 } 1556 1557 /* ===== scopes ===== 1558 * 1559 * SCOPE_LOOP maps to C's `for (;;) { ... }`. CG places the continue label 1560 * just before `scope_begin` and the break label just before `scope_end` 1561 * (see src/cg/control.c:208,253). The C target leaves those label 1562 * placements in the body — they sit just before `for (;;) {` and just 1563 * after `}` respectively, so any outer-scope `goto continue_lbl` or 1564 * `goto break_lbl` (e.g. a nested loop's `continue` targeting this 1565 * outer loop) still resolves. Inside the `for` body, `c_jump` and 1566 * `c_cmp_branch` translate jumps whose target is the *innermost* scope's 1567 * break/continue label into `break;` / `continue;`; outer-scope targets 1568 * fall back to `goto`. The redundant `Lk: ;` adjacent to the `for` is 1569 * cosmetic; gcc/clang fold it. */ 1570 1571 static void c_grow_scopes(CTarget* t, u32 needed) { 1572 c_vec_grow_or_panic(t, t->scopes, t->scopes_cap, needed); 1573 } 1574 1575 CGScope c_emit_scope_begin(CTarget* t, const CGScopeDesc* d) { 1576 if (t->nscopes + 1u >= t->scopes_cap) c_grow_scopes(t, t->nscopes + 2u); 1577 u32 idx = t->nscopes; 1578 t->scopes[idx].kind = d->kind; 1579 t->scopes[idx].break_label = d->break_label; 1580 t->scopes[idx].continue_label = d->continue_label; 1581 t->scopes[idx].structured = 0; 1582 t->nscopes += 1u; 1583 if (d->kind == SCOPE_LOOP) { 1584 cbuf_puts(&t->body, " for (;;) {\n"); 1585 t->scopes[idx].structured = 1; 1586 t->last_was_terminator = 0; 1587 return (CGScope)(idx + 1u); 1588 } 1589 return (CGScope)(idx + 1u); 1590 } 1591 1592 void c_emit_scope_end(CTarget* t, CGScope s) { 1593 if (s == 0 || (u32)s > t->nscopes) { 1594 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 1595 "C target: scope_end on invalid handle"); 1596 } 1597 u32 idx = (u32)s - 1u; 1598 if (t->scopes[idx].structured) { 1599 /* CG places break_label just before scope_end, so the label sits 1600 * inside the for-body. Anything that lands on it (including a 1601 * `goto break_lbl` from a nested scope's labeled break) needs to 1602 * exit the for — without an explicit `break;`, fall-through would 1603 * iterate again. Always emit; if the body already terminated the 1604 * defensive break is dead but harmless. */ 1605 cbuf_puts(&t->body, " break;\n"); 1606 cbuf_puts(&t->body, " }\n"); 1607 /* The closing brace is not a terminator; control can fall through it 1608 * (e.g., off the end of a void function). */ 1609 t->last_was_terminator = 0; 1610 } 1611 t->nscopes -= 1u; 1612 } 1613 1614 void c_emit_break_to(CTarget* t, CGScope s) { 1615 if (s == 0 || (u32)s > t->nscopes) { 1616 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 1617 "C target: break_to on invalid handle"); 1618 } 1619 c_emit_jump(t, t->scopes[s - 1u].break_label); 1620 } 1621 1622 void c_emit_continue_to(CTarget* t, CGScope s) { 1623 if (s == 0 || (u32)s > t->nscopes) { 1624 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 1625 "C target: continue_to on invalid handle"); 1626 } 1627 c_emit_jump(t, t->scopes[s - 1u].continue_label); 1628 } 1629 1630 /* ===== switch dispatch ===== */ 1631 1632 /* Emit `case <value>:`. For an int32_t selector the bare literal is 1633 * already the right type, so we skip the cast; for wider/narrower 1634 * integers we wrap in `(T)` so the case constant matches the switch 1635 * value's promoted type (avoids -Wswitch warnings on narrower 1636 * selectors). */ 1637 static void c_emit_case_value(CTarget* t, KitCgTypeId sel_ty, u64 v) { 1638 u32 w = c_int_width_for_signedness(t, sel_ty); 1639 cbuf_puts(&t->body, " case "); 1640 if (w != 0 && w != 32) { 1641 cbuf_putc(&t->body, '('); 1642 c_emit_type(t, &t->body, sel_ty); 1643 cbuf_puts(&t->body, ")"); 1644 } 1645 c_emit_imm_literal(t, (i64)v); 1646 cbuf_puts(&t->body, ":"); 1647 } 1648 1649 void c_emit_switch_( 1650 CTarget* t, const CGSwitchDesc* d) { /* gcc/clang ignore strategy hints and 1651 pick their own dispatch shape. */ 1652 (void)d->hint; 1653 if (t->last_was_terminator) return; 1654 cbuf_puts(&t->body, " switch ("); 1655 c_emit_operand(t, d->selector); 1656 cbuf_puts(&t->body, ") {\n"); 1657 for (u32 i = 0; i < d->ncases; ++i) { 1658 char buf[24]; 1659 c_label_name(d->cases[i].label, buf, sizeof buf); 1660 c_emit_case_value(t, d->selector.type, d->cases[i].value); 1661 cbuf_puts(&t->body, " goto "); 1662 cbuf_puts(&t->body, buf); 1663 cbuf_puts(&t->body, ";\n"); 1664 } 1665 cbuf_puts(&t->body, " default: "); 1666 if (d->default_label != (Label)LABEL_NONE) { 1667 char buf[24]; 1668 c_label_name(d->default_label, buf, sizeof buf); 1669 cbuf_puts(&t->body, "goto "); 1670 cbuf_puts(&t->body, buf); 1671 cbuf_puts(&t->body, ";\n"); 1672 } else { 1673 /* No default supplied — the kit IR's contract for that case is 1674 * "if no case matches, fall through." `break;` does exactly that 1675 * inside the for-wrapper around structured scopes. */ 1676 cbuf_puts(&t->body, "break;\n"); 1677 } 1678 cbuf_puts(&t->body, " }\n"); 1679 /* The switch always transfers control (every arm jumps or breaks). 1680 * Mark as terminator so any frontend-emitted defensive jump after 1681 * dispatch is dropped. */ 1682 t->last_was_terminator = 1; 1683 } 1684 1685 /* ===== load_label_addr / indirect_branch ===== 1686 * GCC computed-goto extension: `&&L` is the address of label L within 1687 * the current function, and `goto *p;` jumps to such an address. This 1688 * is the lowering every cc1-like backend uses (and what the toy 1689 * frontend ultimately compiles to via the C target). */ 1690 void c_emit_load_label_addr(CTarget* t, Operand dst, Label l) { 1691 char buf[24]; 1692 if (dst.kind != OPK_LOCAL) { 1693 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 1694 "C target: load_label_addr dst must be LOCAL"); 1695 } 1696 c_ensure_local(t, dst.v.local, dst.type); 1697 c_emit_local_assign_open(t, dst.v.local, (KitCgTypeId)0); 1698 cbuf_puts(&t->body, "(void*)&&"); 1699 c_label_name(l, buf, sizeof buf); 1700 cbuf_puts(&t->body, buf); 1701 c_emit_local_assign_close(t); 1702 } 1703 1704 void c_emit_indirect_branch(CTarget* t, Operand addr, 1705 const Label* valid_targets, u32 ntargets) { 1706 (void)valid_targets; 1707 (void)ntargets; 1708 if (t->last_was_terminator) return; 1709 cbuf_puts(&t->body, " goto *"); 1710 c_emit_operand(t, addr); 1711 cbuf_puts(&t->body, ";\n"); 1712 t->last_was_terminator = 1; 1713 } 1714 1715 /* ===== function-local static label-address data ===== */ 1716 1717 static int c_is_local_static_sym(CTarget* t, ObjSymId sym) { 1718 for (u32 i = 0; i < t->local_static_nsyms; ++i) { 1719 if (t->local_static_syms[i] == sym) return 1; 1720 } 1721 return 0; 1722 } 1723 1724 static void c_mark_local_static_sym(CTarget* t, ObjSymId sym) { 1725 if (sym == OBJ_SYM_NONE || c_is_local_static_sym(t, sym)) return; 1726 /* Append-style: VEC_GROW for the doubling realloc, but keep the 1727 * cur_fn-relative panic location this path uses on OOM. */ 1728 if (VEC_GROW(t->c->ctx->heap, t->local_static_syms, t->local_static_syms_cap, 1729 t->local_static_nsyms + 1u)) { 1730 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 1731 "C target: out of memory"); 1732 } 1733 t->local_static_syms[t->local_static_nsyms++] = sym; 1734 } 1735 1736 static void c_grow_local_static_entries(CTarget* t, u32 want) { 1737 /* Append-style (the caller initializes the [0, count) entries after this 1738 * grows): VEC_GROW for the doubling realloc, with the cur_fn-relative panic 1739 * location this path uses on OOM. */ 1740 if (VEC_GROW(t->c->ctx->heap, t->local_static_entries, 1741 t->local_static_entries_cap, want)) { 1742 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 1743 "C target: out of memory"); 1744 } 1745 } 1746 1747 int c_emit_can_local_static_data(CTarget* t, 1748 const CGLocalStaticDataDesc* desc) { 1749 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1750 const CgType* ty = cg_type_get(t->c, desc->type); 1751 if (!ty) { 1752 compiler_panic(t->c, loc, "C target: unknown local static type %u", 1753 (unsigned)desc->type); 1754 } 1755 if (ty->kind == KIT_CG_TYPE_ARRAY) { 1756 ty = cg_type_get(t->c, ty->array.elem); 1757 } 1758 return ty && ty->kind == KIT_CG_TYPE_PTR; 1759 } 1760 1761 int c_emit_local_static_data_begin(CTarget* t, 1762 const CGLocalStaticDataDesc* desc) { 1763 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1764 if (!t->cur_fn) { 1765 compiler_panic(t->c, loc, 1766 "C target: function-local static data outside function"); 1767 } 1768 if (t->local_static_active) { 1769 compiler_panic(t->c, loc, 1770 "C target: nested function-local static data definition"); 1771 } 1772 const CgType* ty = cg_type_get(t->c, desc->type); 1773 if (!ty) { 1774 compiler_panic(t->c, loc, "C target: unknown local static type %u", 1775 (unsigned)desc->type); 1776 } 1777 1778 u64 count = 1; 1779 int is_array = 0; 1780 KitCgTypeId elem = desc->type; 1781 if (ty->kind == KIT_CG_TYPE_ARRAY) { 1782 is_array = 1; 1783 count = ty->array.count; 1784 elem = ty->array.elem; 1785 ty = cg_type_get(t->c, elem); 1786 } 1787 if (!c_emit_can_local_static_data(t, desc)) { 1788 return 0; 1789 } 1790 if (count > UINT32_MAX) { 1791 compiler_panic(t->c, loc, "C target: local static pointer table too large"); 1792 } 1793 1794 c_grow_local_static_entries(t, (u32)count); 1795 for (u32 i = 0; i < (u32)count; ++i) { 1796 t->local_static_entries[i].label = LABEL_NONE; 1797 t->local_static_entries[i].addend = 0; 1798 t->local_static_entries[i].has_label = 0; 1799 } 1800 t->local_static_nentries = (u32)count; 1801 t->local_static_sym = desc->sym; 1802 t->local_static_type = desc->type; 1803 t->local_static_count = count; 1804 t->local_static_offset = 0; 1805 t->local_static_ptr_width = (u32)cg_type_size(t->c, elem); 1806 t->local_static_align = 1807 desc->align ? desc->align : cg_type_align(t->c, desc->type); 1808 t->local_static_active = 1; 1809 t->local_static_is_array = (u8)is_array; 1810 t->local_static_readonly = 1811 (desc->attrs.flags & KIT_CG_DATADEF_READONLY) ? 1u : 0u; 1812 c_mark_local_static_sym(t, desc->sym); 1813 return 1; 1814 } 1815 1816 void c_emit_local_static_data_write(CTarget* t, const u8* data, u64 len) { 1817 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1818 if (!t->local_static_active || !len) return; 1819 if (data) { 1820 for (u64 i = 0; i < len; ++i) { 1821 if (data[i] != 0) { 1822 compiler_panic(t->c, loc, 1823 "C target: function-local static label table supports " 1824 "only zero bytes and label addresses"); 1825 } 1826 } 1827 } 1828 t->local_static_offset += len; 1829 } 1830 1831 void c_emit_local_static_data_label_addr(CTarget* t, Label target, i64 addend, 1832 u32 width, u32 address_space) { 1833 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1834 (void)address_space; 1835 if (!t->local_static_active) { 1836 compiler_panic(t->c, loc, 1837 "C target: label address outside local static data"); 1838 } 1839 if (width != t->local_static_ptr_width) { 1840 compiler_panic(t->c, loc, 1841 "C target: label address width %u does not match pointer " 1842 "width %u", 1843 (unsigned)width, (unsigned)t->local_static_ptr_width); 1844 } 1845 if ((t->local_static_offset % t->local_static_ptr_width) != 0) { 1846 compiler_panic(t->c, loc, 1847 "C target: unaligned label address in local static data"); 1848 } 1849 u64 idx = t->local_static_offset / t->local_static_ptr_width; 1850 if (idx >= t->local_static_count) { 1851 compiler_panic(t->c, loc, 1852 "C target: too many local static label table entries"); 1853 } 1854 CLocalStaticLabelEntry* e = &t->local_static_entries[(u32)idx]; 1855 if (e->has_label) { 1856 compiler_panic(t->c, loc, 1857 "C target: duplicate local static label table entry"); 1858 } 1859 e->label = target; 1860 e->addend = addend; 1861 e->has_label = 1; 1862 t->local_static_offset += width; 1863 } 1864 1865 static void c_emit_local_static_label_expr(CTarget* t, 1866 const CLocalStaticLabelEntry* e) { 1867 char lbuf[24]; 1868 if (!e->has_label) { 1869 cbuf_puts(&t->decls, "(void*)0"); 1870 return; 1871 } 1872 if (e->addend == 0) { 1873 cbuf_puts(&t->decls, "&&"); 1874 c_label_name(e->label, lbuf, sizeof lbuf); 1875 cbuf_puts(&t->decls, lbuf); 1876 return; 1877 } 1878 cbuf_puts(&t->decls, "(void*)((char*)&&"); 1879 c_label_name(e->label, lbuf, sizeof lbuf); 1880 cbuf_puts(&t->decls, lbuf); 1881 cbuf_puts(&t->decls, " + "); 1882 cbuf_put_i64(&t->decls, e->addend); 1883 cbuf_puts(&t->decls, ")"); 1884 } 1885 1886 void c_emit_local_static_data_end(CTarget* t) { 1887 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1888 if (!t->local_static_active) return; 1889 u64 total_size = t->local_static_count * t->local_static_ptr_width; 1890 if (t->local_static_offset > total_size) { 1891 compiler_panic(t->c, loc, 1892 "C target: local static initializer exceeds object size"); 1893 } 1894 const char* nm = c_sym_name(t, t->local_static_sym); 1895 cbuf_puts(&t->decls, " static __attribute__((unused)) "); 1896 cbuf_puts(&t->decls, "_Alignas("); 1897 cbuf_put_u64(&t->decls, t->local_static_align ? t->local_static_align : 1); 1898 cbuf_puts(&t->decls, ") void* "); 1899 if (t->local_static_readonly) cbuf_puts(&t->decls, "const "); 1900 cbuf_puts(&t->decls, nm); 1901 if (t->local_static_is_array) { 1902 cbuf_puts(&t->decls, "["); 1903 cbuf_put_u64(&t->decls, t->local_static_count); 1904 cbuf_puts(&t->decls, "]"); 1905 } 1906 cbuf_puts(&t->decls, " = {"); 1907 for (u32 i = 0; i < t->local_static_nentries; ++i) { 1908 if (i > 0) cbuf_putc(&t->decls, ','); 1909 if ((i & 3u) == 0) cbuf_puts(&t->decls, "\n "); 1910 c_emit_local_static_label_expr(t, &t->local_static_entries[i]); 1911 } 1912 cbuf_puts(&t->decls, "\n };\n"); 1913 1914 t->local_static_active = 0; 1915 t->local_static_sym = OBJ_SYM_NONE; 1916 t->local_static_type = KIT_CG_TYPE_NONE; 1917 t->local_static_count = 0; 1918 t->local_static_offset = 0; 1919 t->local_static_ptr_width = 0; 1920 t->local_static_align = 0; 1921 t->local_static_nentries = 0; 1922 t->local_static_is_array = 0; 1923 t->local_static_readonly = 0; 1924 } 1925 1926 /* ===== local, local_addr ===== */ 1927 1928 CGLocal c_emit_local(CTarget* t, const CGLocalDesc* d) { 1929 t->next_local += 1u; 1930 if (t->next_local == CG_LOCAL_NONE) { 1931 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 1932 "C target: semantic local id exhausted"); 1933 return CG_LOCAL_NONE; 1934 } 1935 c_ensure_local(t, (CGLocal)t->next_local, d->type); 1936 return (CGLocal)t->next_local; 1937 } 1938 1939 void c_emit_local_addr(CTarget* t, Operand dst, const CGLocalDesc* d, 1940 CGLocal s) { 1941 (void)d; 1942 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1943 if (dst.kind != OPK_LOCAL) { 1944 compiler_panic(t->c, loc, "C target: local_addr dst must be LOCAL"); 1945 } 1946 c_ensure_local(t, dst.v.local, dst.type); 1947 c_ensure_local(t, s, d->type); 1948 char buf[24]; 1949 c_emit_local_assign_open(t, dst.v.local, (KitCgTypeId)0); 1950 cbuf_puts(&t->body, "&"); 1951 c_local_name(s, buf, sizeof buf); 1952 cbuf_puts(&t->body, buf); 1953 c_emit_local_assign_close(t); 1954 } 1955 1956 /* ===== convert ===== */ 1957 1958 void c_emit_convert(CTarget* t, ConvKind k, Operand dst, Operand src) { 1959 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 1960 if (dst.kind != OPK_LOCAL) { 1961 compiler_panic(t->c, loc, "C target: convert dst must be LOCAL"); 1962 } 1963 c_ensure_local(t, dst.v.local, dst.type); 1964 char buf[24]; 1965 c_local_name(dst.v.local, buf, sizeof buf); 1966 1967 if (k == CV_BITCAST) { 1968 /* Same-size reinterpretation. Use __builtin_memcpy through a temp so 1969 * neither aliasing nor representation assumptions creep in. The temp 1970 * lives in its own `{ ... }` block, so no name collision tracking. */ 1971 u32 id = ++t->next_tmp; 1972 cbuf_puts(&t->body, " { "); 1973 c_emit_type(t, &t->body, src.type); 1974 cbuf_puts(&t->body, " __bc"); 1975 cbuf_put_u64(&t->body, (u64)id); 1976 cbuf_puts(&t->body, " = "); 1977 c_emit_operand(t, src); 1978 cbuf_puts(&t->body, "; __builtin_memcpy(&"); 1979 cbuf_puts(&t->body, buf); 1980 cbuf_puts(&t->body, ", &__bc"); 1981 cbuf_put_u64(&t->body, (u64)id); 1982 cbuf_puts(&t->body, ", sizeof __bc"); 1983 cbuf_put_u64(&t->body, (u64)id); 1984 cbuf_puts(&t->body, "); }\n"); 1985 return; 1986 } 1987 1988 if (c_type_is_bool(t, dst.type)) { 1989 c_emit_local_assign_open(t, dst.v.local, dst.type); 1990 cbuf_puts(&t->body, "("); 1991 c_emit_type(t, &t->body, dst.type); 1992 cbuf_puts(&t->body, ")("); 1993 c_emit_operand(t, src); 1994 cbuf_puts(&t->body, " != 0)"); 1995 c_emit_local_assign_close(t); 1996 return; 1997 } 1998 1999 /* Integer and float conversions: a C cast does the right thing once the 2000 * source is first cast to the appropriate signedness (for SEXT/ZEXT and 2001 * ITOF_S/U / FTOI_S/U). */ 2002 int src_signed = 1; 2003 switch (k) { 2004 case CV_ZEXT: 2005 case CV_ITOF_U: 2006 case CV_FTOI_U: 2007 src_signed = 0; 2008 break; 2009 default: 2010 src_signed = 1; 2011 break; 2012 } 2013 2014 /* The cast `(dst.type)(src)` produces a value of dst.type. */ 2015 c_emit_local_assign_open(t, dst.v.local, dst.type); 2016 cbuf_puts(&t->body, "("); 2017 c_emit_type(t, &t->body, dst.type); 2018 cbuf_puts(&t->body, ")"); 2019 if (k == CV_SEXT || k == CV_ZEXT) { 2020 c_emit_operand_signed(t, src, src_signed); 2021 } else if (k == CV_TRUNC && c_operand_is_ptr_typed(t, src)) { 2022 /* Casting a pointer directly to a narrower integer trips 2023 * -Wvoid-pointer-to-int-cast (and -Wpointer-to-int-cast). Bridge 2024 * through uintptr_t. */ 2025 cbuf_puts(&t->body, "((uintptr_t)"); 2026 c_emit_operand(t, src); 2027 cbuf_puts(&t->body, ")"); 2028 } else { 2029 /* TRUNC / FTOI / ITOF / FEXT / FTRUNC: rely on C cast semantics. */ 2030 c_emit_operand(t, src); 2031 } 2032 c_emit_local_assign_close(t); 2033 } 2034 2035 /* === call === */ 2036 2037 static KitCgTypeId c_call_arg_type(CTarget* t, const CgType* fty, 2038 const CGCallDesc* d, u32 i) { 2039 if (i < fty->func.nparams) return fty->func.params[i].type; 2040 return c_local_type_or_panic(t, d->args[i]); 2041 } 2042 2043 static void c_emit_call_arg(CTarget* t, const CgType* fty, const CGCallDesc* d, 2044 u32 i) { 2045 KitCgTypeId ty = c_call_arg_type(t, fty, d, i); 2046 c_ensure_local(t, d->args[i], ty); 2047 c_emit_operand(t, c_op_local(d->args[i], ty)); 2048 } 2049 2050 /* Render call operand `i`, optionally cast to unsigned __int128 first (used by 2051 * the unsigned i128 helpers below). */ 2052 static void c_emit_ti_operand(CTarget* t, const CgType* fty, 2053 const CGCallDesc* d, u32 i, int as_unsigned) { 2054 if (as_unsigned) cbuf_puts(&t->body, "(unsigned __int128)("); 2055 c_emit_call_arg(t, fty, d, i); 2056 if (as_unsigned) cbuf_puts(&t->body, ")"); 2057 } 2058 2059 /* The CG arithmetic layer (src/cg/arith.c) lowers 128-bit integer operations 2060 * into calls to runtime helpers: compiler-rt-standard names for mul/div/mod/ 2061 * shift/neg, and __kit_*-prefixed ones for add/sub/bitwise/not/extend/compare 2062 * — operations that real toolchains inline (so have no compiler-rt symbol), or 2063 * that use kit's own -1/0/1 compare convention. A C compiler has native 2064 * __int128, so the portable C backend re-expresses every such call as a native 2065 * operator: the emitted source then needs neither kit's runtime nor the host's 2066 * compiler-rt builtins. Returns 1 if it emitted the intrinsic, 0 to fall 2067 * through to a normal call. */ 2068 static int c_try_emit_ti_intrinsic(CTarget* t, const CgType* fty, 2069 const CGCallDesc* d) { 2070 if (d->callee.kind != OPK_GLOBAL) return 0; 2071 const char* n = c_sym_name(t, d->callee.v.global.sym); 2072 if (!n) return 0; 2073 2074 /* Symmetric binary ops over two i128 operands: (a) OP (b). `u` casts both 2075 * operands to unsigned __int128 first (unsigned divide/remainder). */ 2076 static const struct { 2077 const char* name; 2078 const char* op; 2079 int u; 2080 } kBin[] = { 2081 {"__kit_addti3", "+", 0}, {"__kit_subti3", "-", 0}, 2082 {"__multi3", "*", 0}, {"__kit_andti3", "&", 0}, 2083 {"__kit_orti3", "|", 0}, {"__kit_xorti3", "^", 0}, 2084 {"__divti3", "/", 0}, {"__modti3", "%", 0}, 2085 {"__udivti3", "/", 1}, {"__umodti3", "%", 1}, 2086 }; 2087 if (d->nargs == 2) { 2088 for (size_t i = 0; i < sizeof kBin / sizeof kBin[0]; ++i) { 2089 if (strcmp(n, kBin[i].name) != 0) continue; 2090 cbuf_puts(&t->body, "("); 2091 c_emit_ti_operand(t, fty, d, 0, kBin[i].u); 2092 cbuf_puts(&t->body, " "); 2093 cbuf_puts(&t->body, kBin[i].op); 2094 cbuf_puts(&t->body, " "); 2095 c_emit_ti_operand(t, fty, d, 1, kBin[i].u); 2096 cbuf_puts(&t->body, ")"); 2097 return 1; 2098 } 2099 } 2100 2101 /* Shifts: (value) OP (count). The count is a plain int operand, never cast; 2102 * logical right shift takes an unsigned value. */ 2103 if (d->nargs == 2) { 2104 const char* sop = NULL; 2105 int uval = 0; 2106 if (strcmp(n, "__ashlti3") == 0) { 2107 sop = "<<"; 2108 } else if (strcmp(n, "__ashrti3") == 0) { 2109 sop = ">>"; 2110 } else if (strcmp(n, "__lshrti3") == 0) { 2111 sop = ">>"; 2112 uval = 1; 2113 } 2114 if (sop) { 2115 cbuf_puts(&t->body, "("); 2116 c_emit_ti_operand(t, fty, d, 0, uval); 2117 cbuf_puts(&t->body, " "); 2118 cbuf_puts(&t->body, sop); 2119 cbuf_puts(&t->body, " "); 2120 c_emit_call_arg(t, fty, d, 1); 2121 cbuf_puts(&t->body, ")"); 2122 return 1; 2123 } 2124 } 2125 2126 /* Unary ops and i64 -> i128 widening. */ 2127 if (d->nargs == 1) { 2128 const char* uop = NULL; 2129 if (strcmp(n, "__negti2") == 0) 2130 uop = "-"; 2131 else if (strcmp(n, "__kit_notti3") == 0) 2132 uop = "~"; 2133 if (uop) { 2134 cbuf_puts(&t->body, "("); 2135 cbuf_puts(&t->body, uop); 2136 cbuf_puts(&t->body, "("); 2137 c_emit_call_arg(t, fty, d, 0); 2138 cbuf_puts(&t->body, "))"); 2139 return 1; 2140 } 2141 if (strcmp(n, "__kit_sext64ti") == 0) { 2142 cbuf_puts(&t->body, "((__int128)(int64_t)("); 2143 c_emit_call_arg(t, fty, d, 0); 2144 cbuf_puts(&t->body, "))"); 2145 return 1; 2146 } 2147 if (strcmp(n, "__kit_zext64ti") == 0) { 2148 cbuf_puts(&t->body, "((unsigned __int128)(uint64_t)("); 2149 c_emit_call_arg(t, fty, d, 0); 2150 cbuf_puts(&t->body, "))"); 2151 return 1; 2152 } 2153 } 2154 2155 /* Compare: kit's helpers return -1/0/1 (the CG layer compares the result 2156 * against zero), so reproduce that sign convention with native operators. */ 2157 if (d->nargs == 2) { 2158 int usign = -1; 2159 if (strcmp(n, "__kit_cmpti2") == 0) 2160 usign = 0; 2161 else if (strcmp(n, "__kit_ucmpti2") == 0) 2162 usign = 1; 2163 if (usign >= 0) { 2164 cbuf_puts(&t->body, "("); 2165 c_emit_ti_operand(t, fty, d, 0, usign); 2166 cbuf_puts(&t->body, " < "); 2167 c_emit_ti_operand(t, fty, d, 1, usign); 2168 cbuf_puts(&t->body, " ? -1 : ("); 2169 c_emit_ti_operand(t, fty, d, 0, usign); 2170 cbuf_puts(&t->body, " > "); 2171 c_emit_ti_operand(t, fty, d, 1, usign); 2172 cbuf_puts(&t->body, " ? 1 : 0))"); 2173 return 1; 2174 } 2175 } 2176 return 0; 2177 } 2178 2179 static void c_emit_call_expr(CTarget* t, const CgType* fty, 2180 const CGCallDesc* d) { 2181 if (c_try_emit_ti_intrinsic(t, fty, d)) return; 2182 if (d->callee.kind == OPK_GLOBAL) { 2183 c_ensure_forward_decl(t, d->callee.v.global.sym, d->fn_type); 2184 cbuf_puts(&t->body, c_sym_name(t, d->callee.v.global.sym)); 2185 } else if (d->callee.kind == OPK_LOCAL) { 2186 const char* fp = c_typedef_name(t, d->fn_type); 2187 cbuf_puts(&t->body, "(("); 2188 c_ensure_typedef(t, d->fn_type); 2189 cbuf_puts(&t->body, fp); 2190 cbuf_puts(&t->body, ")"); 2191 c_emit_operand(t, d->callee); 2192 cbuf_puts(&t->body, ")"); 2193 } else { 2194 compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, 2195 "C target: callee kind %d not supported", 2196 (int)d->callee.kind); 2197 } 2198 2199 cbuf_puts(&t->body, "("); 2200 for (u32 i = 0; i < d->nargs; ++i) { 2201 if (i > 0) cbuf_puts(&t->body, ", "); 2202 c_emit_call_arg(t, fty, d, i); 2203 } 2204 cbuf_puts(&t->body, ")"); 2205 } 2206 2207 const char* c_emit_tail_call_unrealizable_reason(CTarget* t, 2208 const CGCallDesc* d) { 2209 return c_emit_tail_call_unrealizable_reason_for(t, t->cur_fn, d); 2210 } 2211 2212 const char* c_emit_tail_call_unrealizable_reason_for( 2213 CTarget* t, const CGFuncDesc* caller_fd, const CGCallDesc* d) { 2214 SrcLoc loc = caller_fd ? caller_fd->loc : (SrcLoc){0, 0, 0}; 2215 const CgType* fty = cg_type_get(t->c, d->fn_type); 2216 if (!fty || fty->kind != KIT_CG_TYPE_FUNC) { 2217 compiler_panic(t->c, loc, "C target: tail call: bad fn_type"); 2218 } 2219 const CgType* caller = 2220 caller_fd ? cg_type_get(t->c, caller_fd->fn_type) : NULL; 2221 if (!caller || caller->kind != KIT_CG_TYPE_FUNC) { 2222 compiler_panic(t->c, loc, "C target: tail call outside function"); 2223 } 2224 if (caller->func.abi_variadic) { 2225 return "C target: caller variadic tail call not yet supported by clang " 2226 "musttail"; 2227 } 2228 if (fty->func.abi_variadic) { 2229 return "C target: variadic tail call not yet supported by clang musttail"; 2230 } 2231 if (caller->func.nparams != fty->func.nparams) { 2232 return "C target: tail call with differing parameter counts not yet " 2233 "supported by clang musttail"; 2234 } 2235 return NULL; 2236 } 2237 2238 void c_emit_call(CTarget* t, const CGCallDesc* d) { 2239 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2240 2241 const CgType* fty = cg_type_get(t->c, d->fn_type); 2242 if (!fty || fty->kind != KIT_CG_TYPE_FUNC) { 2243 compiler_panic(t->c, loc, "C target: call: bad fn_type"); 2244 } 2245 KitCgTypeId ret_type = cg_func_ret_type(fty); 2246 int is_tail = (d->flags & CG_CALL_TAIL) != 0; 2247 2248 if (is_tail) { 2249 cbuf_puts(&t->body, " __attribute__((musttail)) return "); 2250 c_emit_call_expr(t, fty, d); 2251 cbuf_puts(&t->body, ";\n"); 2252 t->last_was_terminator = 1; 2253 } else if (d->result == CG_LOCAL_NONE) { 2254 cbuf_puts(&t->body, " "); 2255 c_emit_call_expr(t, fty, d); 2256 cbuf_puts(&t->body, ";\n"); 2257 } else { 2258 c_ensure_local(t, d->result, ret_type); 2259 c_emit_local_assign_open(t, d->result, ret_type); 2260 c_emit_call_expr(t, fty, d); 2261 c_emit_local_assign_close(t); 2262 } 2263 } 2264 2265 /* === load / store === */ 2266 2267 void c_emit_load(CTarget* t, Operand dst, Operand addr, MemAccess m) { 2268 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2269 if (dst.kind != OPK_LOCAL) { 2270 compiler_panic(t->c, loc, "C target: load dst must be LOCAL"); 2271 } 2272 c_ensure_local(t, dst.v.local, dst.type); 2273 KitCgTypeId access_ty = m.type ? m.type : dst.type; 2274 if (c_type_is_aggregate(t, access_ty) && !c_type_is_aggregate(t, dst.type)) 2275 access_ty = dst.type; 2276 /* The deref `*(access_ty*)addr` produces a value of access_ty. */ 2277 c_emit_local_assign_open(t, dst.v.local, access_ty); 2278 c_emit_addr_deref(t, addr, access_ty); 2279 c_emit_local_assign_close(t); 2280 } 2281 2282 void c_emit_store(CTarget* t, Operand addr, Operand src, MemAccess m) { 2283 KitCgTypeId access_ty = m.type ? m.type : src.type; 2284 if (c_type_is_aggregate(t, access_ty) && !c_type_is_aggregate(t, src.type)) 2285 access_ty = src.type; 2286 cbuf_puts(&t->body, " "); 2287 c_emit_addr_deref(t, addr, access_ty); 2288 /* c_emit_operand_as bridges int/ptr crossings through uintptr_t so 2289 * roundtrips don't trip `-Wint-conversion`. */ 2290 cbuf_puts(&t->body, " = "); 2291 c_emit_operand_as(t, src, access_ty); 2292 cbuf_puts(&t->body, ";\n"); 2293 } 2294 2295 void c_emit_addr_of(CTarget* t, Operand dst, Operand lv) { 2296 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2297 if (dst.kind != OPK_LOCAL) { 2298 compiler_panic(t->c, loc, "C target: addr_of dst must be LOCAL"); 2299 } 2300 c_ensure_local(t, dst.v.local, dst.type); 2301 /* `c_emit_lvalue_addr` casts its output to dst.type already. */ 2302 c_emit_local_assign_open(t, dst.v.local, dst.type); 2303 c_emit_lvalue_addr(t, lv, dst.type); 2304 c_emit_local_assign_close(t); 2305 } 2306 2307 void c_emit_ret(CTarget* t, CGLocal value) { 2308 /* Already-terminated block: this ret is unreachable (the frontend's 2309 * defensive `return 0;` epilogue lands here right after a user return). */ 2310 if (t->last_was_terminator) return; 2311 /* CG emits a defensive void-return epilogue at the end of every function. For 2312 * a non-void function that's unreachable; emitting a bare `return;` would 2313 * trip -Wreturn-type. Spell it as `__builtin_unreachable()` so the host C 2314 * compiler sees the path is dead without us inventing a fake value. A genuine 2315 * void return (the function's result is the void builtin) must still emit 2316 * `return;` -- testing against KIT_CG_TYPE_NONE here would misfire, since the 2317 * cutover represents void as the void builtin, not NONE. */ 2318 if (value == CG_LOCAL_NONE && t->cur_fn) { 2319 if (!cg_type_is_void(t->c, t->cur_fn->result_type)) { 2320 cbuf_puts(&t->body, " __builtin_unreachable();\n"); 2321 t->last_was_terminator = 1; 2322 return; 2323 } 2324 } 2325 cbuf_puts(&t->body, " return"); 2326 if (value != CG_LOCAL_NONE) { 2327 cbuf_puts(&t->body, " "); 2328 KitCgTypeId ret_type = t->cur_fn ? t->cur_fn->result_type : (KitCgTypeId)0; 2329 const CgType* rty = ret_type ? cg_type_get(t->c, ret_type) : NULL; 2330 int is_aggregate = rty && (rty->kind == KIT_CG_TYPE_RECORD || 2331 rty->kind == KIT_CG_TYPE_ARRAY); 2332 if (ret_type && !is_aggregate) { 2333 KitCgTypeId value_ty = c_local_type_or_panic(t, value); 2334 c_emit_operand_as(t, c_op_local(value, value_ty), ret_type); 2335 } else { 2336 c_emit_operand(t, c_op_local(value, ret_type)); 2337 } 2338 } 2339 cbuf_puts(&t->body, ";\n"); 2340 t->last_was_terminator = 1; 2341 } 2342 2343 /* === unreachable === 2344 * Control terminator for statically-unreachable code (the C 2345 * __builtin_unreachable point). Ends the basic block; emit the host 2346 * compiler's `__builtin_unreachable()` so it sees the path is dead. */ 2347 void c_emit_unreachable(CTarget* t) { 2348 if (t->last_was_terminator) return; 2349 cbuf_puts(&t->body, " __builtin_unreachable();\n"); 2350 t->last_was_terminator = 1; 2351 } 2352 2353 /* === alias === 2354 * `kit_cg_alias` makes alias_sym refer to target_sym's body. In obj-file 2355 * land that's two ObjSyms sharing a (section_id, value); in C source we 2356 * have to spell it out: 2357 * 2358 * ELF/PE → `Ret alias(args) __attribute__((alias("target")));` 2359 * Single definition, true aliasing, &alias == &target. 2360 * Mach-O → emit a thunk `Ret alias(args) { return target(args); }`. 2361 * Clang on Darwin rejects __attribute__((alias)) outright, 2362 * so we fall back to a wrapper. Loses the `&alias==&target` 2363 * identity but preserves call-through semantics, which is 2364 * all the kit-emitted code path needs. 2365 * 2366 * The emitted decl serves as the alias definition AND a forward prototype 2367 * for callers, so we mark sym_forwarded to dedup against a later c_call. */ 2368 void c_emit_alias(CTarget* t, ObjSymId alias_sym, ObjSymId target_sym, 2369 KitCgTypeId type) { 2370 if (c_sym_forwarded_test_and_set(t, alias_sym)) return; 2371 const char* alias_name = c_sym_name(t, alias_sym); 2372 const char* target_name = c_sym_name(t, target_sym); 2373 const CgType* fty = cg_type_get(t->c, type); 2374 int is_func = fty && fty->kind == KIT_CG_TYPE_FUNC; 2375 2376 const ObjFormatImpl* fmt = obj_format_lookup(t->c->target.obj); 2377 if (!fmt || !fmt->alias_via_thunk) { 2378 /* Attribute form. Works for both function and object aliases on ELF 2379 * and PE/COFF. */ 2380 c_emit_func_signature(t, &t->forwards, alias_name, type); 2381 cbuf_puts(&t->forwards, " __attribute__((alias(\""); 2382 cbuf_puts(&t->forwards, target_name); 2383 cbuf_puts(&t->forwards, "\")));\n"); 2384 return; 2385 } 2386 2387 /* Mach-O thunk fallback. Functions only for v1 — object aliases on 2388 * Darwin would need a more elaborate scheme (see doc/CBACKEND.md). */ 2389 if (!is_func) { 2390 compiler_panic(t->c, (SrcLoc){0, 0, 0}, 2391 "C target: object alias on Mach-O not yet supported"); 2392 } 2393 /* Forward prototype for the target (its full definition lands separately 2394 * via c_func_begin). Also dedup that. */ 2395 c_ensure_forward_decl(t, target_sym, type); 2396 /* `static`? No — alias must be externally visible. */ 2397 c_emit_func_signature(t, &t->forwards, alias_name, type); 2398 cbuf_puts(&t->forwards, " { "); 2399 KitCgTypeId ret_type = cg_type_func_ret_id(t->c, type); 2400 if (!cg_type_is_void(t->c, ret_type)) cbuf_puts(&t->forwards, "return "); 2401 cbuf_puts(&t->forwards, target_name); 2402 cbuf_puts(&t->forwards, "("); 2403 for (u32 i = 0; i < fty->func.nparams; ++i) { 2404 if (i > 0) cbuf_puts(&t->forwards, ", "); 2405 cbuf_puts(&t->forwards, "p"); 2406 cbuf_put_u64(&t->forwards, (u64)i); 2407 } 2408 cbuf_puts(&t->forwards, "); }\n"); 2409 } 2410 2411 /* === intrinsic === 2412 * 2413 * All kit IntrinKinds map onto gcc/clang `__builtin_*` builtins, which 2414 * the host C compiler then turns into the appropriate sequence (inline op, 2415 * libcall, runtime CAS, etc.). This is exactly the seam the doc described: 2416 * kit records intent, the downstream toolchain picks the mechanism. 2417 * 2418 * Operand shapes follow arch.h §IntrinKind. */ 2419 2420 static const char* c_bitop_builtin(IntrinKind k, u32 width) { 2421 switch (k) { 2422 case INTRIN_POPCOUNT: 2423 if (width == 32) return "__builtin_popcount"; 2424 if (width == 64) return "__builtin_popcountll"; 2425 if (width == 16 || width == 8) return "__builtin_popcount"; 2426 return NULL; 2427 case INTRIN_CTZ: 2428 if (width == 32) return "__builtin_ctz"; 2429 if (width == 64) return "__builtin_ctzll"; 2430 if (width == 16 || width == 8) return "__builtin_ctz"; 2431 return NULL; 2432 case INTRIN_CLZ: 2433 if (width == 32) return "__builtin_clz"; 2434 if (width == 64) return "__builtin_clzll"; 2435 if (width == 16 || width == 8) return "__builtin_clz"; 2436 return NULL; 2437 case INTRIN_BSWAP: 2438 if (width == 16) return "__builtin_bswap16"; 2439 if (width == 32) return "__builtin_bswap32"; 2440 if (width == 64) return "__builtin_bswap64"; 2441 return NULL; 2442 default: 2443 return NULL; 2444 } 2445 } 2446 2447 static const char* c_overflow_builtin(IntrinKind k) { 2448 switch (k) { 2449 case INTRIN_SADD_OVERFLOW: 2450 case INTRIN_UADD_OVERFLOW: 2451 return "__builtin_add_overflow"; 2452 case INTRIN_SSUB_OVERFLOW: 2453 case INTRIN_USUB_OVERFLOW: 2454 return "__builtin_sub_overflow"; 2455 case INTRIN_SMUL_OVERFLOW: 2456 case INTRIN_UMUL_OVERFLOW: 2457 return "__builtin_mul_overflow"; 2458 default: 2459 return NULL; 2460 } 2461 } 2462 2463 void c_emit_intrinsic(CTarget* t, IntrinKind k, Operand* dsts, u32 ndst, 2464 const Operand* args, u32 narg) { 2465 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2466 switch (k) { 2467 case INTRIN_TRAP: 2468 cbuf_puts(&t->body, " __builtin_trap();\n"); 2469 return; 2470 case INTRIN_PREFETCH: { 2471 cbuf_puts(&t->body, " __builtin_prefetch("); 2472 for (u32 i = 0; i < narg; ++i) { 2473 if (i > 0) cbuf_puts(&t->body, ", "); 2474 c_emit_operand(t, args[i]); 2475 } 2476 cbuf_puts(&t->body, ");\n"); 2477 return; 2478 } 2479 case INTRIN_ASSUME_ALIGNED: { 2480 /* dsts[0] is the result local (pointer); args = (ptr, align [, ofs]) */ 2481 if (ndst != 1) { 2482 compiler_panic(t->c, loc, 2483 "C target: assume_aligned: expected 1 dst, got %u", 2484 (unsigned)ndst); 2485 } 2486 c_ensure_local(t, dsts[0].v.local, dsts[0].type); 2487 /* Returns void*; bridge to dst pointer type. */ 2488 c_emit_local_assign_open(t, dsts[0].v.local, (KitCgTypeId)0); 2489 cbuf_puts(&t->body, "__builtin_assume_aligned("); 2490 for (u32 i = 0; i < narg; ++i) { 2491 if (i > 0) cbuf_puts(&t->body, ", "); 2492 c_emit_operand(t, args[i]); 2493 } 2494 cbuf_puts(&t->body, ")"); 2495 c_emit_local_assign_close(t); 2496 return; 2497 } 2498 case INTRIN_EXPECT: { 2499 /* dsts[0] = __builtin_expect(args[0], args[1]) but typed via long. */ 2500 if (ndst != 1 || narg != 2) { 2501 compiler_panic(t->c, loc, 2502 "C target: expect: bad shape (ndst=%u narg=%u)", 2503 (unsigned)ndst, (unsigned)narg); 2504 } 2505 c_ensure_local(t, dsts[0].v.local, dsts[0].type); 2506 /* Returns `long`; dst.type may be a narrower int — keep the bridge. */ 2507 c_emit_local_assign_open(t, dsts[0].v.local, (KitCgTypeId)0); 2508 cbuf_puts(&t->body, "__builtin_expect((long)"); 2509 c_emit_operand(t, args[0]); 2510 cbuf_puts(&t->body, ", (long)"); 2511 c_emit_operand(t, args[1]); 2512 cbuf_puts(&t->body, ")"); 2513 c_emit_local_assign_close(t); 2514 return; 2515 } 2516 case INTRIN_POPCOUNT: 2517 case INTRIN_CTZ: 2518 case INTRIN_CLZ: 2519 case INTRIN_BSWAP: { 2520 if (ndst != 1 || narg != 1) { 2521 compiler_panic(t->c, loc, 2522 "C target: bit-intrin: bad shape (ndst=%u narg=%u)", 2523 (unsigned)ndst, (unsigned)narg); 2524 } 2525 /* bswap width is determined by the result type (in bytes -> bit-width 2526 * bucket, matching the old per-width intrinsic split). The other bit 2527 * ops keep deriving width from the operand. */ 2528 u32 w; 2529 if (k == INTRIN_BSWAP) { 2530 u32 bytes = (u32)cg_type_size(t->c, dsts[0].type); 2531 w = bytes <= 2 ? 16u : (bytes <= 4 ? 32u : 64u); 2532 } else { 2533 w = c_int_width_for_signedness(t, args[0].type); 2534 } 2535 const char* fn = c_bitop_builtin(k, w); 2536 if (!fn) { 2537 compiler_panic(t->c, loc, "C target: bit-intrin width %u unsupported", 2538 (unsigned)w); 2539 } 2540 c_ensure_local(t, dsts[0].v.local, dsts[0].type); 2541 /* __builtin_popcount/ctz/clz return `int`; bswap returns its input 2542 * type. Narrow to dst.type via the bridge. */ 2543 c_emit_local_assign_open(t, dsts[0].v.local, (KitCgTypeId)0); 2544 cbuf_puts(&t->body, fn); 2545 cbuf_puts(&t->body, "("); 2546 c_emit_operand(t, args[0]); 2547 cbuf_puts(&t->body, ")"); 2548 c_emit_local_assign_close(t); 2549 return; 2550 } 2551 case INTRIN_SMUL_HIGH: 2552 case INTRIN_UMUL_HIGH: { 2553 u32 width; 2554 int is_signed = k == INTRIN_SMUL_HIGH; 2555 if (ndst != 1 || narg != 2) { 2556 compiler_panic(t->c, loc, 2557 "C target: mul-high: bad shape (ndst=%u narg=%u)", 2558 (unsigned)ndst, (unsigned)narg); 2559 } 2560 width = (u32)cg_type_size(t->c, dsts[0].type) * 8u; 2561 c_ensure_local(t, dsts[0].v.local, dsts[0].type); 2562 c_emit_local_assign_open(t, dsts[0].v.local, (KitCgTypeId)0); 2563 if (width == 64u) { 2564 cbuf_puts(&t->body, is_signed ? "((int64_t)(((__int128)(int64_t)(" 2565 : "((uint64_t)(((unsigned __int128)(uint64_t)("); 2566 c_emit_operand(t, args[0]); 2567 cbuf_puts(&t->body, is_signed ? ") * (__int128)(int64_t)(" 2568 : ") * (unsigned __int128)(uint64_t)("); 2569 c_emit_operand(t, args[1]); 2570 cbuf_puts(&t->body, ")) >> 64))"); 2571 } else { 2572 cbuf_puts(&t->body, is_signed ? "((int32_t)(((int64_t)(int32_t)(" 2573 : "((uint32_t)(((uint64_t)(uint32_t)("); 2574 c_emit_operand(t, args[0]); 2575 cbuf_puts(&t->body, is_signed ? ") * (int64_t)(int32_t)(" 2576 : ") * (uint64_t)(uint32_t)("); 2577 c_emit_operand(t, args[1]); 2578 cbuf_puts(&t->body, is_signed ? ")) >> 32))" : ")) >> 32))"); 2579 } 2580 c_emit_local_assign_close(t); 2581 return; 2582 } 2583 case INTRIN_CPU_YIELD: 2584 /* A portable relax hint may be discarded by the downstream C compiler. */ 2585 cbuf_puts(&t->body, " (void)0;\n"); 2586 return; 2587 case INTRIN_MEMMOVE: { 2588 cbuf_puts(&t->body, " __builtin_memmove("); 2589 for (u32 i = 0; i < narg; ++i) { 2590 if (i > 0) cbuf_puts(&t->body, ", "); 2591 /* The pointer operands (dst and src) may be typed as a plain integer 2592 * local when they come from address arithmetic, which the C target 2593 * declares as int64_t. __builtin_memmove takes void*, so cast 2594 * explicitly to avoid -Wint-conversion. */ 2595 int is_ptr_arg = (i == 0) || (i == 1); 2596 if (is_ptr_arg) cbuf_puts(&t->body, "(void*)"); 2597 c_emit_operand(t, args[i]); 2598 } 2599 cbuf_puts(&t->body, ");\n"); 2600 return; 2601 } 2602 case INTRIN_SADD_OVERFLOW: 2603 case INTRIN_UADD_OVERFLOW: 2604 case INTRIN_SSUB_OVERFLOW: 2605 case INTRIN_USUB_OVERFLOW: 2606 case INTRIN_SMUL_OVERFLOW: 2607 case INTRIN_UMUL_OVERFLOW: { 2608 /* dsts[0] = value local, dsts[1] = i1 overflow flag. 2609 * 2610 * Signedness comes from the intrinsic kind, but kit's CG int type 2611 * is width-only and the C target declares every result as a signed 2612 * fixed-width (int{8,16,32,64}_t). __builtin_*_overflow keys its 2613 * overflow check on the result type, so passing the signed local 2614 * directly makes a UADD test as if it were signed and miss true 2615 * unsigned overflow. Wrap the call in a block with a scratch result 2616 * of the right signedness and copy it back through the int/uint 2617 * bridge. */ 2618 if (ndst != 2 || narg != 2) { 2619 compiler_panic(t->c, loc, "C target: overflow-intrin: bad shape"); 2620 } 2621 int is_unsigned = 2622 (k == INTRIN_UADD_OVERFLOW || k == INTRIN_USUB_OVERFLOW || 2623 k == INTRIN_UMUL_OVERFLOW); 2624 const char* fn = c_overflow_builtin(k); 2625 c_ensure_local(t, dsts[0].v.local, dsts[0].type); 2626 c_ensure_local(t, dsts[1].v.local, dsts[1].type); 2627 char vbuf[24], obuf[24]; 2628 c_local_name(dsts[0].v.local, vbuf, sizeof vbuf); 2629 c_local_name(dsts[1].v.local, obuf, sizeof obuf); 2630 u32 w = c_int_width_for_signedness(t, dsts[0].type); 2631 const char* sty = c_int_type_name_for_width(w, !is_unsigned); 2632 if (!sty) { 2633 compiler_panic(t->c, loc, 2634 "C target: overflow-intrin: unsupported width %u", 2635 (unsigned)w); 2636 } 2637 cbuf_puts(&t->body, " { "); 2638 cbuf_puts(&t->body, sty); 2639 cbuf_puts(&t->body, " __ovsc; "); 2640 cbuf_puts(&t->body, obuf); 2641 cbuf_puts(&t->body, " = ("); 2642 c_emit_type(t, &t->body, dsts[1].type); 2643 cbuf_puts(&t->body, ")"); 2644 cbuf_puts(&t->body, fn); 2645 cbuf_puts(&t->body, "(("); 2646 cbuf_puts(&t->body, sty); 2647 cbuf_puts(&t->body, ")"); 2648 c_emit_operand(t, args[0]); 2649 cbuf_puts(&t->body, ", ("); 2650 cbuf_puts(&t->body, sty); 2651 cbuf_puts(&t->body, ")"); 2652 c_emit_operand(t, args[1]); 2653 cbuf_puts(&t->body, ", &__ovsc); "); 2654 cbuf_puts(&t->body, vbuf); 2655 cbuf_puts(&t->body, " = ("); 2656 c_emit_type(t, &t->body, dsts[0].type); 2657 cbuf_puts(&t->body, ")__ovsc; }\n"); 2658 return; 2659 } 2660 case INTRIN_SETJMP: { 2661 t->need_setjmp = 1; 2662 if (ndst != 1 || narg != 1) { 2663 compiler_panic(t->c, loc, "C target: setjmp: bad shape"); 2664 } 2665 c_ensure_local(t, dsts[0].v.local, dsts[0].type); 2666 /* setjmp returns `int`; bridge to dst.type. */ 2667 c_emit_local_assign_open(t, dsts[0].v.local, (KitCgTypeId)0); 2668 cbuf_puts(&t->body, "setjmp(*(jmp_buf*)("); 2669 c_emit_operand(t, args[0]); 2670 cbuf_puts(&t->body, "))"); 2671 c_emit_local_assign_close(t); 2672 return; 2673 } 2674 case INTRIN_LONGJMP: { 2675 t->need_setjmp = 1; 2676 cbuf_puts(&t->body, " longjmp(*(jmp_buf*)("); 2677 c_emit_operand(t, args[0]); 2678 cbuf_puts(&t->body, "), (int)"); 2679 c_emit_operand(t, args[1]); 2680 cbuf_puts(&t->body, ");\n"); 2681 return; 2682 } 2683 case INTRIN_FRAME_ADDRESS: 2684 case INTRIN_RETURN_ADDRESS: { 2685 /* Forward straight to the host compiler's builtin. dsts[0] is the void* 2686 * result; args[0] is the constant level. The builtin requires a bare 2687 * integer constant, so emit the level as a plain decimal (not via 2688 * c_emit_operand, which wraps IMMs in a cast). */ 2689 char nbuf[24]; 2690 unsigned level = 2691 (narg >= 1 && args[0].kind == OPK_IMM) ? (unsigned)args[0].v.imm : 0u; 2692 if (ndst != 1) { 2693 compiler_panic(t->c, loc, 2694 "C target: frame/return address: expected 1 dst, got %u", 2695 (unsigned)ndst); 2696 } 2697 snprintf(nbuf, sizeof nbuf, "%u", level); 2698 c_ensure_local(t, dsts[0].v.local, dsts[0].type); 2699 c_emit_local_assign_open(t, dsts[0].v.local, (KitCgTypeId)0); 2700 cbuf_puts(&t->body, k == INTRIN_FRAME_ADDRESS 2701 ? "__builtin_frame_address(" 2702 : "__builtin_return_address("); 2703 cbuf_puts(&t->body, nbuf); 2704 cbuf_puts(&t->body, ")"); 2705 c_emit_local_assign_close(t); 2706 return; 2707 } 2708 case INTRIN_READCYCLECOUNTER: { 2709 /* Forward to the host compiler's builtin. dsts[0] is the u64 result. */ 2710 if (ndst != 1) { 2711 compiler_panic(t->c, loc, 2712 "C target: readcyclecounter: expected 1 dst, got %u", 2713 (unsigned)ndst); 2714 } 2715 c_ensure_local(t, dsts[0].v.local, dsts[0].type); 2716 c_emit_local_assign_open(t, dsts[0].v.local, (KitCgTypeId)0); 2717 cbuf_puts(&t->body, "__builtin_readcyclecounter()"); 2718 c_emit_local_assign_close(t); 2719 return; 2720 } 2721 case INTRIN_SYSCALL: 2722 compiler_panic(t->c, loc, "C target: syscall intrinsic not supported"); 2723 return; 2724 case INTRIN_NONE: 2725 default: 2726 compiler_panic(t->c, loc, "C target: intrinsic kind %d not handled", 2727 (int)k); 2728 } 2729 } 2730 2731 /* === alloca === */ 2732 2733 void c_emit_alloca(CTarget* t, Operand dst, Operand size, u32 align) { 2734 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2735 if (dst.kind != OPK_LOCAL) { 2736 compiler_panic(t->c, loc, "C target: alloca dst must be LOCAL"); 2737 } 2738 c_ensure_local(t, dst.v.local, dst.type); 2739 /* __builtin_alloca returns `void*`; dst.type is typically void* too. */ 2740 c_emit_local_assign_open(t, dst.v.local, dst.type); 2741 if (align > 1) { 2742 /* gcc has __builtin_alloca_with_align taking bits, not bytes. */ 2743 cbuf_puts(&t->body, "__builtin_alloca_with_align("); 2744 c_emit_operand(t, size); 2745 cbuf_puts(&t->body, ", "); 2746 cbuf_put_u64(&t->body, (u64)align * 8u); 2747 cbuf_puts(&t->body, ")"); 2748 } else { 2749 cbuf_puts(&t->body, "__builtin_alloca("); 2750 c_emit_operand(t, size); 2751 cbuf_puts(&t->body, ")"); 2752 } 2753 c_emit_local_assign_close(t); 2754 } 2755 2756 /* === varargs === 2757 * 2758 * The C-target va_list is the host toolchain's `va_list` from <stdarg.h>. 2759 * The first arg of all va_* is `ap_addr` - the address of the va_list local. 2760 * We deref to get the va_list lvalue C's macros expect. */ 2761 2762 void c_emit_va_start(CTarget* t, Operand ap_addr) { 2763 t->need_stdarg = 1; 2764 /* va_start needs the "last named parameter". CG doesn't pass that to the 2765 * backend; gcc/clang accept any non-modified ident here for variadic 2766 * compatibility — feed the synthesized parameter name `p<nparams-1>` from 2767 * the enclosing function. */ 2768 const CGFuncDesc* fd = t->cur_fn; 2769 SrcLoc loc = fd ? fd->loc : (SrcLoc){0, 0, 0}; 2770 if (!fd) compiler_panic(t->c, loc, "C target: va_start outside function"); 2771 const CgType* fty = cg_type_get(t->c, fd->fn_type); 2772 if (!fty || fty->kind != KIT_CG_TYPE_FUNC || fty->func.nparams == 0) { 2773 compiler_panic(t->c, loc, 2774 "C target: va_start in non-variadic function shape"); 2775 } 2776 cbuf_puts(&t->body, " __builtin_va_start(*(va_list*)("); 2777 c_emit_operand(t, ap_addr); 2778 cbuf_puts(&t->body, "), p"); 2779 cbuf_put_u64(&t->body, (u64)(fty->func.nparams - 1u)); 2780 cbuf_puts(&t->body, ");\n"); 2781 } 2782 2783 void c_emit_va_end(CTarget* t, Operand ap_addr) { 2784 cbuf_puts(&t->body, " __builtin_va_end(*(va_list*)("); 2785 c_emit_operand(t, ap_addr); 2786 cbuf_puts(&t->body, "));\n"); 2787 } 2788 2789 void c_emit_va_copy(CTarget* t, Operand dst_addr, Operand src_addr) { 2790 cbuf_puts(&t->body, " __builtin_va_copy(*(va_list*)("); 2791 c_emit_operand(t, dst_addr); 2792 cbuf_puts(&t->body, "), *(va_list*)("); 2793 c_emit_operand(t, src_addr); 2794 cbuf_puts(&t->body, "));\n"); 2795 } 2796 2797 void c_emit_va_arg(CTarget* t, Operand dst, Operand ap_addr, KitCgTypeId ty) { 2798 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2799 if (dst.kind != OPK_LOCAL) { 2800 compiler_panic(t->c, loc, "C target: va_arg dst must be LOCAL"); 2801 } 2802 c_ensure_local(t, dst.v.local, dst.type); 2803 /* __builtin_va_arg yields a value of `ty`. */ 2804 c_emit_local_assign_open(t, dst.v.local, ty); 2805 cbuf_puts(&t->body, "__builtin_va_arg(*(va_list*)("); 2806 c_emit_operand(t, ap_addr); 2807 cbuf_puts(&t->body, "), "); 2808 c_emit_type(t, &t->body, ty); 2809 cbuf_puts(&t->body, ")"); 2810 c_emit_local_assign_close(t); 2811 } 2812 2813 /* === copy_bytes / set_bytes === */ 2814 2815 void c_emit_copy_bytes(CTarget* t, Operand dst_addr, Operand src_addr, 2816 AggregateAccess m) { 2817 c_assert_no_index(t, dst_addr, "copy_bytes dst"); 2818 c_assert_no_index(t, src_addr, "copy_bytes src"); 2819 /* dst/src may be plain integer regs from address arithmetic (declared 2820 * int64_t); __builtin_memcpy takes void*, so cast to avoid 2821 * -Wint-conversion. */ 2822 cbuf_puts(&t->body, " __builtin_memcpy((void*)"); 2823 c_emit_copy_addr(t, dst_addr); 2824 cbuf_puts(&t->body, ", (void*)"); 2825 c_emit_copy_addr(t, src_addr); 2826 cbuf_puts(&t->body, ", "); 2827 cbuf_put_u64(&t->body, (u64)m.size); 2828 cbuf_puts(&t->body, ");\n"); 2829 } 2830 2831 static void c_emit_copy_addr(CTarget* t, Operand addr) { 2832 char buf[24]; 2833 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2834 switch (addr.kind) { 2835 case OPK_LOCAL: 2836 c_ensure_local(t, addr.v.local, addr.type); 2837 if (c_operand_is_ptr_typed(t, addr)) { 2838 c_emit_operand(t, addr); 2839 } else { 2840 cbuf_putc(&t->body, '&'); 2841 c_local_name(addr.v.local, buf, sizeof buf); 2842 cbuf_puts(&t->body, buf); 2843 } 2844 return; 2845 case OPK_GLOBAL: { 2846 obj_sym_mark_referenced(t->obj, addr.v.global.sym); 2847 cbuf_puts(&t->body, "((char*)&"); 2848 cbuf_puts(&t->body, c_sym_name(t, addr.v.global.sym)); 2849 if (addr.v.global.addend != 0) { 2850 cbuf_puts(&t->body, " + "); 2851 cbuf_put_i64(&t->body, addr.v.global.addend); 2852 } 2853 cbuf_putc(&t->body, ')'); 2854 return; 2855 } 2856 case OPK_INDIRECT: 2857 c_emit_indirect_addr_expr(t, c_addr_mode(addr)); 2858 return; 2859 default: 2860 compiler_panic(t->c, loc, 2861 "C target: copy_bytes address operand kind %d not " 2862 "supported", 2863 (int)addr.kind); 2864 } 2865 } 2866 2867 void c_emit_set_bytes(CTarget* t, Operand dst_addr, Operand byte_value, 2868 AggregateAccess m) { 2869 c_assert_no_index(t, dst_addr, "set_bytes dst"); 2870 /* dst may be a plain integer local from address arithmetic (declared 2871 * int64_t); __builtin_memset takes void*, so cast to avoid 2872 * -Wint-conversion. */ 2873 cbuf_puts(&t->body, " __builtin_memset((void*)"); 2874 c_emit_copy_addr(t, dst_addr); 2875 cbuf_puts(&t->body, ", (int)"); 2876 c_emit_operand(t, byte_value); 2877 cbuf_puts(&t->body, ", "); 2878 cbuf_put_u64(&t->body, (u64)m.size); 2879 cbuf_puts(&t->body, ");\n"); 2880 } 2881 2882 /* === TLS === 2883 * 2884 * Thread-local data is emitted as `_Thread_local _Alignas(A) uint8_t name[N];` 2885 * during c_emit_data, and tls_addr_of spells `((char*)&name + addend)` with 2886 * the requested pointer type. The host C compiler picks the TLS model. */ 2887 2888 void c_emit_tls_addr_of(CTarget* t, Operand dst, ObjSymId sym, i64 addend); 2889 2890 void c_emit_tls_addr_of(CTarget* t, Operand dst, ObjSymId sym, i64 addend) { 2891 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2892 if (dst.kind != OPK_LOCAL) { 2893 compiler_panic(t->c, loc, "C target: tls_addr_of dst must be LOCAL"); 2894 } 2895 c_ensure_local(t, dst.v.local, dst.type); 2896 const char* nm = c_sym_name(t, sym); 2897 /* RHS spells `(char*)&sym + addend` — pointer type that may not match 2898 * dst.type; keep the bridge to cast through cleanly. */ 2899 c_emit_local_assign_open(t, dst.v.local, (KitCgTypeId)0); 2900 cbuf_puts(&t->body, "((char*)&"); 2901 cbuf_puts(&t->body, nm); 2902 if (addend != 0) { 2903 cbuf_puts(&t->body, " + "); 2904 cbuf_put_i64(&t->body, addend); 2905 } 2906 cbuf_puts(&t->body, ")"); 2907 c_emit_local_assign_close(t); 2908 } 2909 2910 /* === bitfields === 2911 * 2912 * kit CG flattens bitfields to (storage_type, byte_offset, bit_offset, 2913 * bit_width) at the access boundary, so the C target never sees a C-level 2914 * bitfield declaration. We extract/insert via explicit mask+shift on the 2915 * underlying storage unit (a fixed-width unsigned int loaded through the 2916 * usual address-deref path), which sidesteps the C bitfield ABI ambiguity 2917 * entirely. */ 2918 2919 void c_emit_bitfield_load(CTarget* t, Operand dst, Operand addr, 2920 BitFieldAccess bf); 2921 void c_emit_bitfield_store(CTarget* t, Operand addr, Operand src, 2922 BitFieldAccess bf); 2923 2924 /* Returns the unsigned C integer type matching the storage-unit byte size. */ 2925 static const char* c_bf_storage_type(u32 size) { 2926 switch (size) { 2927 case 1: 2928 return "uint8_t"; 2929 case 2: 2930 return "uint16_t"; 2931 case 4: 2932 return "uint32_t"; 2933 case 8: 2934 return "uint64_t"; 2935 default: 2936 return NULL; 2937 } 2938 } 2939 2940 /* Spell an address expression for a backend-addressable lvalue operand. 2941 * Unlike c_emit_operand, this never reads the object value; it materializes 2942 * the address of the local/global/indirect storage itself. */ 2943 static void c_emit_lvalue_addr_expr_raw(CTarget* t, Operand addr) { 2944 char buf[24]; 2945 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 2946 switch (addr.kind) { 2947 case OPK_LOCAL: 2948 cbuf_putc(&t->body, '&'); 2949 c_ensure_local(t, addr.v.local, addr.type); 2950 c_local_name(addr.v.local, buf, sizeof buf); 2951 cbuf_puts(&t->body, buf); 2952 return; 2953 case OPK_GLOBAL: { 2954 obj_sym_mark_referenced(t->obj, addr.v.global.sym); 2955 const char* nm = c_sym_name(t, addr.v.global.sym); 2956 cbuf_puts(&t->body, "((char*)&"); 2957 cbuf_puts(&t->body, nm); 2958 if (addr.v.global.addend != 0) { 2959 cbuf_puts(&t->body, " + "); 2960 cbuf_put_i64(&t->body, addr.v.global.addend); 2961 } 2962 cbuf_putc(&t->body, ')'); 2963 return; 2964 } 2965 case OPK_INDIRECT: { 2966 CAddrMode m = c_addr_mode(addr); 2967 if ((u32)m.base >= t->local_cap || !t->local_declared[m.base]) { 2968 compiler_panic(t->c, loc, 2969 "C target: bitfield on undeclared base local v%u", 2970 (unsigned)m.base); 2971 } 2972 cbuf_putc(&t->body, '('); 2973 c_emit_indirect_addr_expr(t, m); 2974 cbuf_putc(&t->body, ')'); 2975 return; 2976 } 2977 default: 2978 compiler_panic(t->c, loc, 2979 "C target: bitfield address on operand kind %d not " 2980 "supported", 2981 (int)addr.kind); 2982 } 2983 } 2984 2985 /* Spell `*(uintN_t*)((char*)addr + bf.storage_offset)` into the body. */ 2986 static void c_bf_storage_lvalue(CTarget* t, Operand addr, BitFieldAccess bf, 2987 const char* storage_ty) { 2988 cbuf_puts(&t->body, "(*("); 2989 cbuf_puts(&t->body, storage_ty); 2990 cbuf_puts(&t->body, "*)((char*)"); 2991 c_emit_lvalue_addr_expr_raw(t, addr); 2992 if (bf.storage_offset != 0) { 2993 cbuf_puts(&t->body, " + "); 2994 cbuf_put_u64(&t->body, (u64)bf.storage_offset); 2995 } 2996 cbuf_puts(&t->body, "))"); 2997 } 2998 2999 void c_emit_bitfield_load(CTarget* t, Operand dst, Operand addr, 3000 BitFieldAccess bf) { 3001 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 3002 if (dst.kind != OPK_LOCAL) { 3003 compiler_panic(t->c, loc, "C target: bitfield_load dst must be LOCAL"); 3004 } 3005 c_assert_no_index(t, addr, "bitfield_load"); 3006 if (bf.bit_width == 0) { 3007 /* Zero-width — layout barrier only; nothing to load. Emit a no-op 3008 * assignment so the dst local still gets a defined value. */ 3009 c_ensure_local(t, dst.v.local, dst.type); 3010 /* RHS is the literal 0 (int); narrowing to dst.type is fine. */ 3011 c_emit_local_assign_open(t, dst.v.local, dst.type); 3012 cbuf_puts(&t->body, "0"); 3013 c_emit_local_assign_close(t); 3014 return; 3015 } 3016 const char* sty = c_bf_storage_type(bf.storage.size); 3017 if (!sty) { 3018 compiler_panic(t->c, loc, "C target: bitfield storage size %u unsupported", 3019 (unsigned)bf.storage.size); 3020 } 3021 c_ensure_local(t, dst.v.local, dst.type); 3022 /* RHS is the storage-width int from the mask/shift expression; bridge 3023 * to dst.type so any signedness/width adjustment is explicit. */ 3024 c_emit_local_assign_open(t, dst.v.local, (KitCgTypeId)0); 3025 /* For signed bitfields, sign-extend via the standard shift-up / arith-shift- 3026 * down trick on a signed integer of the storage width. For unsigned, mask 3027 * the extracted bits. 3028 * 3029 * Storage is little-endian-bit-indexed on every kit-supported target 3030 * (LSB-first within a storage unit on x86_64/aarch64/rv64). */ 3031 u32 sw = bf.storage.size * 8u; 3032 if (bf.signed_) { 3033 /* (int_storage_t)((storage << shl) >> shr) where: 3034 * shl = sw - bit_width - bit_offset 3035 * shr = sw - bit_width 3036 * Then cast to dst type. */ 3037 u32 shl = sw - (u32)bf.bit_width - (u32)bf.bit_offset; 3038 u32 shr = sw - (u32)bf.bit_width; 3039 cbuf_puts(&t->body, "(((int"); 3040 cbuf_put_u64(&t->body, (u64)sw); 3041 cbuf_puts(&t->body, "_t)("); 3042 c_bf_storage_lvalue(t, addr, bf, sty); 3043 cbuf_puts(&t->body, " << "); 3044 cbuf_put_u64(&t->body, (u64)shl); 3045 cbuf_puts(&t->body, ")) >> "); 3046 cbuf_put_u64(&t->body, (u64)shr); 3047 cbuf_puts(&t->body, ")"); 3048 } else { 3049 /* ((storage >> bit_offset) & ((1u << bit_width) - 1)) */ 3050 u64 mask = (bf.bit_width >= 64) ? ~(u64)0 : (((u64)1 << bf.bit_width) - 1u); 3051 cbuf_puts(&t->body, "(("); 3052 c_bf_storage_lvalue(t, addr, bf, sty); 3053 cbuf_puts(&t->body, " >> "); 3054 cbuf_put_u64(&t->body, (u64)bf.bit_offset); 3055 cbuf_puts(&t->body, ") & ("); 3056 cbuf_puts(&t->body, sty); 3057 cbuf_puts(&t->body, ")0x"); 3058 static const char hex[] = "0123456789abcdef"; 3059 int started = 0; 3060 for (int sh = 60; sh >= 0; sh -= 4) { 3061 u32 nib = (u32)((mask >> sh) & 0xfu); 3062 if (nib || started || sh == 0) { 3063 cbuf_putc(&t->body, hex[nib]); 3064 started = 1; 3065 } 3066 } 3067 cbuf_puts(&t->body, ")"); 3068 } 3069 c_emit_local_assign_close(t); 3070 } 3071 3072 void c_emit_bitfield_store(CTarget* t, Operand addr, Operand src, 3073 BitFieldAccess bf) { 3074 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 3075 c_assert_no_index(t, addr, "bitfield_store"); 3076 if (bf.bit_width == 0) return; /* zero-width: no-op */ 3077 const char* sty = c_bf_storage_type(bf.storage.size); 3078 if (!sty) { 3079 compiler_panic(t->c, loc, "C target: bitfield storage size %u unsupported", 3080 (unsigned)bf.storage.size); 3081 } 3082 u64 mask = (bf.bit_width >= 64) ? ~(u64)0 : (((u64)1 << bf.bit_width) - 1u); 3083 /* *(uintN_t*)p = (*(uintN_t*)p & ~(mask << bit_offset)) | 3084 * (((uintN_t)src & mask) << bit_offset); */ 3085 cbuf_puts(&t->body, " "); 3086 c_bf_storage_lvalue(t, addr, bf, sty); 3087 cbuf_puts(&t->body, " = ("); 3088 c_bf_storage_lvalue(t, addr, bf, sty); 3089 cbuf_puts(&t->body, " & ~(("); 3090 cbuf_puts(&t->body, sty); 3091 cbuf_puts(&t->body, ")0x"); 3092 static const char hex[] = "0123456789abcdef"; 3093 int started = 0; 3094 for (int sh = 60; sh >= 0; sh -= 4) { 3095 u32 nib = (u32)((mask >> sh) & 0xfu); 3096 if (nib || started || sh == 0) { 3097 cbuf_putc(&t->body, hex[nib]); 3098 started = 1; 3099 } 3100 } 3101 cbuf_puts(&t->body, " << "); 3102 cbuf_put_u64(&t->body, (u64)bf.bit_offset); 3103 cbuf_puts(&t->body, ")) | (((("); 3104 cbuf_puts(&t->body, sty); 3105 cbuf_puts(&t->body, ")"); 3106 c_emit_operand(t, src); 3107 cbuf_puts(&t->body, ") & ("); 3108 cbuf_puts(&t->body, sty); 3109 cbuf_puts(&t->body, ")0x"); 3110 started = 0; 3111 for (int sh = 60; sh >= 0; sh -= 4) { 3112 u32 nib = (u32)((mask >> sh) & 0xfu); 3113 if (nib || started || sh == 0) { 3114 cbuf_putc(&t->body, hex[nib]); 3115 started = 1; 3116 } 3117 } 3118 cbuf_puts(&t->body, ") << "); 3119 cbuf_put_u64(&t->body, (u64)bf.bit_offset); 3120 cbuf_puts(&t->body, ");\n"); 3121 } 3122 3123 /* === inline asm === 3124 * 3125 * Re-serialize kit's asm-block IR (template + constraint-bound operands + 3126 * clobbers) as GCC extended asm. The kit CG already speaks GCC-style 3127 * constraint strings ("r", "=r", "+m", "[name]constraint", matching "0"...), 3128 * so we pass the template through and emit the constraint+operand pairs in 3129 * order. */ 3130 3131 void c_emit_asm_block(CTarget* t, const char* tmpl, const AsmConstraint* outs, 3132 u32 no, Operand* oo, const AsmConstraint* ins, u32 ni, 3133 const Operand* io, const Sym* clobs, u32 nc); 3134 3135 static void c_emit_c_string_literal(CBuf* b, const char* s) { 3136 cbuf_putc(b, '"'); 3137 for (; *s; ++s) { 3138 char ch = *s; 3139 if (ch == '"' || ch == '\\') { 3140 cbuf_putc(b, '\\'); 3141 cbuf_putc(b, ch); 3142 } else if (ch == '\n') { 3143 cbuf_puts(b, "\\n"); 3144 } else if (ch == '\r') { 3145 cbuf_puts(b, "\\r"); 3146 } else if (ch == '\t') { 3147 cbuf_puts(b, "\\t"); 3148 } else if ((unsigned char)ch < 0x20 || (unsigned char)ch >= 0x7f) { 3149 static const char hex[] = "0123456789abcdef"; 3150 cbuf_puts(b, "\\x"); 3151 cbuf_putc(b, hex[((unsigned char)ch >> 4) & 0xfu]); 3152 cbuf_putc(b, hex[(unsigned char)ch & 0xfu]); 3153 } else { 3154 cbuf_putc(b, ch); 3155 } 3156 } 3157 cbuf_putc(b, '"'); 3158 } 3159 3160 /* "__kit_ao<i>" / "__kit_ai<i>": a unique name for the register temporary that 3161 * carries a hard-register-pinned output/input operand. */ 3162 static void c_asm_reg_temp_name(char* out, size_t cap, int is_out, u32 idx) { 3163 const char* pfx = is_out ? "__kit_ao" : "__kit_ai"; 3164 size_t i = 0; 3165 char tmp[16]; 3166 size_t n = 0; 3167 u32 v = idx; 3168 while (*pfx && i + 1 < cap) out[i++] = *pfx++; 3169 if (!v) tmp[n++] = '0'; 3170 while (v) { 3171 tmp[n++] = (char)('0' + v % 10); 3172 v /= 10; 3173 } 3174 while (n && i + 1 < cap) out[i++] = tmp[--n]; 3175 out[i] = '\0'; 3176 } 3177 3178 /* Emit an asm output operand's lvalue expression (a plain local, or a 3179 * dereferenced address for OPK_INDIRECT). Usable as both lvalue and rvalue. */ 3180 static void c_emit_asm_out_lvalue(CTarget* t, Operand op) { 3181 if (op.kind == OPK_LOCAL) { 3182 char rb[24]; 3183 c_ensure_local(t, op.v.local, op.type); 3184 c_local_name(op.v.local, rb, sizeof rb); 3185 cbuf_puts(&t->body, rb); 3186 } else { 3187 c_emit_addr_deref(t, op, op.type); 3188 } 3189 } 3190 3191 void c_emit_asm_block(CTarget* t, const char* tmpl, const AsmConstraint* outs, 3192 u32 no, Operand* oo, const AsmConstraint* ins, u32 ni, 3193 const Operand* io, const Sym* clobs, u32 nc) { 3194 char nm[24]; 3195 for (u32 i = 0; i < no; ++i) c_assert_no_index(t, oo[i], "asm_block out"); 3196 for (u32 i = 0; i < ni; ++i) c_assert_no_index(t, io[i], "asm_block in"); 3197 3198 /* GNU local register variables (AsmConstraint.reg): a target backend resolves 3199 * the pin to a physical register, but the portable C backend has no register 3200 * names to bind — so re-emit each pinned operand as a faithful 3201 * `register T v __asm__("reg")` temporary (scoped in a block) and let the 3202 * host compiler honor the binding. Dormant unless a frontend marks an 3203 * operand; only the C frontend does, for register variables. */ 3204 int any_pin = 0; 3205 for (u32 i = 0; i < no; ++i) 3206 if (outs[i].reg) any_pin = 1; 3207 for (u32 i = 0; i < ni; ++i) 3208 if (ins[i].reg) any_pin = 1; 3209 3210 if (any_pin) { 3211 cbuf_puts(&t->body, " {\n"); 3212 for (u32 i = 0; i < ni; ++i) { 3213 if (!ins[i].reg) continue; 3214 c_asm_reg_temp_name(nm, sizeof nm, 0, i); 3215 cbuf_puts(&t->body, " register "); 3216 c_emit_type(t, &t->body, io[i].type); 3217 cbuf_puts(&t->body, " "); 3218 cbuf_puts(&t->body, nm); 3219 cbuf_puts(&t->body, " __asm__("); 3220 c_emit_c_string_literal(&t->body, pool_slice(t->c->global, ins[i].reg).s); 3221 cbuf_puts(&t->body, ") = "); 3222 c_emit_operand(t, io[i]); 3223 cbuf_puts(&t->body, ";\n"); 3224 } 3225 for (u32 i = 0; i < no; ++i) { 3226 if (!outs[i].reg) continue; 3227 c_asm_reg_temp_name(nm, sizeof nm, 1, i); 3228 cbuf_puts(&t->body, " register "); 3229 c_emit_type(t, &t->body, oo[i].type); 3230 cbuf_puts(&t->body, " "); 3231 cbuf_puts(&t->body, nm); 3232 cbuf_puts(&t->body, " __asm__("); 3233 c_emit_c_string_literal(&t->body, 3234 pool_slice(t->c->global, outs[i].reg).s); 3235 cbuf_puts(&t->body, ")"); 3236 if (outs[i].dir == KIT_CG_ASM_INOUT) { 3237 cbuf_puts(&t->body, " = "); 3238 c_emit_asm_out_lvalue(t, oo[i]); 3239 } 3240 cbuf_puts(&t->body, ";\n"); 3241 } 3242 } 3243 3244 cbuf_puts(&t->body, any_pin ? " __asm__ __volatile__ (" 3245 : " __asm__ __volatile__ ("); 3246 c_emit_c_string_literal(&t->body, tmpl ? tmpl : ""); 3247 /* Outputs. */ 3248 cbuf_puts(&t->body, " : "); 3249 for (u32 i = 0; i < no; ++i) { 3250 if (i > 0) cbuf_puts(&t->body, ", "); 3251 if (outs[i].name) { 3252 cbuf_puts(&t->body, "["); 3253 cbuf_puts(&t->body, pool_slice(t->c->global, outs[i].name).s); 3254 cbuf_puts(&t->body, "] "); 3255 } 3256 c_emit_c_string_literal(&t->body, outs[i].str ? outs[i].str : ""); 3257 cbuf_puts(&t->body, "("); 3258 /* Outputs must be an lvalue. OPK_LOCAL is a plain C local; this 3259 * works directly. OPK_LOCAL / OPK_INDIRECT also produce lvalues. A pinned 3260 * output names its register temporary instead. */ 3261 if (outs[i].reg) { 3262 c_asm_reg_temp_name(nm, sizeof nm, 1, i); 3263 cbuf_puts(&t->body, nm); 3264 } else { 3265 c_emit_asm_out_lvalue(t, oo[i]); 3266 } 3267 cbuf_puts(&t->body, ")"); 3268 } 3269 /* Inputs. kit synthesizes a matching `"N"` input for every ASM_INOUT 3270 * output (so its IR sees a fresh read), but gcc treats `+r` outputs as 3271 * already serving the read role and rejects a redundant matching input. 3272 * Drop those synthesized matches when the referenced output is `+`-tied. */ 3273 cbuf_puts(&t->body, " : "); 3274 int emitted_any = 0; 3275 for (u32 i = 0; i < ni; ++i) { 3276 const char* cs = ins[i].str ? ins[i].str : ""; 3277 if (cs[0] >= '0' && cs[0] <= '9') { 3278 u32 idx = (u32)(cs[0] - '0'); 3279 if (idx < no && outs[idx].str && outs[idx].str[0] == '+') continue; 3280 } 3281 if (emitted_any) cbuf_puts(&t->body, ", "); 3282 emitted_any = 1; 3283 if (ins[i].name) { 3284 cbuf_puts(&t->body, "["); 3285 cbuf_puts(&t->body, pool_slice(t->c->global, ins[i].name).s); 3286 cbuf_puts(&t->body, "] "); 3287 } 3288 c_emit_c_string_literal(&t->body, cs); 3289 cbuf_puts(&t->body, "("); 3290 if (ins[i].reg) { 3291 c_asm_reg_temp_name(nm, sizeof nm, 0, i); 3292 cbuf_puts(&t->body, nm); 3293 } else { 3294 c_emit_operand(t, io[i]); 3295 } 3296 cbuf_puts(&t->body, ")"); 3297 } 3298 /* Clobbers. */ 3299 cbuf_puts(&t->body, " : "); 3300 for (u32 i = 0; i < nc; ++i) { 3301 if (i > 0) cbuf_puts(&t->body, ", "); 3302 c_emit_c_string_literal(&t->body, pool_slice(t->c->global, clobs[i]).s); 3303 } 3304 cbuf_puts(&t->body, ");\n"); 3305 3306 if (any_pin) { 3307 for (u32 i = 0; i < no; ++i) { 3308 if (!outs[i].reg) continue; 3309 c_asm_reg_temp_name(nm, sizeof nm, 1, i); 3310 cbuf_puts(&t->body, " "); 3311 c_emit_asm_out_lvalue(t, oo[i]); 3312 cbuf_puts(&t->body, " = "); 3313 cbuf_puts(&t->body, nm); 3314 cbuf_puts(&t->body, ";\n"); 3315 } 3316 cbuf_puts(&t->body, " }\n"); 3317 } 3318 } 3319 3320 /* === load_const === 3321 * 3322 * Used by CG for non-integer literal pushes (mainly floats — 3323 * `kit_cg_push_float`). Bytes are the target's ABI encoding of the value; we 3324 * copy them into the dst local via a static const byte array and 3325 * __builtin_memcpy so any host C compiler sees the same bit pattern. */ 3326 3327 void c_emit_load_const(CTarget* t, Operand dst, ConstBytes cb); 3328 3329 void c_emit_load_const(CTarget* t, Operand dst, ConstBytes cb) { 3330 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 3331 if (dst.kind != OPK_LOCAL) { 3332 compiler_panic(t->c, loc, "C target: load_const dst must be LOCAL"); 3333 } 3334 c_ensure_local(t, dst.v.local, dst.type); 3335 char buf[24]; 3336 c_local_name(dst.v.local, buf, sizeof buf); 3337 u32 id = ++t->next_tmp; 3338 cbuf_puts(&t->body, " { static const uint8_t __k"); 3339 cbuf_put_u64(&t->body, (u64)id); 3340 cbuf_puts(&t->body, "["); 3341 cbuf_put_u64(&t->body, (u64)cb.size); 3342 cbuf_puts(&t->body, "] = {"); 3343 static const char hex[] = "0123456789abcdef"; 3344 for (u32 i = 0; i < cb.size; ++i) { 3345 if (i > 0) cbuf_putc(&t->body, ','); 3346 cbuf_puts(&t->body, "0x"); 3347 cbuf_putc(&t->body, hex[(cb.bytes[i] >> 4) & 0xfu]); 3348 cbuf_putc(&t->body, hex[cb.bytes[i] & 0xfu]); 3349 } 3350 cbuf_puts(&t->body, "}; __builtin_memcpy(&"); 3351 cbuf_puts(&t->body, buf); 3352 cbuf_puts(&t->body, ", __k"); 3353 cbuf_put_u64(&t->body, (u64)id); 3354 cbuf_puts(&t->body, ", "); 3355 cbuf_put_u64(&t->body, (u64)cb.size); 3356 cbuf_puts(&t->body, "); }\n"); 3357 } 3358 3359 /* === atomics === 3360 * 3361 * Lowered to gcc/clang's `__atomic_*` generic builtins. The host compiler 3362 * picks the inline sequence vs. libcall and applies the requested memory 3363 * order. kit's KitCgMemOrder enum aligns 1-1 with the `__ATOMIC_*` constants. 3364 */ 3365 3366 static const char* c_memorder_token(KitCgMemOrder o) { 3367 switch (o) { 3368 case KIT_CG_MO_RELAXED: 3369 return "__ATOMIC_RELAXED"; 3370 case KIT_CG_MO_CONSUME: 3371 return "__ATOMIC_CONSUME"; 3372 case KIT_CG_MO_ACQUIRE: 3373 return "__ATOMIC_ACQUIRE"; 3374 case KIT_CG_MO_RELEASE: 3375 return "__ATOMIC_RELEASE"; 3376 case KIT_CG_MO_ACQ_REL: 3377 return "__ATOMIC_ACQ_REL"; 3378 case KIT_CG_MO_SEQ_CST: 3379 return "__ATOMIC_SEQ_CST"; 3380 } 3381 return "__ATOMIC_SEQ_CST"; 3382 } 3383 3384 void c_emit_atomic_load(CTarget* t, Operand dst, Operand addr, MemAccess m, 3385 KitCgMemOrder o); 3386 void c_emit_atomic_store(CTarget* t, Operand addr, Operand src, MemAccess m, 3387 KitCgMemOrder o); 3388 void c_emit_atomic_rmw(CTarget* t, KitCgAtomicOp op, Operand dst, Operand addr, 3389 Operand val, MemAccess m, KitCgMemOrder o); 3390 void c_emit_atomic_cas(CTarget* t, Operand prior, Operand ok, Operand addr, 3391 Operand expected, Operand desired, MemAccess m, 3392 KitCgMemOrder so, KitCgMemOrder fo); 3393 void c_emit_fence(CTarget* t, KitCgMemOrder o); 3394 3395 void c_emit_atomic_load(CTarget* t, Operand dst, Operand addr, MemAccess m, 3396 KitCgMemOrder o) { 3397 (void)m; 3398 c_assert_no_index(t, addr, "atomic_load"); 3399 c_ensure_local(t, dst.v.local, dst.type); 3400 /* __atomic_load_n returns a value of the pointed-to type (dst.type). */ 3401 c_emit_local_assign_open(t, dst.v.local, dst.type); 3402 cbuf_puts(&t->body, "__atomic_load_n(("); 3403 c_emit_type(t, &t->body, dst.type); 3404 cbuf_puts(&t->body, "*)"); 3405 c_emit_operand(t, addr); 3406 cbuf_puts(&t->body, ", "); 3407 cbuf_puts(&t->body, c_memorder_token(o)); 3408 cbuf_puts(&t->body, ")"); 3409 c_emit_local_assign_close(t); 3410 } 3411 3412 void c_emit_atomic_store(CTarget* t, Operand addr, Operand src, MemAccess m, 3413 KitCgMemOrder o) { 3414 (void)m; 3415 c_assert_no_index(t, addr, "atomic_store"); 3416 cbuf_puts(&t->body, " __atomic_store_n(("); 3417 c_emit_type(t, &t->body, src.type); 3418 cbuf_puts(&t->body, "*)"); 3419 c_emit_operand(t, addr); 3420 cbuf_puts(&t->body, ", "); 3421 c_emit_operand_as(t, src, src.type); 3422 cbuf_puts(&t->body, ", "); 3423 cbuf_puts(&t->body, c_memorder_token(o)); 3424 cbuf_puts(&t->body, ");\n"); 3425 } 3426 3427 static const char* c_atomic_op_builtin(KitCgAtomicOp op) { 3428 switch (op) { 3429 case KIT_CG_ATOMIC_XCHG: 3430 return "__atomic_exchange_n"; 3431 case KIT_CG_ATOMIC_ADD: 3432 return "__atomic_fetch_add"; 3433 case KIT_CG_ATOMIC_SUB: 3434 return "__atomic_fetch_sub"; 3435 case KIT_CG_ATOMIC_AND: 3436 return "__atomic_fetch_and"; 3437 case KIT_CG_ATOMIC_OR: 3438 return "__atomic_fetch_or"; 3439 case KIT_CG_ATOMIC_XOR: 3440 return "__atomic_fetch_xor"; 3441 case KIT_CG_ATOMIC_NAND: 3442 return "__atomic_fetch_nand"; 3443 } 3444 return NULL; 3445 } 3446 3447 void c_emit_atomic_rmw(CTarget* t, KitCgAtomicOp op, Operand dst, Operand addr, 3448 Operand val, MemAccess m, KitCgMemOrder o) { 3449 (void)m; 3450 SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; 3451 c_assert_no_index(t, addr, "atomic_rmw"); 3452 const char* fn = c_atomic_op_builtin(op); 3453 if (!fn) { 3454 compiler_panic(t->c, loc, "C target: unknown atomic op %d", (int)op); 3455 } 3456 c_ensure_local(t, dst.v.local, dst.type); 3457 /* __atomic_fetch_* returns the prior value of the pointed-to type. */ 3458 c_emit_local_assign_open(t, dst.v.local, val.type); 3459 cbuf_puts(&t->body, fn); 3460 cbuf_puts(&t->body, "(("); 3461 c_emit_type(t, &t->body, val.type); 3462 cbuf_puts(&t->body, "*)"); 3463 c_emit_operand(t, addr); 3464 cbuf_puts(&t->body, ", "); 3465 c_emit_operand_as(t, val, val.type); 3466 cbuf_puts(&t->body, ", "); 3467 cbuf_puts(&t->body, c_memorder_token(o)); 3468 cbuf_puts(&t->body, ")"); 3469 c_emit_local_assign_close(t); 3470 } 3471 3472 void c_emit_atomic_cas(CTarget* t, Operand prior, Operand ok, Operand addr, 3473 Operand expected, Operand desired, MemAccess m, 3474 KitCgMemOrder so, KitCgMemOrder fo) { 3475 (void)m; 3476 c_assert_no_index(t, addr, "atomic_cas"); 3477 /* gcc's __atomic_compare_exchange_n needs a real lvalue holding the 3478 * expected value because it is updated on failure. Materialize a scratch 3479 * local with the compare type, then copy it out to the prior result. */ 3480 c_ensure_local(t, prior.v.local, prior.type); 3481 c_ensure_local(t, ok.v.local, ok.type); 3482 u32 id = ++t->next_tmp; 3483 cbuf_puts(&t->body, " { "); 3484 c_emit_type(t, &t->body, prior.type); 3485 cbuf_puts(&t->body, " __cas"); 3486 cbuf_put_u64(&t->body, (u64)id); 3487 cbuf_puts(&t->body, " = "); 3488 c_emit_operand_as(t, expected, prior.type); 3489 cbuf_puts(&t->body, "; "); 3490 char ok_name[24], prior_name[24]; 3491 c_local_name(ok.v.local, ok_name, sizeof ok_name); 3492 c_local_name(prior.v.local, prior_name, sizeof prior_name); 3493 cbuf_puts(&t->body, ok_name); 3494 cbuf_puts(&t->body, " = ("); 3495 c_emit_type(t, &t->body, ok.type); 3496 cbuf_puts(&t->body, ")__atomic_compare_exchange_n(("); 3497 c_emit_type(t, &t->body, prior.type); 3498 cbuf_puts(&t->body, "*)"); 3499 c_emit_operand(t, addr); 3500 cbuf_puts(&t->body, ", &__cas"); 3501 cbuf_put_u64(&t->body, (u64)id); 3502 cbuf_puts(&t->body, ", "); 3503 c_emit_operand_as(t, desired, prior.type); 3504 cbuf_puts(&t->body, ", 0, "); 3505 cbuf_puts(&t->body, c_memorder_token(so)); 3506 cbuf_puts(&t->body, ", "); 3507 cbuf_puts(&t->body, c_memorder_token(fo)); 3508 cbuf_puts(&t->body, "); "); 3509 /* prior local = __cas; */ 3510 cbuf_puts(&t->body, prior_name); 3511 cbuf_puts(&t->body, " = __cas"); 3512 cbuf_put_u64(&t->body, (u64)id); 3513 cbuf_puts(&t->body, "; }\n"); 3514 } 3515 3516 void c_emit_fence(CTarget* t, KitCgMemOrder o) { 3517 cbuf_puts(&t->body, " __atomic_thread_fence("); 3518 cbuf_puts(&t->body, c_memorder_token(o)); 3519 cbuf_puts(&t->body, ");\n"); 3520 } 3521 3522 /* === set_loc === */ 3523 3524 static void cbuf_put_line_filename(CBuf* b, KitSlice s) { 3525 size_t i; 3526 cbuf_putc(b, '"'); 3527 for (i = 0; i < s.len; ++i) { 3528 { 3529 unsigned char ch = (unsigned char)s.s[i]; 3530 switch (ch) { 3531 case '\\': 3532 case '"': 3533 cbuf_putc(b, '\\'); 3534 cbuf_putc(b, (char)ch); 3535 break; 3536 case '\n': 3537 cbuf_puts(b, "\\n"); 3538 break; 3539 case '\r': 3540 cbuf_puts(b, "\\r"); 3541 break; 3542 case '\t': 3543 cbuf_puts(b, "\\t"); 3544 break; 3545 default: 3546 cbuf_putc(b, (char)ch); 3547 break; 3548 } 3549 } 3550 } 3551 cbuf_putc(b, '"'); 3552 } 3553 3554 void c_emit_set_loc(CTarget* t, SrcLoc l) { 3555 KitSlice file; 3556 3557 if (!t->cur_fn || l.file_id == 0 || l.line == 0) return; 3558 if (t->have_emitted_loc && t->emitted_loc.file_id == l.file_id && 3559 t->emitted_loc.line == l.line) { 3560 return; 3561 } 3562 3563 file = kit_compiler_file_name(t->c, l.file_id); 3564 if (!file.len) return; 3565 3566 cbuf_puts(&t->body, "#line "); 3567 cbuf_put_u64(&t->body, (u64)l.line); 3568 cbuf_putc(&t->body, ' '); 3569 cbuf_put_line_filename(&t->body, file); 3570 cbuf_putc(&t->body, '\n'); 3571 3572 t->emitted_loc = l; 3573 t->have_emitted_loc = 1; 3574 } 3575 3576 /* === data emission === 3577 * 3578 * Walks the ObjBuilder's symbol table at finalize and emits a C declaration 3579 * for every data object — defined or extern. Bytes are emitted verbatim as a 3580 * `uint8_t name[N] = { 0x.., ... }` initializer. Relocations targeting bytes 3581 * inside a defined symbol are spelled as runtime fixups in a constructor; this 3582 * covers both same-TU and cross-TU references uniformly and avoids the C 3583 * static-initializer restrictions on non-constant addresses. 3584 * 3585 * The host C compiler re-applies the Mach-O leading-underscore on link, so the 3586 * C source uses the kit linker name minus the `_` prefix (matching 3587 * c_sym_name elsewhere in this file). */ 3588 3589 static int c_is_data_section(const Section* sec) { 3590 if (!sec) return 0; 3591 switch (sec->kind) { 3592 case SEC_DATA: 3593 case SEC_RODATA: 3594 case SEC_BSS: 3595 return 1; 3596 case SEC_OTHER: 3597 /* User-named sections holding allocated data (e.g. `.text.hot` would 3598 * be EXEC, but a custom data section is just SF_ALLOC). */ 3599 return (sec->flags & SF_ALLOC) && !(sec->flags & SF_EXEC); 3600 default: 3601 return 0; 3602 } 3603 } 3604 3605 static void c_emit_link_attrs(CBuf* b, const ObjSym* os) { 3606 if (os->bind == SB_WEAK) cbuf_puts(b, "__attribute__((weak)) "); 3607 if (os->vis == SV_HIDDEN) { 3608 cbuf_puts(b, "__attribute__((visibility(\"hidden\"))) "); 3609 } else if (os->vis == SV_PROTECTED) { 3610 cbuf_puts(b, "__attribute__((visibility(\"protected\"))) "); 3611 } 3612 } 3613 3614 /* Reads `len` bytes starting at `ofs` from the section's byte buffer. The 3615 * Section uses a chunked Buf; buf_read does the splice for us. */ 3616 static void c_read_section_bytes(const Section* sec, u32 ofs, u8* out, 3617 size_t len) { 3618 buf_read(&sec->bytes, ofs, out, len); 3619 } 3620 3621 static void c_emit_data_bytes(CBuf* b, const u8* bytes, size_t n) { 3622 cbuf_puts(b, " = {"); 3623 for (size_t i = 0; i < n; ++i) { 3624 if (i > 0) cbuf_putc(b, ','); 3625 if ((i & 15u) == 0) cbuf_puts(b, "\n "); 3626 cbuf_puts(b, "0x"); 3627 static const char hex[] = "0123456789abcdef"; 3628 cbuf_putc(b, hex[(bytes[i] >> 4) & 0xfu]); 3629 cbuf_putc(b, hex[bytes[i] & 0xfu]); 3630 } 3631 cbuf_puts(b, "\n }"); 3632 } 3633 3634 /* Mach-O TLS support: the user-visible SK_TLS symbol is a 24-byte TLV 3635 * descriptor in __DATA,__thread_vars, and the actual initial bytes live in 3636 * a synthesized `<name>$tlv$init` sym in __thread_data (or __thread_bss). 3637 * The descriptor carries an R_ABS64 reloc at offset +16 pointing at that 3638 * init sym. For C-source emission we don't care about the descriptor at all 3639 * — we just emit `_Thread_local` with the init sym's bytes and let the host 3640 * C compiler synthesize whatever TLV plumbing it needs. */ 3641 3642 /* Find the data init sym referenced by a Mach-O TLS descriptor at 3643 * `desc_base` in section `desc_sec`. Looks for an R_ABS64 reloc at 3644 * `desc_base + 16`. Returns OBJ_SYM_NONE if not found. */ 3645 static ObjSymId c_macho_tls_find_init(CTarget* t, ObjSecId desc_sec, 3646 u32 desc_base) { 3647 u32 total = obj_reloc_total(t->obj); 3648 for (u32 i = 0; i < total; ++i) { 3649 const Reloc* r = obj_reloc_at(t->obj, i); 3650 if (r->section_id != desc_sec) continue; 3651 if (r->offset != desc_base + 16u) continue; 3652 return r->sym; 3653 } 3654 return OBJ_SYM_NONE; 3655 } 3656 3657 /* Returns 1 if the section is __DATA,__thread_vars (the descriptor section 3658 * on Mach-O). Compared by interned Sym id. */ 3659 static int c_sec_name_is_macho_tvars(CTarget* t, const Section* sec) { 3660 if (!sec) return 0; 3661 Sym tvars = 3662 pool_intern_slice(t->c->global, SLICE_LIT("__DATA,__thread_vars")); 3663 return sec->name == tvars; 3664 } 3665 3666 /* Returns 1 if any relocation falls into the half-open range [base, base+size) 3667 * of section `sec_id` (i.e. patches the bytes of this symbol). */ 3668 static int c_sym_has_relocs(CTarget* t, ObjSecId sec_id, u32 base, u32 size) { 3669 u32 total = obj_reloc_total(t->obj); 3670 for (u32 i = 0; i < total; ++i) { 3671 const Reloc* r = obj_reloc_at(t->obj, i); 3672 if (r->section_id != sec_id) continue; 3673 if (r->offset >= base && r->offset < base + size) return 1; 3674 } 3675 return 0; 3676 } 3677 3678 /* Emit one data symbol: extern declaration if undef, otherwise the full 3679 * definition with bytes. Function symbols are skipped — those go through the 3680 * forwards path. */ 3681 static void c_emit_data_symbol(CTarget* t, ObjSymId id, const ObjSym* os) { 3682 if (c_is_local_static_sym(t, id)) return; 3683 if (os->kind == SK_FUNC || os->kind == SK_IFUNC) return; 3684 if (os->kind == SK_SECTION || os->kind == SK_FILE) return; 3685 /* On descriptor-model TLS targets (Mach-O), obj_tls.c synthesizes 3686 * `__tlv_bootstrap` as an SK_UNDEF extern for the TLV descriptor's first 3687 * field. The C target delegates all TLS lowering to the host compiler via 3688 * `_Thread_local`, so this descriptor-time-only symbol has no place in the 3689 * emitted source. */ 3690 if (os->kind == SK_UNDEF && obj_format_tls_via_descriptor(t->c)) { 3691 const ObjBuilder* ob = t->obj; 3692 if (id == obj_tlv_bootstrap_get(ob)) return; 3693 } 3694 const char* nm = c_sym_name(t, id); 3695 CBuf* b = &t->data_defs; 3696 /* SK_TLS user-visible syms need a _Thread_local prefix. On ELF the sym 3697 * lives in .tdata/.tbss with the right bytes/size and our normal data 3698 * path handles them once we set the qualifier. On Mach-O the user-visible 3699 * sym is the 24-byte TLV descriptor — its bytes are not the user's data, 3700 * so we can't faithfully reproduce it in C; bail to a SKIP. */ 3701 int is_tls = (os->kind == SK_TLS); 3702 3703 /* Extern (undefined) data — only declare if referenced. We can't readily 3704 * distinguish "referenced as data" from "referenced as func address" here, 3705 * so declare it as `extern uint8_t name[];` only if it was actually 3706 * referenced from somewhere; otherwise it'd produce unused warnings. The 3707 * obj symbol's `referenced` bit is exactly the right signal. */ 3708 /* SK_TLS with no defining section = extern TLS — falls through to the 3709 * undef branch below with the `_Thread_local` qualifier. */ 3710 /* Extern: SK_UNDEF, or any other defined-kind sym that the producer 3711 * marked as having no defining section (the C frontend uses SK_OBJ + 3712 * section=NONE for `extern T x __attribute__((weak));`). */ 3713 int is_extern = (os->kind == SK_UNDEF) || 3714 (os->kind != SK_COMMON && os->section_id == OBJ_SEC_NONE); 3715 if (is_extern) { 3716 /* Always declare extern data syms in C source: the host cc tolerates 3717 * unused externs, and the ObjSym::referenced bit isn't reliably set on 3718 * syms the C target only addresses by writing the name into the source 3719 * (no relocation gets emitted against them). 3720 * 3721 * Weak externs need different attributes per object format: on Mach-O 3722 * the `weak` attribute requires a definition; the right spelling for an 3723 * undefined weak ref is `__attribute__((weak_import))`. On ELF/PE the 3724 * existing `weak` attribute works as expected. */ 3725 if (os->bind == SB_WEAK) { 3726 const ObjFormatImpl* fmt = obj_format_lookup(t->c->target.obj); 3727 const char* weak_attr = 3728 (fmt && fmt->weak_undef_attr) ? fmt->weak_undef_attr : "weak"; 3729 cbuf_puts(b, "__attribute__(("); 3730 cbuf_puts(b, weak_attr); 3731 cbuf_puts(b, ")) "); 3732 } 3733 if (os->vis == SV_HIDDEN) { 3734 cbuf_puts(b, "__attribute__((visibility(\"hidden\"))) "); 3735 } else if (os->vis == SV_PROTECTED) { 3736 cbuf_puts(b, "__attribute__((visibility(\"protected\"))) "); 3737 } 3738 cbuf_puts(b, "extern "); 3739 if (is_tls) cbuf_puts(b, "_Thread_local "); 3740 cbuf_puts(b, "uint8_t "); 3741 cbuf_puts(b, nm); 3742 cbuf_puts(b, "[];\n"); 3743 return; 3744 } 3745 if (is_tls && obj_format_tls_via_descriptor(t->c)) { 3746 /* Mach-O splits TLS across two object-file symbols (see obj_tls.c): the 3747 * user-visible sym is a 24-byte TLV descriptor in 3748 * __DATA,__thread_vars; the actual initial bytes live in a synthesized 3749 * `<name>$tlv$init` sym in __DATA,__thread_data (or __thread_bss). For 3750 * C source emission we don't need either of those — `_Thread_local` 3751 * delegates to the host C compiler, which builds its own descriptor. 3752 * 3753 * We use the descriptor sym as the carrier (its name is what user code 3754 * references) and pull the initial bytes/size/alignment from the init 3755 * sym, found via the R_ABS64 reloc at descriptor offset +16. The init 3756 * sym is skipped in its own iteration. */ 3757 const Section* desc_sec = obj_section_get(t->obj, os->section_id); 3758 if (c_sec_name_is_macho_tvars(t, desc_sec)) { 3759 ObjSymId init_id = 3760 c_macho_tls_find_init(t, os->section_id, (u32)os->value); 3761 if (init_id == OBJ_SYM_NONE) { 3762 compiler_panic(t->c, (SrcLoc){0, 0, 0}, 3763 "C target: Mach-O TLS descriptor missing init reloc"); 3764 } 3765 const ObjSym* init_os = obj_symbol_get(t->obj, init_id); 3766 if (!init_os || init_os->section_id == OBJ_SEC_NONE) { 3767 compiler_panic(t->c, (SrcLoc){0, 0, 0}, 3768 "C target: Mach-O TLS init sym not defined"); 3769 } 3770 const Section* init_sec = obj_section_get(t->obj, init_os->section_id); 3771 u32 init_base = (u32)init_os->value; 3772 u32 init_size = (u32)init_os->size; 3773 /* TLS data with relocations would need the constructor-fixup path 3774 * (and we'd have to rewrite the reloc target's section/offset to 3775 * the descriptor's name in the emitted C). No test currently 3776 * exercises this; surface it as a clear panic-as-skip if we hit it. */ 3777 if (c_sym_has_relocs(t, init_os->section_id, init_base, init_size)) { 3778 compiler_panic(t->c, (SrcLoc){0, 0, 0}, 3779 "C target: Mach-O TLS with pointer init not yet " 3780 "supported"); 3781 } 3782 if (os->bind == SB_LOCAL) cbuf_puts(b, "static "); 3783 cbuf_puts(b, "_Thread_local "); 3784 c_emit_link_attrs(b, os); 3785 cbuf_puts(b, "__attribute__((unused)) "); 3786 cbuf_puts(b, "_Alignas("); 3787 cbuf_put_u64(b, init_sec->align ? init_sec->align : 1); 3788 cbuf_puts(b, ") uint8_t "); 3789 cbuf_puts(b, nm); 3790 cbuf_puts(b, "["); 3791 cbuf_put_u64(b, init_size ? init_size : 1); 3792 cbuf_puts(b, "]"); 3793 if (init_sec->kind == SEC_BSS || init_sec->sem == SSEM_NOBITS || 3794 init_size == 0) { 3795 cbuf_puts(b, ";\n"); 3796 } else { 3797 Heap* h = t->c->ctx->heap; 3798 u8* bytes = (u8*)h->alloc(h, init_size, 1); 3799 if (!bytes) { 3800 compiler_panic(t->c, (SrcLoc){0, 0, 0}, 3801 "C target: oom on TLS init bytes"); 3802 } 3803 c_read_section_bytes(init_sec, init_base, bytes, init_size); 3804 c_emit_data_bytes(b, bytes, init_size); 3805 h->free(h, bytes, init_size); 3806 cbuf_puts(b, ";\n"); 3807 } 3808 return; 3809 } 3810 /* Not the descriptor: this is the synthesized `<name>$tlv$init` data 3811 * sym (or a __thread_ptrs entry). The descriptor case above already 3812 * emitted the user-facing _Thread_local; nothing more to do. */ 3813 return; 3814 } 3815 if (os->kind == SK_COMMON) { 3816 /* Common — uninitialized, with explicit alignment. Emit as 3817 * tentative-definition (`uint8_t name[size];` at file scope), which C 3818 * treats as a common-style definition under -fcommon. */ 3819 cbuf_puts(b, "__attribute__((unused)) _Alignas("); 3820 cbuf_put_u64(b, os->common_align ? os->common_align : 1); 3821 cbuf_puts(b, ") uint8_t "); 3822 cbuf_puts(b, nm); 3823 cbuf_puts(b, "["); 3824 cbuf_put_u64(b, os->size); 3825 cbuf_puts(b, "];\n"); 3826 return; 3827 } 3828 if (os->section_id == OBJ_SEC_NONE) return; 3829 const Section* sec = obj_section_get(t->obj, os->section_id); 3830 if (!c_is_data_section(sec)) return; 3831 u32 base = (u32)os->value; 3832 u32 size = (u32)os->size; 3833 u32 nrelocs = 0; 3834 u32 total_relocs = obj_reloc_total(t->obj); 3835 for (u32 i = 0; i < total_relocs; ++i) { 3836 const Reloc* r = obj_reloc_at(t->obj, i); 3837 if (r->section_id == os->section_id && r->offset >= base && 3838 r->offset < base + size) { 3839 nrelocs++; 3840 } 3841 } 3842 3843 Heap* h = t->c->ctx->heap; 3844 const Reloc** rs = NULL; 3845 if (nrelocs) { 3846 rs = (const Reloc**)h->alloc(h, nrelocs * sizeof(const Reloc*), 1); 3847 u32 j = 0; 3848 for (u32 i = 0; i < total_relocs; ++i) { 3849 const Reloc* r = obj_reloc_at(t->obj, i); 3850 if (r->section_id == os->section_id && r->offset >= base && 3851 r->offset < base + size) { 3852 rs[j++] = r; 3853 } 3854 } 3855 for (u32 i = 1; i < nrelocs; ++i) { 3856 const Reloc* tmp = rs[i]; 3857 u32 k = i; 3858 while (k > 0 && rs[k - 1]->offset > tmp->offset) { 3859 rs[k] = rs[k - 1]; 3860 k--; 3861 } 3862 rs[k] = tmp; 3863 } 3864 /* The C backend can only render an absolute address (&sym as a pointer 3865 * value) into a data slot. A PC-relative or section-difference reloc is 3866 * not a C constant expression, and a sub-pointer-width address cannot be 3867 * truncated into its slot in portable C — reject those rather than 3868 * silently mis-size the slot (the width logic below assumes ABS32/ABS64). 3869 */ 3870 for (u32 i = 0; i < nrelocs; ++i) { 3871 if (rs[i]->kind != R_ABS32 && rs[i]->kind != R_ABS64) 3872 compiler_panic(t->c, (SrcLoc){0, 0, 0}, 3873 "C target: unsupported non-absolute data relocation " 3874 "(kind %u) targeting '%s'; the C backend emits only " 3875 "absolute (R_ABS32/R_ABS64) data relocations", 3876 (unsigned)rs[i]->kind, c_sym_name(t, rs[i]->sym)); 3877 } 3878 } 3879 3880 cbuf_puts(b, "struct "); 3881 if (nrelocs > 0) cbuf_puts(b, "__attribute__((packed)) "); 3882 cbuf_puts(b, "__kit_data_"); 3883 cbuf_puts(b, nm); 3884 cbuf_puts(b, " {\n"); 3885 3886 if (nrelocs == 0) { 3887 cbuf_puts(b, " uint8_t raw["); 3888 cbuf_put_u64(b, size ? size : 1); 3889 cbuf_puts(b, "];\n"); 3890 } else { 3891 u32 cur = base; 3892 for (u32 i = 0; i < nrelocs; ++i) { 3893 const Reloc* r = rs[i]; 3894 if (r->offset > cur) { 3895 cbuf_puts(b, " uint8_t chunk_"); 3896 cbuf_put_u64(b, i); 3897 cbuf_puts(b, "["); 3898 cbuf_put_u64(b, r->offset - cur); 3899 cbuf_puts(b, "];\n"); 3900 } 3901 u32 width = (r->kind == R_ABS32) ? 4 : 8; 3902 const char* ty = (width == 4) ? "uint32_t" : "void*"; 3903 cbuf_puts(b, " "); 3904 cbuf_puts(b, ty); 3905 cbuf_puts(b, " ptr_"); 3906 cbuf_put_u64(b, i); 3907 cbuf_puts(b, ";\n"); 3908 cur = r->offset + width; 3909 } 3910 if (cur < base + size) { 3911 cbuf_puts(b, " uint8_t chunk_"); 3912 cbuf_put_u64(b, nrelocs); 3913 cbuf_puts(b, "["); 3914 cbuf_put_u64(b, base + size - cur); 3915 cbuf_puts(b, "];\n"); 3916 } 3917 } 3918 cbuf_puts(b, "};\n"); 3919 3920 if (os->bind == SB_LOCAL) cbuf_puts(b, "static "); 3921 if (is_tls) cbuf_puts(b, "_Thread_local "); 3922 c_emit_link_attrs(b, os); 3923 cbuf_puts(b, "__attribute__((unused)) "); 3924 3925 int is_ro = (sec->kind == SEC_RODATA); 3926 if (is_ro) cbuf_puts(b, "const "); 3927 3928 cbuf_puts(b, "_Alignas("); 3929 cbuf_put_u64(b, sec->align ? sec->align : 1); 3930 cbuf_puts(b, ") struct __kit_data_"); 3931 cbuf_puts(b, nm); 3932 cbuf_puts(b, " "); 3933 cbuf_puts(b, nm); 3934 3935 if (sec->kind == SEC_BSS || sec->sem == SSEM_NOBITS) { 3936 cbuf_puts(b, ";\n"); 3937 } else if (size == 0) { 3938 cbuf_puts(b, " = {{0}};\n"); 3939 } else { 3940 cbuf_puts(b, " = {\n"); 3941 u8* bytes = (u8*)h->alloc(h, size, 1); 3942 c_read_section_bytes(sec, base, bytes, size); 3943 3944 if (nrelocs == 0) { 3945 cbuf_puts(b, " .raw = {"); 3946 for (u32 i = 0; i < size; ++i) { 3947 if (i > 0) cbuf_puts(b, ", "); 3948 cbuf_put_u64(b, bytes[i]); 3949 } 3950 cbuf_puts(b, "}\n"); 3951 } else { 3952 u32 cur = base; 3953 for (u32 i = 0; i < nrelocs; ++i) { 3954 const Reloc* r = rs[i]; 3955 if (r->offset > cur) { 3956 cbuf_puts(b, " .chunk_"); 3957 cbuf_put_u64(b, i); 3958 cbuf_puts(b, " = {"); 3959 for (u32 k = 0; k < r->offset - cur; ++k) { 3960 if (k > 0) cbuf_puts(b, ", "); 3961 cbuf_put_u64(b, bytes[cur - base + k]); 3962 } 3963 cbuf_puts(b, "},\n"); 3964 } 3965 3966 u32 width = (r->kind == R_ABS32) ? 4 : 8; 3967 c_ensure_forward_decl(t, r->sym, 0); 3968 const char* tgt = c_sym_name(t, r->sym); 3969 const char* cast = (width == 4) ? "(uint32_t)(uintptr_t)" : "(void*)"; 3970 3971 cbuf_puts(b, " .ptr_"); 3972 cbuf_put_u64(b, i); 3973 cbuf_puts(b, " = "); 3974 cbuf_puts(b, cast); 3975 cbuf_puts(b, "((char*)&"); 3976 cbuf_puts(b, tgt); 3977 if (r->addend != 0) { 3978 cbuf_puts(b, " + "); 3979 cbuf_put_i64(b, r->addend); 3980 } 3981 cbuf_puts(b, "),\n"); 3982 cur = r->offset + width; 3983 } 3984 if (cur < base + size) { 3985 cbuf_puts(b, " .chunk_"); 3986 cbuf_put_u64(b, nrelocs); 3987 cbuf_puts(b, " = {"); 3988 for (u32 k = 0; k < base + size - cur; ++k) { 3989 if (k > 0) cbuf_puts(b, ", "); 3990 cbuf_put_u64(b, bytes[cur - base + k]); 3991 } 3992 cbuf_puts(b, "}\n"); 3993 } 3994 } 3995 h->free(h, bytes, size); 3996 cbuf_puts(b, "};\n"); 3997 } 3998 3999 if (nrelocs) h->free(h, (void*)rs, nrelocs * sizeof(const Reloc*)); 4000 } 4001 4002 /* Re-emit a file-scope `__asm__("...")` block at TU scope. The CG layer hands 4003 * us the de-escaped assembly text (real newlines); re-quote it as a single C 4004 * string literal so the host C compiler assembles it. Lands in data_defs, which 4005 * finalize flushes at file scope before any function body. */ 4006 void c_emit_file_scope_asm(CTarget* t, const char* src, size_t len) { 4007 CBuf* b = &t->data_defs; 4008 cbuf_puts(b, "__asm__(\""); 4009 for (size_t i = 0; i < len; ++i) { 4010 char ch = src[i]; 4011 switch (ch) { 4012 case '\\': 4013 cbuf_puts(b, "\\\\"); 4014 break; 4015 case '"': 4016 cbuf_puts(b, "\\\""); 4017 break; 4018 case '\n': 4019 cbuf_puts(b, "\\n"); 4020 break; 4021 case '\t': 4022 cbuf_puts(b, "\\t"); 4023 break; 4024 case '\r': 4025 cbuf_puts(b, "\\r"); 4026 break; 4027 default: 4028 cbuf_putc(b, ch); 4029 break; 4030 } 4031 } 4032 cbuf_puts(b, "\");\n"); 4033 } 4034 4035 static void c_emit_data(CTarget* t) { 4036 ObjSymIter* it = obj_symiter_new(t->obj); 4037 if (!it) return; 4038 ObjSymEntry e; 4039 while (obj_symiter_next(it, &e)) { 4040 if (!e.sym) continue; 4041 c_emit_data_symbol(t, e.id, e.sym); 4042 } 4043 obj_symiter_free(it); 4044 } 4045 4046 /* === finalize / destroy === */ 4047 4048 void c_emit_finalize(CTarget* t) { 4049 if (t->finalized) return; 4050 t->finalized = 1; 4051 c_emit_prologue(t); 4052 if (t->need_stdarg) c_writer_puts(t, "#include <stdarg.h>\n"); 4053 if (t->need_setjmp) c_writer_puts(t, "#include <setjmp.h>\n"); 4054 if (t->need_stdarg || t->need_setjmp) c_writer_puts(t, "\n"); 4055 if (t->typedefs.len) { 4056 c_writer_write(t, t->typedefs.data, t->typedefs.len); 4057 c_writer_puts(t, "\n"); 4058 } 4059 c_emit_data(t); 4060 if (t->forwards.len) { 4061 c_writer_write(t, t->forwards.data, t->forwards.len); 4062 c_writer_puts(t, "\n"); 4063 } 4064 if (t->data_defs.len) { 4065 c_writer_write(t, t->data_defs.data, t->data_defs.len); 4066 c_writer_puts(t, "\n"); 4067 } 4068 if (t->body.len) c_writer_write(t, t->body.data, t->body.len); 4069 } 4070 4071 void c_emit_destroy(CTarget* t) { 4072 Heap* h = t->c->ctx->heap; 4073 cbuf_fini(&t->forwards); 4074 cbuf_fini(&t->typedefs); 4075 cbuf_fini(&t->data_defs); 4076 cbuf_fini(&t->decls); 4077 cbuf_fini(&t->body); 4078 if (t->sym_forwarded) h->free(h, t->sym_forwarded, t->sym_forwarded_cap); 4079 t->sym_forwarded = NULL; 4080 t->sym_forwarded_cap = 0; 4081 if (t->local_static_syms) { 4082 h->free(h, t->local_static_syms, 4083 t->local_static_syms_cap * sizeof(*t->local_static_syms)); 4084 } 4085 if (t->local_static_entries) { 4086 h->free(h, t->local_static_entries, 4087 t->local_static_entries_cap * sizeof(*t->local_static_entries)); 4088 } 4089 if (t->local_declared) h->free(h, t->local_declared, t->local_cap); 4090 if (t->local_type) 4091 h->free(h, t->local_type, t->local_cap * sizeof(KitCgTypeId)); 4092 if (t->scopes) h->free(h, t->scopes, t->scopes_cap * sizeof(CScopeInfo)); 4093 t->local_declared = NULL; 4094 t->local_type = NULL; 4095 t->scopes = NULL; 4096 t->local_static_syms = NULL; 4097 t->local_static_entries = NULL; 4098 t->local_cap = 0; 4099 t->scopes_cap = 0; 4100 t->local_static_syms_cap = 0; 4101 t->local_static_entries_cap = 0; 4102 t->local_static_nsyms = 0; 4103 t->local_static_nentries = 0; 4104 }