cg_adapter.c (49982B)
1 #include <string.h> 2 3 #include "parse/parse_priv.h" 4 5 KitCgTypeId pcg_tid(Parser* p, const Type* ty) { 6 return type_cg_id_in_pool(p->c, p->pool, ty); 7 } 8 9 /* Set both a slot's C type and its lowered CG id together so the two never 10 * drift. Every site that writes slot->type must go through this (or copy a 11 * whole slot, which carries cg_id along). The id is lowered lazily on first 12 * read (pcg_slot_cg_id), not here, so an incomplete record stamped at push time 13 * still lowers to its real layout once completed -- identical to a direct 14 * type_cg_id_in_pool call. */ 15 static void pcg_slot_set_type(PcgSlot* s, const Type* ty) { 16 s->type = ty; 17 s->cg_id = KIT_CG_TYPE_NONE; /* lazily lowered on first read */ 18 } 19 20 /* The slot's lowered CG id, lowering+caching on first read. A NULL type yields 21 * KIT_CG_TYPE_NONE every time (the sentinel also means "unfilled", but 22 * type_cg_id_in_pool(NULL) is constant so re-lowering is free). For a real type 23 * the first read crosses the bridge once; later reads are a load. */ 24 static KitCgTypeId pcg_slot_cg_id(Parser* p, PcgSlot* s) { 25 if (s->cg_id == KIT_CG_TYPE_NONE && s->type) 26 s->cg_id = type_cg_id_in_pool(p->c, p->pool, s->type); 27 return s->cg_id; 28 } 29 30 /* The cached CG id of the TOS slot's type, lowering lazily on first read. 31 * Empty-stack-safe (returns NONE), matching pcg_tid(p, pcg_top_type(p)). */ 32 static KitCgTypeId pcg_top_cg_id(Parser* p) { 33 return p->cg_type_sp 34 ? pcg_slot_cg_id(p, &p->cg_slot_stack[p->cg_type_sp - 1u]) 35 : KIT_CG_TYPE_NONE; 36 } 37 38 /* The cached CG id of the depth-2 slot's type (matching pcg_top2_type). */ 39 static KitCgTypeId pcg_top2_cg_id(Parser* p) { 40 return p->cg_type_sp >= 2 41 ? pcg_slot_cg_id(p, &p->cg_slot_stack[p->cg_type_sp - 2u]) 42 : KIT_CG_TYPE_NONE; 43 } 44 45 #define PCG_VALUE_LVALUE 1u 46 #define PCG_VALUE_MODIFIABLE 2u 47 #define PCG_VALUE_BITFIELD 4u 48 #define PCG_VALUE_NULL_PTR_CONST 8u 49 #define PCG_VALUE_REGISTER 16u 50 51 static u8 pcg_lvalue_flags_for_type(const Type* ty) { 52 u8 flags = PCG_VALUE_LVALUE; 53 if (ty && !(ty->qual & Q_CONST) && ty->kind != TY_ARRAY && 54 ty->kind != TY_FUNC && ty->kind != TY_VOID) { 55 flags |= PCG_VALUE_MODIFIABLE; 56 } 57 return flags; 58 } 59 60 /* Build a MemAccess from an already-lowered CG id plus the C type (for its 61 * qualifiers). Lets a caller that already has the slot's cached cg_id skip the 62 * type_cg_id_in_pool re-crossing pcg_mem(ty) does twice (lower + align). */ 63 static KitCgMemAccess pcg_mem_id(Parser* p, KitCgTypeId id, const Type* ty) { 64 KitCgMemAccess m; 65 memset(&m, 0, sizeof m); 66 m.type = id; 67 m.align = (u32)kit_cg_type_align(p->c, id); 68 if (ty && (ty->qual & Q_VOLATILE)) m.flags |= KIT_CG_MEM_VOLATILE; 69 if (type_is_int(ty) && pcg_type_is_signed(ty)) 70 m.flags |= KIT_CG_MEM_SOURCE_SIGNED; 71 return m; 72 } 73 74 KitCgMemAccess pcg_mem(Parser* p, const Type* ty) { 75 return pcg_mem_id(p, pcg_tid(p, ty), ty); 76 } 77 78 static void pcg_aux_clear(PcgLvAux* a) { 79 a->offset = 0; 80 a->scale = 0; 81 a->bit_offset = 0; 82 a->bit_width = 0; 83 a->storage_size = 0; 84 a->bit_signed = 0; 85 a->base_kind = PCG_LV_BASE_LOCAL; 86 a->is_subobject = 0; 87 a->pad[0] = a->pad[1] = a->pad[2] = a->pad[3] = a->pad[4] = 0; 88 } 89 90 static void pcg_stack_grow(Parser* p, u32 want) { 91 PcgSlot* ns; 92 u32 nc; 93 if (p->cg_type_cap >= want) return; 94 nc = p->cg_type_cap ? p->cg_type_cap * 2u : 64u; 95 while (nc < want) nc *= 2u; 96 ns = arena_zarray(p->pool->arena, PcgSlot, nc); 97 if (!ns) perr(p, "out of memory in CG shadow stack"); 98 if (p->cg_slot_stack && p->cg_type_sp) 99 memcpy(ns, p->cg_slot_stack, sizeof(*ns) * p->cg_type_sp); 100 p->cg_slot_stack = ns; 101 p->cg_type_cap = nc; 102 } 103 104 void pcg_push_type(Parser* p, const Type* ty) { 105 PcgSlot* s; 106 pcg_stack_grow(p, p->cg_type_sp + 1u); 107 s = &p->cg_slot_stack[p->cg_type_sp]; 108 pcg_slot_set_type(s, ty); 109 s->flags = 0; 110 pcg_aux_clear(&s->aux); 111 ++p->cg_type_sp; 112 } 113 114 void pcg_drop_type(Parser* p) { 115 if (p->cg_type_sp) --p->cg_type_sp; 116 } 117 118 void pcg_dup_type(Parser* p) { 119 PcgSlot top; 120 if (p->cg_type_sp) { 121 top = p->cg_slot_stack[p->cg_type_sp - 1u]; 122 } else { 123 pcg_slot_set_type(&top, NULL); 124 top.flags = 0; 125 pcg_aux_clear(&top.aux); 126 } 127 /* Copy the slot out before push: pcg_stack_grow may reallocate. The whole 128 * slot (cg_id included) is copied back at the end, so dup preserves the id. 129 */ 130 pcg_push_type(p, top.type); 131 if (p->cg_type_sp) p->cg_slot_stack[p->cg_type_sp - 1u] = top; 132 } 133 134 void pcg_swap_type(Parser* p) { 135 if (p->cg_type_sp >= 2) { 136 PcgSlot tmp = p->cg_slot_stack[p->cg_type_sp - 1u]; 137 p->cg_slot_stack[p->cg_type_sp - 1u] = p->cg_slot_stack[p->cg_type_sp - 2u]; 138 p->cg_slot_stack[p->cg_type_sp - 2u] = tmp; 139 } 140 } 141 142 void pcg_rot3_type(Parser* p) { 143 if (p->cg_type_sp >= 3) { 144 PcgSlot a = p->cg_slot_stack[p->cg_type_sp - 3u]; 145 p->cg_slot_stack[p->cg_type_sp - 3u] = p->cg_slot_stack[p->cg_type_sp - 2u]; 146 p->cg_slot_stack[p->cg_type_sp - 2u] = p->cg_slot_stack[p->cg_type_sp - 1u]; 147 p->cg_slot_stack[p->cg_type_sp - 1u] = a; 148 } 149 } 150 151 /* Structural CG ops that must keep the parser's typed shadow stack in lockstep 152 * with the CG stack: each emits the CG op (when codegen is enabled) and mirrors 153 * the same structural effect onto the type stack. */ 154 void pcg_dup(Parser* p) { 155 if (pcg_emit_enabled(p)) kit_cg_dup(p->cg); 156 pcg_dup_type(p); 157 } 158 159 void pcg_swap(Parser* p) { 160 if (pcg_emit_enabled(p)) kit_cg_swap(p->cg); 161 pcg_swap_type(p); 162 } 163 164 void pcg_drop(Parser* p) { 165 if (pcg_emit_enabled(p)) kit_cg_drop(p->cg); 166 pcg_drop_type(p); 167 } 168 169 /* Reclaim dead compiler-temp slots at a statement boundary. The authoritative 170 * "no value is live" witness is the CG value stack depth, which 171 * kit_cg_reclaim_temps checks (g->sp == 0): a stray non-empty call is a safe 172 * no-op rather than a miscompile. (The parser's typed shadow stack cg_type_sp 173 * is NOT a reliable witness — it is not drained in lockstep with the value 174 * stack.) */ 175 void pcg_reclaim_temps(Parser* p) { 176 if (!pcg_emit_enabled(p)) return; 177 kit_cg_reclaim_temps(p->cg); 178 } 179 180 PcgLvAux* pcg_top_lv_aux(Parser* p) { 181 return p->cg_type_sp ? &p->cg_slot_stack[p->cg_type_sp - 1u].aux : NULL; 182 } 183 184 PcgLvAux* pcg_lv_aux_at(Parser* p, u32 depth) { 185 return (p->cg_type_sp > depth) 186 ? &p->cg_slot_stack[p->cg_type_sp - 1u - depth].aux 187 : NULL; 188 } 189 190 const Type* pcg_top_type(Parser* p) { 191 return p->cg_type_sp ? p->cg_slot_stack[p->cg_type_sp - 1u].type : NULL; 192 } 193 194 const Type* pcg_top2_type(Parser* p) { 195 return p->cg_type_sp >= 2 ? p->cg_slot_stack[p->cg_type_sp - 2u].type : NULL; 196 } 197 198 void pcg_retag_top(Parser* p, const Type* ty) { 199 if (p->cg_type_sp) { 200 pcg_slot_set_type(&p->cg_slot_stack[p->cg_type_sp - 1u], ty); 201 p->cg_slot_stack[p->cg_type_sp - 1u].flags = 0; 202 pcg_aux_clear(&p->cg_slot_stack[p->cg_type_sp - 1u].aux); 203 } 204 } 205 206 /* Replace the type of the slot `depth` below the top (depth 0 == top) while 207 * preserving its value flags and lvalue aux. Unlike pcg_retag_top this keeps 208 * the slot's lvalue-ness/bitfield/aux intact — used where only the C type 209 * changes (e.g. struct unqualification, narrowing a compound-assign LHS). */ 210 void pcg_retag_keep_flags(Parser* p, u32 depth, const Type* ty) { 211 if (p->cg_type_sp > depth) 212 pcg_slot_set_type(&p->cg_slot_stack[p->cg_type_sp - 1u - depth], ty); 213 } 214 215 int pcg_top_is_bitfield(Parser* p) { 216 return p->cg_type_sp && 217 (p->cg_slot_stack[p->cg_type_sp - 1u].flags & PCG_VALUE_BITFIELD) != 0; 218 } 219 220 void pcg_set_top_bitfield(Parser* p) { 221 if (p->cg_type_sp) 222 p->cg_slot_stack[p->cg_type_sp - 1u].flags |= PCG_VALUE_BITFIELD; 223 } 224 225 int pcg_top_is_register(Parser* p) { 226 return p->cg_type_sp && 227 (p->cg_slot_stack[p->cg_type_sp - 1u].flags & PCG_VALUE_REGISTER) != 0; 228 } 229 230 void pcg_set_top_register(Parser* p) { 231 if (p->cg_type_sp) 232 p->cg_slot_stack[p->cg_type_sp - 1u].flags |= PCG_VALUE_REGISTER; 233 } 234 235 int pcg_top_is_lvalue(Parser* p) { 236 return p->cg_type_sp && 237 (p->cg_slot_stack[p->cg_type_sp - 1u].flags & PCG_VALUE_LVALUE) != 0; 238 } 239 240 int pcg_top_is_modifiable_lvalue(Parser* p) { 241 return p->cg_type_sp && (p->cg_slot_stack[p->cg_type_sp - 1u].flags & 242 (PCG_VALUE_LVALUE | PCG_VALUE_MODIFIABLE)) == 243 (PCG_VALUE_LVALUE | PCG_VALUE_MODIFIABLE); 244 } 245 246 int pcg_top_is_null_ptr_const(Parser* p) { 247 return p->cg_type_sp && (p->cg_slot_stack[p->cg_type_sp - 1u].flags & 248 PCG_VALUE_NULL_PTR_CONST) != 0; 249 } 250 251 void pcg_set_top_lvalue(Parser* p) { 252 const Type* ty = pcg_top_type(p); 253 if (p->cg_type_sp) 254 p->cg_slot_stack[p->cg_type_sp - 1u].flags = pcg_lvalue_flags_for_type(ty); 255 } 256 257 int pcg_emit_enabled(Parser* p) { return p && p->suppress_codegen == 0; } 258 259 void pcg_codegen_suppress_push(Parser* p) { 260 if (p) ++p->suppress_codegen; 261 } 262 263 void pcg_codegen_suppress_pop(Parser* p) { 264 if (!p) return; 265 if (!p->suppress_codegen) 266 perr(p, "internal parser codegen suppression underflow"); 267 --p->suppress_codegen; 268 } 269 270 int pcg_type_is_fp(const Type* ty) { 271 return ty && type_kind_is_fp((TypeKind)ty->kind); 272 } 273 274 int pcg_type_is_signed(const Type* ty) { return type_is_signed_integer(ty); } 275 276 KitCgIntBinOp pcg_int_binop(BinOp op) { 277 switch (op) { 278 case BO_IADD: 279 return KIT_CG_INT_ADD; 280 case BO_ISUB: 281 return KIT_CG_INT_SUB; 282 case BO_IMUL: 283 return KIT_CG_INT_MUL; 284 case BO_SDIV: 285 return KIT_CG_INT_SDIV; 286 case BO_UDIV: 287 return KIT_CG_INT_UDIV; 288 case BO_SREM: 289 return KIT_CG_INT_SREM; 290 case BO_UREM: 291 return KIT_CG_INT_UREM; 292 case BO_AND: 293 return KIT_CG_INT_AND; 294 case BO_OR: 295 return KIT_CG_INT_OR; 296 case BO_XOR: 297 return KIT_CG_INT_XOR; 298 case BO_SHL: 299 return KIT_CG_INT_SHL; 300 case BO_SHR_S: 301 return KIT_CG_INT_ASHR; 302 case BO_SHR_U: 303 return KIT_CG_INT_LSHR; 304 default: 305 return KIT_CG_INT_ADD; 306 } 307 } 308 309 KitCgFpBinOp pcg_fp_binop(BinOp op) { 310 switch (op) { 311 case BO_FADD: 312 return KIT_CG_FP_ADD; 313 case BO_FSUB: 314 return KIT_CG_FP_SUB; 315 case BO_FMUL: 316 return KIT_CG_FP_MUL; 317 case BO_FDIV: 318 return KIT_CG_FP_DIV; 319 default: 320 return KIT_CG_FP_ADD; 321 } 322 } 323 324 KitCgIntCmpOp pcg_int_cmp(CmpOp op) { 325 switch (op) { 326 case CMP_EQ: 327 return KIT_CG_INT_EQ; 328 case CMP_NE: 329 return KIT_CG_INT_NE; 330 case CMP_LT_S: 331 return KIT_CG_INT_LT_S; 332 case CMP_LE_S: 333 return KIT_CG_INT_LE_S; 334 case CMP_GT_S: 335 return KIT_CG_INT_GT_S; 336 case CMP_GE_S: 337 return KIT_CG_INT_GE_S; 338 case CMP_LT_U: 339 return KIT_CG_INT_LT_U; 340 case CMP_LE_U: 341 return KIT_CG_INT_LE_U; 342 case CMP_GT_U: 343 return KIT_CG_INT_GT_U; 344 case CMP_GE_U: 345 return KIT_CG_INT_GE_U; 346 default: 347 return KIT_CG_INT_EQ; 348 } 349 } 350 351 KitCgFpCmpOp pcg_fp_cmp(CmpOp op) { 352 switch (op) { 353 case CMP_EQ: 354 return KIT_CG_FP_OEQ; 355 case CMP_NE: 356 /* C `!=` on floats is *unordered* not-equal: `NaN != x` is true (and 357 * `__builtin_isnan(x)` lowers to `x != x`). Map to UNE, not ONE. */ 358 return KIT_CG_FP_UNE; 359 case CMP_LT_F: 360 case CMP_OLT_F: 361 return KIT_CG_FP_OLT; 362 case CMP_LE_F: 363 case CMP_OLE_F: 364 return KIT_CG_FP_OLE; 365 case CMP_GT_F: 366 case CMP_OGT_F: 367 return KIT_CG_FP_OGT; 368 case CMP_GE_F: 369 case CMP_OGE_F: 370 return KIT_CG_FP_OGE; 371 case CMP_OEQ_F: 372 return KIT_CG_FP_OEQ; 373 case CMP_ONE_F: 374 return KIT_CG_FP_ONE; 375 case CMP_UEQ_F: 376 return KIT_CG_FP_UEQ; 377 case CMP_UNE_F: 378 return KIT_CG_FP_UNE; 379 case CMP_ULT_F: 380 return KIT_CG_FP_ULT; 381 case CMP_ULE_F: 382 return KIT_CG_FP_ULE; 383 case CMP_UGT_F: 384 return KIT_CG_FP_UGT; 385 case CMP_UGE_F: 386 return KIT_CG_FP_UGE; 387 default: 388 return KIT_CG_FP_OEQ; 389 } 390 } 391 392 KitCgAtomicOp pcg_atomic_op(AtomicOp op) { 393 switch (op) { 394 case AO_XCHG: 395 return KIT_CG_ATOMIC_XCHG; 396 case AO_ADD: 397 return KIT_CG_ATOMIC_ADD; 398 case AO_SUB: 399 return KIT_CG_ATOMIC_SUB; 400 case AO_AND: 401 return KIT_CG_ATOMIC_AND; 402 case AO_OR: 403 return KIT_CG_ATOMIC_OR; 404 case AO_XOR: 405 return KIT_CG_ATOMIC_XOR; 406 case AO_NAND: 407 return KIT_CG_ATOMIC_NAND; 408 } 409 return KIT_CG_ATOMIC_XCHG; 410 } 411 412 KitCgMemOrder pcg_mem_order(MemOrder ord) { return (KitCgMemOrder)ord; } 413 414 static int pcg_slot_is_volatile(const FrameSlotDesc* fsd) { 415 return fsd && ((fsd->flags & FSF_VOLATILE) || 416 (fsd->type && (fsd->type->qual & Q_VOLATILE))); 417 } 418 419 FrameSlot pcg_local(Parser* p, const FrameSlotDesc* fsd) { 420 KitCgLocalAttrs attrs; 421 memset(&attrs, 0, sizeof attrs); 422 if (!pcg_emit_enabled(p)) return FRAME_SLOT_NONE; 423 attrs.name = fsd->name; 424 attrs.align = fsd->align; 425 if (pcg_slot_is_volatile(fsd)) attrs.flags |= KIT_CG_LOCAL_MEMORY_REQUIRED; 426 /* FSF_ADDR_TAKEN is no longer propagated to CG: there is no 427 * KIT_CG_LOCAL_ADDRESS_TAKEN attribute. The C-side flag stays for any 428 * parser-internal uses; opt's opt_promote_scalar_locals (Stream I) decides 429 * register-promotion from observed access patterns, not from the flag. */ 430 return kit_cg_local(p->cg, pcg_tid(p, fsd->type), attrs); 431 } 432 433 FrameSlot pcg_param_slot(Parser* p, u32 index, const FrameSlotDesc* fsd) { 434 KitCgLocalAttrs attrs; 435 if (!pcg_emit_enabled(p)) return FRAME_SLOT_NONE; 436 memset(&attrs, 0, sizeof attrs); 437 attrs.name = fsd->name; 438 attrs.align = fsd->align; 439 if (pcg_slot_is_volatile(fsd)) attrs.flags |= KIT_CG_LOCAL_MEMORY_REQUIRED; 440 return kit_cg_param(p->cg, index, pcg_tid(p, fsd->type), attrs); 441 } 442 443 void pcg_param(Parser* p, const CGParamDesc* pd) { 444 (void)p; 445 (void)pd; 446 } 447 448 void pcg_func_begin(Parser* p, const CGFuncDesc* fd) { 449 if (pcg_emit_enabled(p)) { 450 KitCgFuncAttrs attrs; 451 memset(&attrs, 0, sizeof attrs); 452 attrs.inline_policy = fd->inline_policy; 453 if (fd->flags & CGFD_NORETURN) attrs.flags |= KIT_CG_FUNC_NORETURN; 454 kit_cg_func_begin_attrs(p->cg, fd->sym, attrs); 455 } 456 } 457 458 void pcg_func_end(Parser* p) { 459 if (pcg_emit_enabled(p)) kit_cg_func_end(p->cg); 460 } 461 462 void pcg_set_loc(Parser* p, SrcLoc loc) { 463 if (pcg_emit_enabled(p)) kit_cg_set_loc(p->cg, loc); 464 } 465 466 void pcg_push_int(Parser* p, i64 v, const Type* ty) { 467 if (pcg_emit_enabled(p)) { 468 kit_cg_push_int(p->cg, (uint64_t)v, pcg_tid(p, ty)); 469 } 470 pcg_push_type(p, ty); 471 if (v == 0 && p->cg_type_sp) { 472 p->cg_slot_stack[p->cg_type_sp - 1u].flags |= PCG_VALUE_NULL_PTR_CONST; 473 } 474 } 475 476 void pcg_push_float(Parser* p, double v, const Type* ty) { 477 if (pcg_emit_enabled(p)) kit_cg_push_float(p->cg, v, pcg_tid(p, ty)); 478 pcg_push_type(p, ty); 479 } 480 481 /* Tag the TOS place as a bit-field place when `lv` carries bit-field geometry. 482 * The frontend builds the storage-unit place itself (materialize + deref), so 483 * it attaches the descriptor here; a plain load/store then extracts/inserts the 484 * field. Must be called on the place each time a fresh one is built (each deref 485 * yields a plain place). No-op for non-bit-field lvalues. */ 486 static void pcg_apply_bitfield(Parser* p, const PcgLvAux* lv) { 487 if (lv && lv->bit_width) { 488 kit_cg_field_bits(p->cg, lv->bit_offset, lv->bit_width, lv->storage_size, 489 lv->bit_signed); 490 } 491 } 492 493 /* A trivially-addressable lvalue: a bare local slot with no pending field 494 * offset, array scale, or bit-field. Its PLACE is already on the CG stack 495 * (push_local), so a load/store can consume it directly without first 496 * materializing an address. */ 497 static int pcg_lv_is_trivial_local(const PcgLvAux* lv) { 498 return lv && lv->base_kind == PCG_LV_BASE_LOCAL && lv->offset == 0 && 499 lv->scale == 0 && lv->bit_width == 0; 500 } 501 502 /* Materialize the TOS lvalue (folding its pending field offset / array scale 503 * into the address) as a single pointer rvalue. Defined below; the memops use 504 * it to build an explicit place before load/store. */ 505 static void pcg_materialize_lv_to_ptr(Parser* p, const Type* result_ptr_ty); 506 static void pcg_lv_to_memop_place(Parser* p, const Type* field_ty); 507 508 void pcg_push_local_typed(Parser* p, FrameSlot s, const Type* ty) { 509 if (pcg_emit_enabled(p)) kit_cg_push_local(p->cg, s); 510 pcg_push_type(p, ty); 511 if (p->cg_type_sp) { 512 p->cg_slot_stack[p->cg_type_sp - 1u].flags = pcg_lvalue_flags_for_type(ty); 513 p->cg_slot_stack[p->cg_type_sp - 1u].aux.base_kind = PCG_LV_BASE_LOCAL; 514 } 515 } 516 517 void pcg_push_global(Parser* p, ObjSymId sym, const Type* ty) { 518 /* push_symbol_addr produces a pointer rvalue; the parser tags the slot as 519 * a C-language lvalue with PCG_LV_BASE_POINTER_RV so subsequent 520 * load/store/addr know the base is already a pointer. The cg layer accepts 521 * pointer-rvalue bases for memops uniformly (Stream A). */ 522 if (pcg_emit_enabled(p)) kit_cg_push_symbol_addr(p->cg, sym, 0); 523 pcg_push_type(p, ty); 524 if (p->cg_type_sp) { 525 p->cg_slot_stack[p->cg_type_sp - 1u].flags = pcg_lvalue_flags_for_type(ty); 526 p->cg_slot_stack[p->cg_type_sp - 1u].aux.base_kind = PCG_LV_BASE_POINTER_RV; 527 } 528 } 529 530 void pcg_load(Parser* p) { 531 const Type* ty = pcg_top_type(p); 532 int was_lvalue = pcg_top_is_lvalue(p); 533 if (pcg_emit_enabled(p)) { 534 PcgLvAux* lv = pcg_top_lv_aux(p); 535 KitCgTypeId cg_id = pcg_top_cg_id(p); /* cached TOS-slot id, lowered once */ 536 KitCgMemAccess access = pcg_mem_id(p, cg_id, ty); 537 /* Snapshot bit-field geometry before materialize clears the aux. */ 538 PcgLvAux bf = lv ? *lv : (PcgLvAux){0}; 539 /* Build the PLACE the strict load requires. A trivial local already has its 540 * PLACE on the CG stack (push_local) and loads directly; anything else is 541 * reduced to a single pointer (materialize, or a pointer-rvalue base) and 542 * then deref'd to a place. A bit-field place is then tagged with its bit 543 * geometry so the load extracts the field. */ 544 if (!was_lvalue || !pcg_lv_is_trivial_local(lv)) { 545 if (was_lvalue) 546 pcg_lv_to_memop_place(p, ty); 547 else 548 kit_cg_deref(p->cg, 0); 549 } 550 pcg_apply_bitfield(p, &bf); 551 kit_cg_load(p->cg, access); 552 } 553 if (was_lvalue && p->cg_type_sp) { 554 /* The emit block above can rewrite the TOS slot's type (materialize / 555 * deref push/drop), so restore it to the loaded value's type `ty` here -- 556 * stamping cg_id alongside it. */ 557 pcg_slot_set_type(&p->cg_slot_stack[p->cg_type_sp - 1u], ty); 558 p->cg_slot_stack[p->cg_type_sp - 1u].flags = 0; 559 pcg_aux_clear(&p->cg_slot_stack[p->cg_type_sp - 1u].aux); 560 } 561 } 562 563 /* Materialize the pending EA on the TOS lvalue as a pointer rvalue. 564 * Postcondition: TOS is a pointer rvalue of type result_ptr_ty (which the 565 * caller has computed as type_ptr(pool, current_lv_type)) and the CG stack 566 * holds that single pointer where the lvalue's [base] or [base, index] used 567 * to be. Aux is cleared. 568 * 569 * The materialization sequence depends on the aux: 570 * base_kind == LOCAL: 571 * - scale == 0, offset == 0: addr 572 * - scale == 0, offset != 0: addr ; ptr_to_int ; +offset ; 573 * int_to_ptr 574 * - scale != 0: addr ; ptr_to_int ; idx*scale + ofs ; 575 * int_to_ptr base_kind == POINTER_RV: 576 * - scale == 0, offset == 0: no-op 577 * - scale == 0, offset != 0: ptr_to_int ; +offset ; int_to_ptr 578 * - scale != 0: ptr_to_int ; idx*scale + ofs ; 579 * int_to_ptr */ 580 static void pcg_materialize_lv_to_ptr(Parser* p, const Type* result_ptr_ty) { 581 PcgLvAux* lv = pcg_top_lv_aux(p); 582 int emit = pcg_emit_enabled(p); 583 PcgLvBaseKind base_kind = 584 lv ? (PcgLvBaseKind)lv->base_kind : PCG_LV_BASE_LOCAL; 585 i64 ofs = lv ? lv->offset : 0; 586 u32 scale = lv ? lv->scale : 0u; 587 const Type* idx_ty = c_abi_ptrdiff_type(p->abi, p->pool); 588 KitCgTypeId idx_tid = pcg_tid(p, idx_ty); 589 KitCgTypeId ptr_tid = pcg_tid(p, result_ptr_ty); 590 if (scale == 0 && ofs == 0) { 591 if (base_kind == PCG_LV_BASE_LOCAL) { 592 if (emit) kit_cg_addr(p->cg); 593 } 594 /* Already a pointer with no pending modifiers. */ 595 } else if (scale == 0) { 596 if (emit) { 597 if (base_kind == PCG_LV_BASE_LOCAL) kit_cg_addr(p->cg); 598 kit_cg_ptr_to_int(p->cg, idx_tid); 599 kit_cg_push_int(p->cg, (uint64_t)ofs, idx_tid); 600 kit_cg_int_binop(p->cg, KIT_CG_INT_ADD, KIT_CG_INTOP_NONE); 601 kit_cg_int_to_ptr(p->cg, ptr_tid); 602 } 603 } else { 604 /* CG stack on entry: [base_ptr_now, index]. Compute 605 * base_ptr_now + index*scale + ofs. */ 606 if (emit) { 607 if (base_kind == PCG_LV_BASE_LOCAL) { 608 kit_cg_swap(p->cg); /* [index, base_lv] */ 609 kit_cg_addr(p->cg); /* [index, base_ptr] */ 610 kit_cg_swap(p->cg); /* [base_ptr, index] */ 611 } 612 kit_cg_swap(p->cg); /* [index, base_ptr] */ 613 kit_cg_ptr_to_int(p->cg, idx_tid); 614 kit_cg_swap(p->cg); /* [base_int, index] */ 615 kit_cg_push_int(p->cg, (uint64_t)scale, idx_tid); 616 kit_cg_int_binop(p->cg, KIT_CG_INT_MUL, KIT_CG_INTOP_NONE); 617 kit_cg_int_binop(p->cg, KIT_CG_INT_ADD, KIT_CG_INTOP_NONE); 618 if (ofs != 0) { 619 kit_cg_push_int(p->cg, (uint64_t)ofs, idx_tid); 620 kit_cg_int_binop(p->cg, KIT_CG_INT_ADD, KIT_CG_INTOP_NONE); 621 } 622 kit_cg_int_to_ptr(p->cg, ptr_tid); 623 } 624 } 625 pcg_retag_top(p, result_ptr_ty); 626 { 627 PcgLvAux* out = pcg_top_lv_aux(p); 628 if (out) out->base_kind = PCG_LV_BASE_POINTER_RV; 629 } 630 } 631 632 /* Build the PLACE a load/store reads, from the TOS lvalue, keeping a constant 633 * field/element offset as the deref displacement (so the backend folds it into 634 * the load/store: `ldr w, [base, #ofs]`) rather than baking it into an explicit 635 * `base + ofs` pointer the way pcg_materialize_lv_to_ptr + kit_cg_deref(0) 636 * does. Mirrors that pair's postcondition (CG TOS is the place; parser slot is 637 * the field pointer type with aux cleared). The pointer is reinterpreted to the 638 * field type with a bitcast — free on the native backend (a no-op same-width 639 * cast), an explicit cast on the C-source backend. Indexed (scale != 0) and 640 * out-of-displacement-range offsets fall back to the explicit-pointer fold. 641 * Caller guarantees emit is enabled. */ 642 static void pcg_lv_to_memop_place(Parser* p, const Type* field_ty) { 643 PcgLvAux* lv = pcg_top_lv_aux(p); 644 PcgLvBaseKind base_kind = 645 lv ? (PcgLvBaseKind)lv->base_kind : PCG_LV_BASE_LOCAL; 646 i64 ofs = lv ? lv->offset : 0; 647 u32 scale = lv ? lv->scale : 0u; 648 const Type* fptr = type_ptr(p->pool, field_ty); 649 if (ofs < INT32_MIN || ofs > INT32_MAX) { 650 /* Out-of-int32 displacement can't ride a deref/EA offset; materialize an 651 * explicit base+ofs pointer. */ 652 pcg_materialize_lv_to_ptr(p, fptr); 653 kit_cg_deref(p->cg, 0); 654 return; 655 } 656 if (scale != 0u) { 657 /* Scaled subscript: build one fused [base + index*scale + ofs] place via 658 * kit_cg_elem_scaled rather than materializing a standalone 659 * base+index*scale+ofs pointer (an explicit mul/add + a copy into the deref 660 * base). CG stack on entry is [base, index]; decay the base to a field_ty* 661 * pointer value, then fuse. The index stride is the containing array's 662 * element size (scale) while the access type is field_ty, so `a[i].f` 663 * strides by sizeof(elem) but reads `f`. */ 664 kit_cg_swap(p->cg); /* [index, base] */ 665 if (base_kind == PCG_LV_BASE_LOCAL) 666 kit_cg_addr(p->cg); /* [index, base_ptr] */ 667 kit_cg_bitcast(p->cg, pcg_tid(p, fptr)); /* [index, (T*)base] */ 668 kit_cg_swap(p->cg); /* [base, index] */ 669 kit_cg_elem_scaled(p->cg, scale, ofs); /* [place] */ 670 } else { 671 if (base_kind == PCG_LV_BASE_LOCAL) kit_cg_addr(p->cg); 672 kit_cg_bitcast(p->cg, pcg_tid(p, fptr)); 673 kit_cg_deref(p->cg, ofs); 674 } 675 pcg_retag_top(p, fptr); 676 { 677 PcgLvAux* out = pcg_top_lv_aux(p); 678 if (out) out->base_kind = PCG_LV_BASE_POINTER_RV; 679 } 680 } 681 682 void pcg_addr(Parser* p) { 683 const Type* ty = pcg_top_type(p); 684 pcg_materialize_lv_to_ptr(p, type_ptr(p->pool, ty)); 685 } 686 687 /* Pushes the address of a label as a `void*` rvalue (GNU `&&label`). */ 688 void pcg_push_label_addr(Parser* p, CGLabel label) { 689 const Type* vp = type_ptr(p->pool, type_void(p->pool)); 690 if (pcg_emit_enabled(p)) kit_cg_push_label_addr(p->cg, label, pcg_tid(p, vp)); 691 pcg_push_type(p, vp); 692 } 693 694 /* Pops the target pointer and emits a computed `goto *expr;`. */ 695 void pcg_computed_goto(Parser* p, const CGLabel* targets, u32 ntargets) { 696 if (pcg_emit_enabled(p)) kit_cg_computed_goto(p->cg, targets, ntargets); 697 pcg_drop_type(p); 698 } 699 700 /* ---- Control flow ---- 701 * 702 * Label placement / jump / branch ops gate on emit; the conditional branches 703 * also pop the tested value off the type stack to mirror the CG-side consume. 704 * Suppressed parses, such as C99 `extern inline` bodies, do not open a CG 705 * function, so they use a nonzero dummy label only for semantic bookkeeping 706 * around break/continue/case validation. */ 707 CGLabel pcg_label_new(Parser* p) { 708 if (!pcg_emit_enabled(p)) return (CGLabel)1; 709 return kit_cg_label_new(p->cg); 710 } 711 712 void pcg_label_place(Parser* p, CGLabel l) { 713 if (pcg_emit_enabled(p)) kit_cg_label_place(p->cg, l); 714 } 715 716 void pcg_jump(Parser* p, CGLabel l) { 717 if (pcg_emit_enabled(p)) kit_cg_jump(p->cg, l); 718 } 719 720 void pcg_branch_true(Parser* p, CGLabel l) { 721 if (pcg_emit_enabled(p)) kit_cg_branch_true(p->cg, l); 722 pcg_drop_type(p); 723 } 724 725 void pcg_branch_false(Parser* p, CGLabel l) { 726 if (pcg_emit_enabled(p)) kit_cg_branch_false(p->cg, l); 727 pcg_drop_type(p); 728 } 729 730 /* Store [lv, rv] -> [rv]. The expression-value of an assignment is the 731 * assigned rvalue, so the store sequence must leave a copy of rv on TOS. */ 732 /* keep_result == 0: consume [place, value] and leave nothing — the assignment's 733 * value is discarded (the dominant `expr;` / initializer case). Skipping the 734 * dup lets a still-delayed RHS flow straight into the destination local 735 * (kit_cg_store's scalar-local fast path), killing the temp->local routing mov. 736 * keep_result == 1: leave the assignment's value on the stack for an enclosing 737 * expression (`a = b = c`, `if ((x = f()))`). */ 738 static void pcg_store_impl(Parser* p, int keep_result) { 739 const Type* lv_ty = pcg_top2_type(p); 740 const Type* rv_ty = pcg_top_type(p); 741 const Type* mem_ty = lv_ty; 742 /* Cached CG ids of the two slots (lowered once, not re-crossed by pcg_mem). 743 */ 744 KitCgTypeId rv_cg = pcg_top_cg_id(p); 745 KitCgTypeId mem_cg = pcg_top2_cg_id(p); /* tracks mem_ty (= lv_ty) */ 746 int emit = pcg_emit_enabled(p); 747 /* The aux to consume lives on the lvalue slot at parser depth 1. */ 748 PcgLvAux* lv = pcg_lv_aux_at(p, 1); 749 /* Snapshot bit-field geometry before materialize clears the aux. */ 750 PcgLvAux bf = lv ? *lv : (PcgLvAux){0}; 751 KitCgMemAccess access; 752 if (rv_ty && type_is_ptr(rv_ty) && (!lv_ty || !type_is_ptr(lv_ty))) { 753 mem_ty = rv_ty; 754 mem_cg = rv_cg; 755 } 756 access = pcg_mem_id(p, mem_ty ? mem_cg : rv_cg, mem_ty ? mem_ty : rv_ty); 757 if (emit) { 758 int wide = 759 rv_ty && (rv_ty->kind == TY_INT128 || rv_ty->kind == TY_UINT128 || 760 rv_ty->kind == TY_LDOUBLE); 761 if (pcg_lv_is_trivial_local(lv) && !wide) { 762 /* The destination place is already on the CG stack: [place, value]. When 763 * the result is kept, dup rv first so a copy survives the store; when it 764 * is discarded, store straight from [place, value] so the RHS (possibly a 765 * still-delayed arith/cmp) lands directly in the local. */ 766 if (keep_result) { 767 kit_cg_dup(p->cg); 768 kit_cg_rot3(p->cg); 769 kit_cg_swap(p->cg); 770 } 771 kit_cg_store(p->cg, access); 772 } else { 773 /* Stash rv into a temp so the destination place can be built from the 774 * base — folding any field offset / array scale into an explicit pointer 775 * — then reload rv to store it and to leave it as the expression value. 776 */ 777 FrameSlotDesc fsd; 778 FrameSlot tmp; 779 KitCgMemAccess rv_access = pcg_mem_id(p, rv_cg, rv_ty); 780 int trivial = pcg_lv_is_trivial_local(lv); 781 memset(&fsd, 0, sizeof fsd); 782 fsd.type = rv_ty; 783 fsd.size = c_abi_sizeof(p->abi, p->pool, rv_ty); 784 fsd.align = c_abi_alignof(p->abi, p->pool, rv_ty); 785 fsd.kind = FS_LOCAL; 786 tmp = pcg_local(p, &fsd); 787 kit_cg_push_local(p->cg, tmp); /* [base.., value, &tmp] */ 788 kit_cg_swap(p->cg); /* [base.., &tmp, value] */ 789 kit_cg_store(p->cg, rv_access); /* [base..] (stash rv) */ 790 if (!trivial) { 791 /* Materialize operates on the parser-TOS lvalue; drop the rv type slot 792 * so the lvalue is on top and matches the CG [base..]. The pointer is 793 * deref'd to the PLACE the strict store requires, then tagged with the 794 * bit-field geometry so the store inserts the field. */ 795 pcg_drop_type(p); 796 pcg_lv_to_memop_place(p, lv_ty); /* [dst_place] */ 797 pcg_apply_bitfield(p, &bf); 798 pcg_push_type(p, rv_ty); 799 } 800 kit_cg_push_local(p->cg, tmp); 801 kit_cg_load(p->cg, rv_access); /* [dst, value] */ 802 kit_cg_store(p->cg, access); /* [] */ 803 if (keep_result) { 804 kit_cg_push_local(p->cg, tmp); 805 kit_cg_load(p->cg, rv_access); /* [value] */ 806 } 807 } 808 } 809 pcg_drop_type(p); 810 pcg_drop_type(p); 811 if (keep_result) pcg_push_type(p, rv_ty); 812 } 813 814 void pcg_store(Parser* p) { pcg_store_impl(p, 1); } 815 816 /* Store whose assignment value is discarded (the `expr;` / initializer case). 817 * Replaces the `pcg_store(p); pcg_drop(p)` idiom; avoids materializing the RHS 818 * into a temp just to drop it. */ 819 void pcg_store_void(Parser* p) { pcg_store_impl(p, 0); } 820 821 void pcg_deref(Parser* p, const Type* pointee) { 822 const Type* ptr_ty = pcg_top_type(p); 823 if (pointee && pointee->kind == TY_FUNC) { 824 /* Function lvalues collapse to function pointers in C; no CG-level 825 * dereference is needed (functions aren't first-class data). */ 826 pcg_retag_top(p, pointee); 827 return; 828 } 829 if (ptr_ty && ptr_ty->kind == TY_PTR && ptr_ty->ptr.pointee != pointee) { 830 const Type* want_ptr_ty = type_ptr(p->pool, pointee); 831 if (pcg_emit_enabled(p)) kit_cg_bitcast(p->cg, pcg_tid(p, want_ptr_ty)); 832 pcg_retag_top(p, want_ptr_ty); 833 } 834 /* No kit_cg_indirect: the cg load/store accept pointer-rvalue bases 835 * directly. Mark the slot as a C-language lvalue with POINTER_RV base; the 836 * pointer stays on the CG stack untouched. */ 837 pcg_retag_top(p, pointee); 838 if (p->cg_type_sp) { 839 p->cg_slot_stack[p->cg_type_sp - 1u].flags = 840 pcg_lvalue_flags_for_type(pointee); 841 p->cg_slot_stack[p->cg_type_sp - 1u].aux.base_kind = PCG_LV_BASE_POINTER_RV; 842 } 843 } 844 845 /* ---- Lvalue chain helpers ---- */ 846 847 void pcg_lv_member(Parser* p, i64 byte_offset, const Type* field_ty, 848 u16 bf_offset, u16 bf_width, u32 bf_storage_size) { 849 PcgLvAux* lv = pcg_top_lv_aux(p); 850 int was_lvalue = pcg_top_is_lvalue(p); 851 const Type* base_ty = pcg_top_type(p); 852 /* A member of an rvalue aggregate (e.g. `mk().field` for a struct-returning 853 * call) lives in a CG-side temporary that is memory-backed, so the member is 854 * readable as an lvalue — but per C it is not a *modifiable* lvalue. */ 855 int base_is_rvalue_agg = 856 !was_lvalue && base_ty && 857 (base_ty->kind == TY_STRUCT || base_ty->kind == TY_UNION); 858 i64 saved_offset = lv ? lv->offset + byte_offset : byte_offset; 859 u32 saved_scale = lv ? lv->scale : 0u; 860 u8 saved_base_kind = lv ? lv->base_kind : PCG_LV_BASE_LOCAL; 861 /* Bumping the offset preserves the base kind and any earlier offset/scale 862 * accumulated on the chain (`a[i].f.g` keeps `scale = sizeof(elem)` and 863 * adds the field offsets). */ 864 pcg_retag_top(p, field_ty); 865 if (was_lvalue) { 866 pcg_set_top_lvalue(p); 867 } else if (base_is_rvalue_agg && p->cg_type_sp) { 868 p->cg_slot_stack[p->cg_type_sp - 1u].flags = PCG_VALUE_LVALUE; 869 } 870 /* pcg_retag_top cleared aux; re-apply the bumped offset and base kind. */ 871 { 872 PcgLvAux* lv_after = pcg_top_lv_aux(p); 873 if (lv_after) { 874 lv_after->offset = saved_offset; 875 lv_after->scale = saved_scale; 876 lv_after->base_kind = saved_base_kind; 877 lv_after->bit_offset = bf_offset; 878 lv_after->bit_width = bf_width; 879 lv_after->storage_size = bf_storage_size; 880 lv_after->bit_signed = pcg_type_is_signed(field_ty) ? 1u : 0u; 881 /* A member access narrows to a sub-object of a larger CG-tracked 882 * object; record it so aggregate reads materialize a pointer to the 883 * exact sub-object (the offset alone can be 0 for a first member). */ 884 lv_after->is_subobject = 1u; 885 } 886 if (bf_width && p->cg_type_sp) 887 p->cg_slot_stack[p->cg_type_sp - 1u].flags |= PCG_VALUE_BITFIELD; 888 } 889 } 890 891 void pcg_lv_subscript(Parser* p, u32 elem_size, const Type* elem_ty) { 892 /* Stack on entry (parser side): [base_lv, index_rv]. 893 * Stack on entry (CG side): [base, index]. 894 * After this call (parser): [elem_lv] with aux.scale = elem_size. 895 * After this call (CG): [base, index] — unchanged; the eventual 896 * load/store consumes both via the EA. */ 897 PcgLvAux* base_lv = pcg_lv_aux_at(p, 1); 898 i64 saved_offset = base_lv ? base_lv->offset : 0; 899 u8 base_is_lvalue = 900 (p->cg_type_sp >= 2u && 901 (p->cg_slot_stack[p->cg_type_sp - 2u].flags & PCG_VALUE_LVALUE) != 0); 902 u8 saved_base_kind = !base_is_lvalue 903 ? PCG_LV_BASE_POINTER_RV 904 : (base_lv ? base_lv->base_kind : PCG_LV_BASE_LOCAL); 905 if (base_lv && base_lv->scale != 0) { 906 perr(p, "internal: nested subscript without materialization"); 907 } 908 pcg_drop_type(p); /* drop index parser slot */ 909 pcg_retag_top(p, elem_ty); /* retag base parser slot as element */ 910 pcg_set_top_lvalue(p); 911 { 912 PcgLvAux* lv = pcg_top_lv_aux(p); 913 if (lv) { 914 lv->offset = saved_offset; 915 lv->scale = elem_size; 916 lv->base_kind = saved_base_kind; 917 } 918 } 919 } 920 921 void pcg_decay_array(Parser* p, const Type* arr_ty) { 922 const Type* ptr_ty = type_ptr(p->pool, arr_ty->arr.elem); 923 pcg_materialize_lv_to_ptr(p, ptr_ty); 924 } 925 926 void pcg_binop(Parser* p, BinOp op) { 927 const Type* result = pcg_top2_type(p); 928 if (op == BO_FADD || op == BO_FSUB || op == BO_FMUL || op == BO_FDIV) { 929 if (pcg_emit_enabled(p)) { 930 kit_cg_fp_binop(p->cg, pcg_fp_binop(op), KIT_CG_FP_NONE); 931 } 932 } else { 933 if (pcg_emit_enabled(p)) { 934 kit_cg_int_binop(p->cg, pcg_int_binop(op), KIT_CG_INTOP_NONE); 935 } 936 } 937 pcg_drop_type(p); 938 pcg_retag_top(p, result); 939 } 940 941 void pcg_unop(Parser* p, UnOp op) { 942 if (op == UO_NEG && pcg_type_is_fp(pcg_top_type(p))) { 943 if (pcg_emit_enabled(p)) 944 kit_cg_fp_unop(p->cg, KIT_CG_FP_NEG, KIT_CG_FP_NONE); 945 } else { 946 KitCgIntUnOp iop = op == UO_NOT ? KIT_CG_INT_NOT 947 : op == UO_BNOT ? KIT_CG_INT_BNOT 948 : KIT_CG_INT_NEG; 949 if (pcg_emit_enabled(p)) kit_cg_int_unop(p->cg, iop, KIT_CG_INTOP_NONE); 950 } 951 } 952 953 void pcg_cmp(Parser* p, CmpOp op) { 954 /* The FP block starts at CMP_LT_F (relational operator markers) and runs 955 * through the ordered/unordered predicate members; everything below is 956 * integer. CMP_EQ/CMP_NE additionally route to FP when the operand type is 957 * floating (C `==`/`!=` on floats is ordered-equal / unordered-not-equal). */ 958 if (op >= CMP_LT_F || 959 ((op == CMP_EQ || op == CMP_NE) && pcg_type_is_fp(pcg_top_type(p)))) { 960 if (pcg_emit_enabled(p)) kit_cg_fp_cmp(p->cg, pcg_fp_cmp(op)); 961 } else { 962 if (pcg_emit_enabled(p)) kit_cg_int_cmp(p->cg, pcg_int_cmp(op)); 963 } 964 pcg_drop_type(p); 965 pcg_retag_top(p, type_prim(p->pool, TY_INT)); 966 } 967 968 void pcg_convert(Parser* p, const Type* dst) { 969 const Type* src = pcg_top_type(p); 970 /* src is the TOS slot: read its cached id; dst is lowered once and reused for 971 * both its size and the convert id. */ 972 KitCgTypeId src_id = pcg_top_cg_id(p); 973 KitCgTypeId id = pcg_tid(p, dst); 974 u32 ss = (u32)kit_cg_type_size(p->c, src_id); 975 u32 ds = (u32)kit_cg_type_size(p->c, id); 976 int si = type_is_int(src) || type_is_ptr(src); 977 int di = type_is_int(dst) || type_is_ptr(dst); 978 int sf = pcg_type_is_fp(src); 979 int df = pcg_type_is_fp(dst); 980 int emit = pcg_emit_enabled(p); 981 if (src == dst) return; 982 /* C has no struct/union conversion: a pcg_convert reaching here with an 983 * aggregate on the stack is only reconciling a qualifier difference between 984 * two compatible types — e.g. the arms of a `?:` where one is a `const` 985 * struct lvalue (`*top`, top a `const T*`) and the other is not. The 986 * representation is identical, so retag the place to dst and emit nothing. 987 * Falling through would hand the aggregate to the scalar bitcast path, which 988 * pushes it as a value — illegal for an aggregate (api_push rejects it). The 989 * flag-preserving retag keeps it a place so the caller can copy it. */ 990 if (src->kind == TY_STRUCT || src->kind == TY_UNION) { 991 pcg_retag_keep_flags(p, 0, dst); 992 return; 993 } 994 /* Conversion to _Bool is "value != 0", not a truncation: a value whose set 995 * bits all lie above the bool storage width (e.g. 256, or the sign bit of a 996 * 128-bit operand) must still become 1. Emit an explicit compare-against-zero 997 * for any non-bool scalar source. */ 998 if (dst->kind == TY_BOOL && src->kind != TY_BOOL) { 999 if (emit) { 1000 KitCgTypeId sid = src_id; /* cached TOS-slot id */ 1001 if (sf) { 1002 kit_cg_push_float(p->cg, 0.0, sid); 1003 kit_cg_fp_cmp(p->cg, KIT_CG_FP_UNE); 1004 } else { 1005 kit_cg_push_int(p->cg, 0, sid); 1006 kit_cg_int_cmp(p->cg, KIT_CG_INT_NE); 1007 } 1008 /* The compare yields a 0/1 int; narrow it to the bool storage width. */ 1009 kit_cg_trunc(p->cg, id); 1010 } 1011 pcg_retag_top(p, dst); 1012 return; 1013 } 1014 if (type_is_ptr(src) && type_is_ptr(dst)) { 1015 if (emit) kit_cg_bitcast(p->cg, id); 1016 pcg_retag_top(p, dst); 1017 return; 1018 } 1019 if (si && di) { 1020 if (ds < ss) { 1021 if (emit) kit_cg_trunc(p->cg, id); 1022 } else if (ds > ss && type_is_int(src) && pcg_type_is_signed(src)) { 1023 if (emit) kit_cg_sext(p->cg, id); 1024 } else if (ds > ss) { 1025 if (emit) kit_cg_zext(p->cg, id); 1026 } else if (type_is_ptr(src) != type_is_ptr(dst)) { 1027 if (emit) kit_cg_bitcast(p->cg, id); 1028 } 1029 } else if (type_is_int(src) && df) { 1030 if (pcg_type_is_signed(src)) { 1031 if (emit) kit_cg_sint_to_float(p->cg, id, KIT_CG_ROUND_DEFAULT); 1032 } else { 1033 if (emit) kit_cg_uint_to_float(p->cg, id, KIT_CG_ROUND_DEFAULT); 1034 } 1035 } else if (sf && type_is_int(dst)) { 1036 if (pcg_type_is_signed(dst)) { 1037 if (emit) kit_cg_float_to_sint(p->cg, id, KIT_CG_ROUND_DEFAULT); 1038 } else { 1039 if (emit) kit_cg_float_to_uint(p->cg, id, KIT_CG_ROUND_DEFAULT); 1040 } 1041 } else if (sf && df) { 1042 if (ds > ss) { 1043 if (emit) kit_cg_fpext(p->cg, id); 1044 } else if (ds < ss) { 1045 if (emit) kit_cg_fptrunc(p->cg, id); 1046 } 1047 } else { 1048 if (emit) kit_cg_bitcast(p->cg, id); 1049 } 1050 pcg_retag_top(p, dst); 1051 } 1052 1053 /* Emit "value <op> step" for an inc/dec, picking the float or integer binop 1054 * based on the operand type. Floating operands step by 1.0 via an FP add/sub; 1055 * pointers step by the pointee size and everything else by 1. */ 1056 static void pcg_emit_inc_step(Parser* p, const Type* ty, BinOp op, 1057 KitCgIntBinOp cg_op, const Type* step_ty, 1058 u32 step) { 1059 if (pcg_type_is_fp(ty)) { 1060 BinOp fop = (op == BO_ISUB) ? BO_FSUB : BO_FADD; 1061 kit_cg_push_float(p->cg, 1.0, pcg_tid(p, ty)); 1062 kit_cg_fp_binop(p->cg, pcg_fp_binop(fop), KIT_CG_FP_NONE); 1063 } else { 1064 i64 amount = (ty && ty->kind == TY_PTR) ? (i64)step : 1; 1065 kit_cg_push_int(p->cg, amount, pcg_tid(p, step_ty)); 1066 kit_cg_int_binop(p->cg, cg_op, 0); 1067 } 1068 } 1069 1070 void pcg_inc_dec(Parser* p, BinOp op, int post) { 1071 const Type* ty = pcg_top_type(p); 1072 /* Cache the TOS-slot id NOW: pcg_materialize_lv_to_ptr below retypes the slot 1073 * to a pointer, so a later pcg_top_cg_id would no longer be `ty`'s id. */ 1074 KitCgTypeId ty_cg = pcg_top_cg_id(p); 1075 if (!pcg_emit_enabled(p)) { 1076 /* Drop the lvalue parser slot and push the rvalue result type. */ 1077 pcg_drop_type(p); 1078 pcg_push_type(p, ty); 1079 return; 1080 } 1081 { 1082 KitCgIntBinOp cg_op = pcg_int_binop(op); 1083 PcgLvAux* lv = pcg_top_lv_aux(p); 1084 /* Snapshot bit-field geometry before materialize clears the aux. */ 1085 PcgLvAux bf = lv ? *lv : (PcgLvAux){0}; 1086 KitCgMemAccess access = pcg_mem_id(p, ty_cg, ty); 1087 const Type* step_ty = ty; 1088 u32 step = 1; 1089 if (ty && ty->kind == TY_PTR) { 1090 const Type* pointee = ty->ptr.pointee; 1091 if (pointee && pointee->kind == TY_VOID) 1092 perr(p, "pointer arithmetic on void pointer"); 1093 step = c_abi_sizeof(p->abi, p->pool, pointee); 1094 step_ty = c_abi_ptrdiff_type(p->abi, p->pool); 1095 } 1096 /* Materialize the lvalue to a single destination pointer so its address can 1097 * be duplicated for the read-modify-write. */ 1098 pcg_materialize_lv_to_ptr(p, type_ptr(p->pool, ty)); 1099 { 1100 FrameSlotDesc fsd; 1101 FrameSlot tmp; 1102 const Type* result_ty = ty; 1103 KitCgMemAccess r_access = pcg_mem_id(p, ty_cg, result_ty); 1104 memset(&fsd, 0, sizeof fsd); 1105 fsd.type = result_ty; 1106 fsd.size = c_abi_sizeof(p->abi, p->pool, result_ty); 1107 fsd.align = c_abi_alignof(p->abi, p->pool, result_ty); 1108 fsd.kind = FS_LOCAL; 1109 tmp = pcg_local(p, &fsd); 1110 kit_cg_dup(p->cg); /* [ptr, ptr] */ 1111 kit_cg_deref(p->cg, 0); /* [ptr, place] */ 1112 pcg_apply_bitfield(p, &bf); 1113 kit_cg_load(p->cg, access); /* [ptr, old] */ 1114 if (post) { 1115 /* Stash old, compute new, store, then re-load old as result. */ 1116 kit_cg_dup(p->cg); /* [ptr, old, old] */ 1117 kit_cg_push_local(p->cg, tmp); 1118 kit_cg_swap(p->cg); 1119 kit_cg_store(p->cg, r_access); /* [ptr, old] */ 1120 pcg_emit_inc_step(p, ty, op, cg_op, step_ty, step); /* [ptr, new] */ 1121 kit_cg_swap(p->cg); /* [new, ptr] */ 1122 kit_cg_deref(p->cg, 0); /* [new, place] */ 1123 pcg_apply_bitfield(p, &bf); 1124 kit_cg_swap(p->cg); /* [place, new] */ 1125 kit_cg_store(p->cg, access); /* [] */ 1126 kit_cg_push_local(p->cg, tmp); 1127 kit_cg_load(p->cg, r_access); /* [old] */ 1128 } else { 1129 /* Compute new, stash new, store, then re-load new as result. */ 1130 pcg_emit_inc_step(p, ty, op, cg_op, step_ty, step); /* [ptr, new] */ 1131 kit_cg_dup(p->cg); /* [ptr, new, new] */ 1132 kit_cg_push_local(p->cg, tmp); 1133 kit_cg_swap(p->cg); 1134 kit_cg_store(p->cg, r_access); /* [ptr, new] */ 1135 kit_cg_swap(p->cg); /* [new, ptr] */ 1136 kit_cg_deref(p->cg, 0); /* [new, place] */ 1137 pcg_apply_bitfield(p, &bf); 1138 kit_cg_swap(p->cg); /* [place, new] */ 1139 kit_cg_store(p->cg, access); /* [] */ 1140 kit_cg_push_local(p->cg, tmp); 1141 kit_cg_load(p->cg, r_access); /* [new] */ 1142 } 1143 (void)step; 1144 } 1145 } 1146 /* Parser stack: drop the lvalue slot, push the result rvalue type. */ 1147 pcg_drop_type(p); 1148 pcg_push_type(p, ty); 1149 } 1150 1151 void pcg_call(Parser* p, u32 nargs, const Type* fn_type) { 1152 if (pcg_emit_enabled(p)) { 1153 kit_cg_call_default(p->cg, nargs, pcg_tid(p, fn_type)); 1154 } 1155 for (u32 i = 0; i < nargs + 1u; ++i) pcg_drop_type(p); 1156 if (fn_type && fn_type->kind == TY_FUNC && fn_type->fn.ret->kind != TY_VOID) { 1157 pcg_push_type(p, fn_type->fn.ret); 1158 } 1159 } 1160 1161 void pcg_call_symbol(Parser* p, KitCgSym sym, u32 nargs, const Type* fn_type) { 1162 if (pcg_emit_enabled(p)) { 1163 KitCgCallAttrs attrs; 1164 memset(&attrs, 0, sizeof attrs); 1165 kit_cg_call_symbol(p->cg, sym, nargs, attrs); 1166 } 1167 for (u32 i = 0; i < nargs; ++i) pcg_drop_type(p); 1168 if (fn_type && fn_type->kind == TY_FUNC && fn_type->fn.ret->kind != TY_VOID) { 1169 pcg_push_type(p, fn_type->fn.ret); 1170 } 1171 } 1172 1173 void pcg_ret(Parser* p, int has_value) { 1174 if (has_value) { 1175 if (pcg_emit_enabled(p)) kit_cg_ret(p->cg); 1176 pcg_drop_type(p); 1177 } else if (pcg_emit_enabled(p)) { 1178 /* No value supplied. For a void function this is the normal 0-result 1179 * return. For a non-void function it is a UB fall-off-the-end or an 1180 * already-diagnosed bare `return;` — terminate with unreachable rather 1181 * than asking kit_cg_ret to pop a result that was never pushed. */ 1182 if (p->cur_func_ret && p->cur_func_ret->kind != TY_VOID) 1183 kit_cg_unreachable(p->cg); 1184 else 1185 kit_cg_ret(p->cg); 1186 } 1187 } 1188 1189 void pcg_alloca(Parser* p) { 1190 if (pcg_emit_enabled(p)) { 1191 kit_cg_alloca(p->cg, 16, pcg_tid(p, type_ptr(p->pool, type_void(p->pool)))); 1192 } 1193 pcg_drop_type(p); 1194 pcg_push_type(p, type_ptr(p->pool, type_void(p->pool))); 1195 } 1196 1197 void pcg_va_arg(Parser* p, const Type* ty) { 1198 if (pcg_emit_enabled(p)) kit_cg_vararg_next(p->cg, pcg_tid(p, ty)); 1199 pcg_drop_type(p); 1200 pcg_push_type(p, ty); 1201 } 1202 1203 void pcg_va_start(Parser* p) { 1204 if (pcg_emit_enabled(p)) kit_cg_vararg_start(p->cg); 1205 } 1206 1207 void pcg_va_end(Parser* p) { 1208 if (pcg_emit_enabled(p)) kit_cg_vararg_end(p->cg); 1209 } 1210 1211 void pcg_va_copy(Parser* p) { 1212 if (pcg_emit_enabled(p)) kit_cg_vararg_copy(p->cg); 1213 } 1214 1215 void pcg_atomic_load(Parser* p, MemOrder ord) { 1216 const Type* pty = pcg_top_type(p); 1217 const Type* ty = (pty && pty->kind == TY_PTR) ? pty->ptr.pointee : pty; 1218 if (pcg_emit_enabled(p)) { 1219 kit_cg_atomic_load(p->cg, pcg_mem(p, ty), pcg_mem_order(ord)); 1220 } 1221 pcg_retag_top(p, ty); 1222 } 1223 1224 void pcg_atomic_store(Parser* p, MemOrder ord) { 1225 const Type* pty = pcg_top2_type(p); 1226 const Type* ty = (pty && pty->kind == TY_PTR) ? pty->ptr.pointee : pty; 1227 if (pcg_emit_enabled(p)) { 1228 kit_cg_atomic_store(p->cg, pcg_mem(p, ty), pcg_mem_order(ord)); 1229 } 1230 pcg_drop_type(p); 1231 pcg_drop_type(p); 1232 } 1233 1234 void pcg_atomic_rmw(Parser* p, AtomicOp op, MemOrder ord) { 1235 const Type* pty = pcg_top2_type(p); 1236 const Type* ty = (pty && pty->kind == TY_PTR) ? pty->ptr.pointee : pty; 1237 if (pcg_emit_enabled(p)) { 1238 kit_cg_atomic_rmw(p->cg, pcg_mem(p, ty), pcg_atomic_op(op), 1239 pcg_mem_order(ord)); 1240 } 1241 pcg_drop_type(p); 1242 pcg_retag_top(p, ty); 1243 } 1244 1245 void pcg_atomic_cas(Parser* p, MemOrder succ, MemOrder fail) { 1246 const Type* ty = pcg_top2_type(p); 1247 if (pcg_emit_enabled(p)) { 1248 kit_cg_atomic_cmpxchg(p->cg, pcg_mem(p, ty), pcg_mem_order(succ), 1249 pcg_mem_order(fail), 0); 1250 } 1251 pcg_drop_type(p); /* desired */ 1252 pcg_drop_type(p); /* expected */ 1253 pcg_drop_type(p); /* pointer */ 1254 pcg_push_type(p, ty); 1255 pcg_push_type(p, type_prim(p->pool, TY_BOOL)); 1256 } 1257 1258 void pcg_fence(Parser* p, MemOrder ord) { 1259 if (pcg_emit_enabled(p)) kit_cg_atomic_fence(p->cg, pcg_mem_order(ord)); 1260 } 1261 1262 void pcg_intrinsic_unary_to_int(Parser* p, IntrinKind k) { 1263 KitCgIntrinsic ck = k == INTRIN_CLZ ? KIT_CG_INTRIN_CLZ 1264 : k == INTRIN_CTZ ? KIT_CG_INTRIN_CTZ 1265 : KIT_CG_INTRIN_POPCOUNT; 1266 const Type* ity = type_prim(p->pool, TY_INT); 1267 if (pcg_emit_enabled(p)) { 1268 kit_cg_intrinsic(p->cg, ck, 1, pcg_tid(p, ity)); 1269 } 1270 pcg_retag_top(p, ity); 1271 } 1272 1273 void pcg_intrinsic_void(Parser* p, IntrinKind k) { 1274 if (k == INTRIN_UNREACHABLE) { 1275 if (pcg_emit_enabled(p)) kit_cg_unreachable(p->cg); 1276 } else { 1277 if (pcg_emit_enabled(p)) { 1278 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_TRAP, 0, 1279 kit_cg_type_builtin(p->c, KIT_CG_BUILTIN_VOID)); 1280 } 1281 } 1282 } 1283 1284 void pcg_syscall(Parser* p, u32 nargs, const Type* long_ty) { 1285 if (pcg_emit_enabled(p)) 1286 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_SYSCALL, nargs, pcg_tid(p, long_ty)); 1287 for (u32 i = 0; i < nargs; ++i) pcg_drop_type(p); 1288 pcg_push_type(p, long_ty); 1289 } 1290 1291 /* __builtin_readcyclecounter(): read the target cycle/timestamp counter. No 1292 * operands; pushes an unsigned long long result. */ 1293 void pcg_readcyclecounter(Parser* p) { 1294 const Type* ull = type_prim(p->pool, TY_ULLONG); 1295 if (pcg_emit_enabled(p)) 1296 kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_READCYCLECOUNTER, 0, pcg_tid(p, ull)); 1297 pcg_push_type(p, ull); 1298 } 1299 1300 /* __builtin_return_address(level) / __builtin_frame_address(level): emit the 1301 * frame-pointer-chain intrinsic. The constant level rides as a single immediate 1302 * operand (kept as OPK_IMM by kit_cg_intrinsic); the result is void*. */ 1303 void pcg_frame_or_return_address(Parser* p, int is_return, u32 level) { 1304 const Type* void_ptr = type_ptr(p->pool, type_void(p->pool)); 1305 KitCgIntrinsic intrin = 1306 is_return ? KIT_CG_INTRIN_RETURN_ADDRESS : KIT_CG_INTRIN_FRAME_ADDRESS; 1307 pcg_push_int(p, (i64)level, type_prim(p->pool, TY_INT)); 1308 if (pcg_emit_enabled(p)) 1309 kit_cg_intrinsic(p->cg, intrin, 1, pcg_tid(p, void_ptr)); 1310 /* kit_cg_intrinsic popped the level operand and pushed the void* result; 1311 * retag the slot pcg_push_int added (also clears the level's value flags, 1312 * e.g. the null-pointer-constant tag set for level 0). */ 1313 pcg_retag_top(p, void_ptr); 1314 } 1315 1316 void pcg_inline_asm(Parser* p, const char* tmpl, const AsmConstraint* outs, 1317 u32 nout, const AsmConstraint* ins, u32 nin, 1318 const Sym* clobbers, u32 nclob) { 1319 KitCgInlineAsm a; 1320 KitCgAsmOperand* o = NULL; 1321 KitCgAsmOperand* in = NULL; 1322 KitSym* cl = NULL; 1323 memset(&a, 0, sizeof a); 1324 a.tmpl = kit_sym_intern(p->c, kit_slice_cstr(tmpl ? tmpl : "")); 1325 if (nout) { 1326 o = arena_zarray(p->pool->arena, KitCgAsmOperand, nout); 1327 for (u32 i = 0; i < nout; ++i) { 1328 o[i].constraint = 1329 kit_sym_intern(p->c, kit_slice_cstr(outs[i].str ? outs[i].str : "")); 1330 o[i].name = outs[i].name; 1331 o[i].type = pcg_tid(p, outs[i].type); 1332 o[i].reg = outs[i].reg; 1333 o[i].dir = KIT_CG_ASM_OUT; 1334 } 1335 } 1336 if (nin) { 1337 in = arena_zarray(p->pool->arena, KitCgAsmOperand, nin); 1338 for (u32 i = 0; i < nin; ++i) { 1339 in[i].constraint = 1340 kit_sym_intern(p->c, kit_slice_cstr(ins[i].str ? ins[i].str : "")); 1341 in[i].name = ins[i].name; 1342 in[i].type = pcg_tid(p, ins[i].type); 1343 in[i].reg = ins[i].reg; 1344 in[i].dir = (ins[i].dir == ASM_INOUT) ? KIT_CG_ASM_INOUT : KIT_CG_ASM_IN; 1345 } 1346 } 1347 if (nclob) { 1348 cl = arena_array(p->pool->arena, KitSym, nclob); 1349 for (u32 i = 0; i < nclob; ++i) cl[i] = clobbers[i]; 1350 } 1351 a.outputs = o; 1352 a.noutputs = nout; 1353 a.inputs = in; 1354 a.ninputs = nin; 1355 a.clobbers = cl; 1356 a.nclobbers = nclob; 1357 if (pcg_emit_enabled(p)) kit_cg_inline_asm(p->cg, a); 1358 /* Mirror kit_cg_inline_asm's stack effect on the parser's typed shadow stack. 1359 */ 1360 for (u32 i = 0; i < nin; ++i) pcg_drop_type(p); 1361 for (u32 i = 0; i < nout; ++i) pcg_push_type(p, outs[i].type); 1362 }