ir.h (23770B)
1 #ifndef KIT_IR_H 2 #define KIT_IR_H 3 4 #include "abi/abi.h" 5 #include "arch/native_target.h" 6 #include "core/arena.h" 7 #include "core/core.h" 8 9 /* Optimizer-private physical/virtual operand model. 10 * 11 * The semantic CG API now exposes only CGLocal/Label/CgTarget concepts. 12 * O1 still needs a mutable pseudo-register and frame-slot view for liveness, 13 * allocation, and MIR. Keep those names local to src/opt by remapping the old 14 * optimizer tokens after including the semantic headers. Do not move these 15 * fields back into cg/cgtarget.h. */ 16 typedef NativeFrameSlot OptFrameSlot; 17 #define FrameSlot OptFrameSlot 18 #define FRAME_SLOT_NONE NATIVE_FRAME_SLOT_NONE 19 20 typedef NativeFrameSlotKind OptFrameSlotKind; 21 #define FrameSlotKind OptFrameSlotKind 22 #define FS_LOCAL NATIVE_FRAME_SLOT_LOCAL 23 #define FS_PARAM NATIVE_FRAME_SLOT_PARAM 24 #define FS_SPILL NATIVE_FRAME_SLOT_SPILL 25 #define FS_ALLOCA NATIVE_FRAME_SLOT_ALLOCA 26 #define FS_OUTGOING NATIVE_FRAME_SLOT_OUTGOING 27 #define FS_SAVE NATIVE_FRAME_SLOT_SAVE 28 29 typedef NativeFrameSlotFlag OptFrameSlotFlag; 30 #define FSF_ADDR_TAKEN NATIVE_FRAME_SLOT_ADDR_TAKEN 31 #define FSF_MEMORY_REQUIRED NATIVE_FRAME_SLOT_MEMORY_REQUIRED 32 #define FSF_FIXED_OFFSET NATIVE_FRAME_SLOT_FIXED_OFFSET 33 #define FSF_VOLATILE (1u << 8) 34 35 typedef NativeFrameSlotDesc OptFrameSlotDesc; 36 #define FrameSlotDesc OptFrameSlotDesc 37 38 typedef NativeKnownFrameDesc OptCGKnownFrameDesc; 39 #define CGKnownFrameDesc OptCGKnownFrameDesc 40 41 typedef NativeAllocClass RegClass; 42 #define RC_INT NATIVE_REG_INT 43 #define RC_FP NATIVE_REG_FP 44 #define RC_VEC NATIVE_REG_VEC 45 46 /* The single float-ABI-aware value register-class decision (defined in ir.c). 47 * All optimizer passes route through it so their classifications agree. */ 48 u8 opt_value_reg_class(Compiler* c, KitCgTypeId ty); 49 50 #define CG_REG_ALLOCABLE NATIVE_REG_ALLOCABLE 51 #define CG_REG_CALLER_SAVED NATIVE_REG_CALLER_SAVED 52 #define CG_REG_CALLEE_SAVED NATIVE_REG_CALLEE_SAVED 53 #define CG_REG_ARG NATIVE_REG_ARG 54 #define CG_REG_RET NATIVE_REG_RET 55 #define CG_REG_RESERVED NATIVE_REG_RESERVED 56 57 typedef NativePhysRegInfo OptCGPhysRegInfo; 58 #define CGPhysRegInfo OptCGPhysRegInfo 59 60 typedef enum OptOperandKind { 61 OPT_OPK_IMM = OPK_IMM, 62 OPT_OPK_LOCAL = OPK_LOCAL, 63 OPT_OPK_GLOBAL = OPK_GLOBAL, 64 OPT_OPK_INDIRECT = OPK_INDIRECT, 65 OPT_OPK_REG = 0xf0u, 66 } OptOperandKind; 67 #define OPK_REG OPT_OPK_REG 68 69 typedef struct OptOperand { 70 u8 kind; 71 u8 cls; 72 u8 pad[2]; 73 KitCgTypeId type; 74 union { 75 i64 imm; 76 Reg reg; 77 FrameSlot frame_slot; 78 CGLocal local; 79 struct { 80 ObjSymId sym; 81 i64 addend; 82 } global; 83 struct { 84 Reg base; 85 Reg index; 86 u8 log2_scale; 87 i32 ofs; 88 } ind; 89 } v; 90 } OptOperand; 91 #define Operand OptOperand 92 93 typedef enum OptCGLocalStorageKind { 94 CG_LOCAL_STORAGE_FRAME, 95 CG_LOCAL_STORAGE_REG, 96 } OptCGLocalStorageKind; 97 98 typedef struct OptCGLocalStorage { 99 u8 kind; 100 u8 pad[3]; 101 union { 102 Reg reg; 103 FrameSlot frame_slot; 104 } v; 105 } OptCGLocalStorage; 106 #define CGLocalStorage OptCGLocalStorage 107 #define CGLocalStorageKind OptCGLocalStorageKind 108 109 typedef struct OptCGABIPart { 110 Operand op; 111 u32 offset; 112 } OptCGABIPart; 113 #define CGABIPart OptCGABIPart 114 115 typedef struct OptCGABIValue { 116 KitCgTypeId type; 117 const ABIArgInfo* abi; 118 Operand storage; 119 CGABIPart* parts; 120 u32 nparts; 121 } OptCGABIValue; 122 #define CGABIValue OptCGABIValue 123 124 typedef enum OptCGCallPlanMoveKind { 125 CG_CALL_PLAN_REG, 126 CG_CALL_PLAN_STACK, 127 CG_CALL_PLAN_TAIL_STACK, 128 CG_CALL_PLAN_SRC_VALUE, 129 CG_CALL_PLAN_SRC_ADDR, 130 } OptCGCallPlanMoveKind; 131 132 typedef struct OptCGCallPlanMove { 133 Operand src; 134 Operand dst; 135 MemAccess mem; 136 u32 src_offset; 137 u32 stack_offset; 138 Reg dst_reg; 139 u8 src_kind; 140 u8 dst_kind; 141 u8 cls; 142 u8 pad; 143 } OptCGCallPlanMove; 144 #define CGCallPlanMove OptCGCallPlanMove 145 146 typedef struct OptCGCallPlanRet { 147 Operand dst; 148 MemAccess mem; 149 u32 dst_offset; 150 Reg src_reg; 151 u8 cls; 152 u8 pad[3]; 153 } OptCGCallPlanRet; 154 #define CGCallPlanRet OptCGCallPlanRet 155 156 typedef struct OptCGCallPlan { 157 Operand callee; 158 CGCallPlanMove* args; 159 CGCallPlanRet* rets; 160 u32 nargs; 161 u32 nrets; 162 u32 stack_arg_size; 163 u32 clobber_mask[3]; 164 u32 return_mask[3]; 165 u16 flags; 166 u8 has_sret; 167 u8 is_variadic; 168 } OptCGCallPlan; 169 #define CGCallPlan OptCGCallPlan 170 171 typedef struct OptCGParamDesc { 172 u32 index; 173 Sym name; 174 KitCgTypeId type; 175 u32 size; 176 u32 align; 177 u32 flags; 178 SrcLoc loc; 179 CGLocalStorage storage; 180 const ABIArgInfo* abi; 181 const CGABIPart* incoming; 182 u32 nincoming; 183 } OptCGParamDesc; 184 #define CGParamDesc OptCGParamDesc 185 186 typedef struct OptCGCallDesc { 187 KitCgTypeId fn_type; 188 Operand callee; 189 CGABIValue* args; 190 CGABIValue ret; 191 u32 nargs; 192 u16 flags; 193 u8 tail_policy; 194 u8 pad; 195 KitCgInlinePolicy inline_policy; 196 const ABIFuncInfo* abi; 197 } OptCGCallDesc; 198 #define CGCallDesc OptCGCallDesc 199 200 typedef struct OptCGFuncDesc { 201 ObjSymId sym; 202 ObjSecId text_section_id; 203 ObjGroupId group_id; 204 KitCgTypeId fn_type; 205 KitCgTypeId result_type; /* KIT_CG_TYPE_NONE/void == no result */ 206 const CGParamDesc* params; 207 u32 nparams; 208 SrcLoc loc; 209 u32 flags; 210 KitCgInlinePolicy inline_policy; 211 u8 atomize; 212 u8 pad[3]; 213 const ABIFuncInfo* abi; 214 } OptCGFuncDesc; 215 #define CGFuncDesc OptCGFuncDesc 216 217 typedef struct OptCGScopeDesc { 218 u8 kind; 219 u8 pad[3]; 220 Label break_label; 221 Label continue_label; 222 Operand cond; 223 KitCgTypeId result_type; 224 } OptCGScopeDesc; 225 #define CGScopeDesc OptCGScopeDesc 226 227 /* SSA value id. VAL_NONE=0 is reserved as a sentinel. Recorded CG virtual 228 * registers live in Func's pseudo-register table; before pseudo-reg SSA, 229 * OPK_REG operands carry those mutable Reg ids. After pseudo-reg SSA, OPK_REG 230 * operands carry Val ids. The mode is explicit on Func, not encoded in the 231 * numeric id. */ 232 typedef u32 Val; 233 #define VAL_NONE 0u 234 235 typedef Reg PReg; 236 #define PREG_NONE ((PReg)REG_NONE) 237 238 typedef u32 InstId; 239 #define INST_ID_NONE 0u 240 241 /* IROps mirror the CGTarget surface 1:1 plus a handful of SSA-only ops 242 * (IR_PHI, IR_CONST_I, IR_CONST_BYTES). Each CGTarget method records as 243 * exactly one Inst, so level-1 replay is a flat walk that re-issues 244 * each Inst as one wrapped target call. doc/OPT.md §1.1. */ 245 typedef enum IROp { 246 IR_NOP, 247 /* SSA-only constants (used by const-propagation; recording uses 248 * load_imm/load_const which become IR_LOAD_IMM/IR_LOAD_CONST). */ 249 IR_CONST_I, 250 IR_CONST_BYTES, 251 252 /* Param/frame declarations recorded from CGTarget.param. The frame 253 * slot id table lives separately on Func; this op records the 254 * sequence point so replay can re-issue target->param in order. */ 255 IR_PARAM_DECL, 256 257 /* Address-bearing data movement. */ 258 IR_LOAD_IMM, /* opnds[0] dst REG; extra.imm = imm */ 259 IR_LOAD_CONST, /* opnds[0] dst REG; extra.cbytes */ 260 IR_COPY, /* opnds[0] dst REG, opnds[1] src REG */ 261 IR_LOAD, /* opnds[0] dst REG, opnds[1] addr; extra.mem */ 262 IR_STORE, /* opnds[0] addr, opnds[1] src REG|IMM; extra.mem */ 263 IR_ADDR_OF, /* opnds[0] dst REG, opnds[1] lv (LOCAL|GLOBAL|INDIRECT) */ 264 IR_TLS_ADDR_OF, /* opnds[0] dst REG; extra.aux = IRTlsAux */ 265 IR_AGG_COPY, /* opnds[0] dst, opnds[1] src; extra.aux = IRAggAux */ 266 IR_AGG_SET, /* opnds[0] dst, opnds[1] byte; extra.aux = IRAggAux */ 267 IR_BITFIELD_LOAD, /* opnds[0] dst REG, opnds[1] record; extra.aux */ 268 IR_BITFIELD_STORE, /* opnds[0] record, opnds[1] src; extra.aux */ 269 270 /* Arithmetic / cmp / convert. opnds[0] dst REG, [1] a, optionally [2] b. 271 * extra.imm carries the BinOp/UnOp/CmpOp/ConvKind tag. */ 272 IR_BINOP, 273 IR_UNOP, 274 IR_CMP, 275 IR_CONVERT, 276 277 /* Calls. extra.aux = IRCallAux (see below). defs = result OPK_REG ids: 278 * PReg before opt_build_reg_ssa, Val after it. */ 279 IR_CALL, 280 281 /* Phis. extra.aux = IRPhiAux. */ 282 IR_PHI, 283 284 /* Control flow / scopes. */ 285 IR_BR, /* unconditional. block.succ[0] = target block id. */ 286 IR_CONDBR, /* opnds[0] cond REG; succ[0] = true, succ[1] = false. */ 287 IR_CMP_BRANCH, /* fused. opnds = [a, b]; extra.imm = CmpOp; 288 succ[0] = taken, succ[1] = fallthrough. */ 289 IR_SWITCH, /* multi-target structured switch. opnds[0] = selector; 290 extra.aux = IRSwitchAux; succ[0..ncases) = case 291 blocks, succ[ncases] = default block. */ 292 IR_INDIRECT_BRANCH, /* opnds[0] = addr REG; extra.aux = IRIndirectAux. 293 succ[0..nvalid) = the valid target blocks. */ 294 IR_LOAD_LABEL_ADDR, /* opnds[0] dst REG; extra.imm = target block id. */ 295 IR_LOCAL_STATIC_DATA_BEGIN, /* extra.aux = CgIrLocalStaticBeginAux */ 296 IR_LOCAL_STATIC_DATA_WRITE, /* extra.aux = CgIrLocalStaticWriteAux */ 297 IR_LOCAL_STATIC_DATA_LABEL_ADDR, /* extra.aux = CgIrLocalStaticLabelAux */ 298 IR_LOCAL_STATIC_DATA_END, 299 IR_RET, /* extra.aux = IRRetAux* (NULL for void). */ 300 IR_UNREACHABLE, /* control terminator; no operands, no successors. */ 301 IR_SCOPE_BEGIN, /* extra.aux = IRScopeAux. */ 302 IR_SCOPE_END, /* extra.imm = scope id (Val). */ 303 IR_BREAK_TO, /* extra.imm = scope id (Val). */ 304 IR_CONTINUE_TO, /* extra.imm = scope id (Val). */ 305 306 /* alloca / variadics. */ 307 IR_ALLOCA, /* opnds = [dst REG, size]; extra.imm = align */ 308 IR_VA_START, /* opnds = [ap] */ 309 IR_VA_ARG, /* opnds = [dst REG, ap]; extra.aux = KitCgTypeId*/ 310 IR_VA_END, /* opnds = [ap] */ 311 IR_VA_COPY, /* opnds = [dst, src] */ 312 313 /* Atomics. */ 314 IR_ATOMIC_LOAD, /* opnds = [dst, addr]; extra.aux = IRAtomicAux */ 315 IR_ATOMIC_STORE, /* opnds = [addr, src]; extra.aux = IRAtomicAux */ 316 IR_ATOMIC_RMW, /* opnds = [dst, addr, val]; extra.aux */ 317 IR_ATOMIC_CAS, /* defs = [prior, ok] OPK_REG ids; extra.aux = IRCasAux */ 318 IR_FENCE, /* extra.imm = KitCgMemOrder */ 319 320 /* Inline asm. extra.aux = IRAsmAux. */ 321 IR_ASM_BLOCK, 322 323 /* Compiler intrinsics (see arch.h IntrinKind). extra.aux = IRIntrinAux. */ 324 IR_INTRINSIC, 325 326 /* set_loc is *not* an IR op — SrcLoc is sticky on Inst.loc, applied at 327 * recording time from the wrapper's pending_loc. */ 328 } IROp; 329 330 /* ---- per-op aux structs ---- */ 331 332 typedef struct IRTlsAux { 333 ObjSymId sym; 334 i64 addend; 335 } IRTlsAux; 336 337 typedef struct IRSwitchAuxCase { 338 u64 value; 339 u32 block; /* successor block id */ 340 } IRSwitchAuxCase; 341 342 typedef struct IRSwitchAux { 343 KitCgTypeId selector_type; 344 IRSwitchAuxCase* cases; 345 u32 ncases; 346 u32 default_block; /* if no default, this is the post-switch fallthrough */ 347 u8 has_default; /* 1 if frontend supplied an explicit default */ 348 u8 hint; /* KitCgSwitchHint */ 349 u8 pad[2]; 350 } IRSwitchAux; 351 352 typedef struct IRIndirectAux { 353 u32* targets; /* successor block ids; same as Block.succ[0..ntargets) */ 354 u32 ntargets; 355 } IRIndirectAux; 356 357 typedef struct IRAggAux { 358 AggregateAccess access; 359 } IRAggAux; 360 361 typedef struct IRBitFieldAux { 362 BitFieldAccess access; 363 } IRBitFieldAux; 364 365 #define OPT_REG_CLASSES 3u 366 #define OPT_MAX_HARD_REGS 32u 367 368 /* One per-class clobber bitmask set; see Func.inst_clobbers. */ 369 typedef u32 OptInstClobberMask[OPT_REG_CLASSES]; 370 #define OPT_MAX_SCRATCH_REGS 4u 371 372 typedef struct IRGepAux { 373 KitCgTypeId base_type; 374 u32 nindices; 375 i64* indices; 376 } IRGepAux; 377 378 typedef struct IRPhiAux { 379 u32 npreds; 380 u32* pred_blocks; 381 Val* pred_vals; 382 u32 slot_id; /* 0 if not from mem2reg; else 1-based FrameSlot id */ 383 u32 reg_id; /* 0 if not from mutable-pseudo SSA; else original Reg id */ 384 } IRPhiAux; 385 386 #define IRF_NO_COALESCE (1u << 0) 387 388 /* IR_CALL aux. The CGTarget interface is rich enough that we keep the 389 * full descriptor for replay; SSA passes inspect args/results in their 390 * Val form via the CGABIValue.storage.v.reg fields where applicable. */ 391 typedef struct IRCallAux { 392 CGCallDesc desc; 393 CGCallPlan plan; 394 u8 plan_valid; 395 u8 use_plan_replay; 396 u8 pad[2]; 397 /* Result Vals (one per ABI-decomposed return part). 0 for void. */ 398 u32 nresults; 399 Val* results; 400 /* For SSA-aware passes: the call may have args that are REG operands 401 * (carrying Val uses). They live in desc.args[i].storage.v.reg or 402 * desc.args[i].parts[k].op.v.reg. */ 403 } IRCallAux; 404 405 typedef struct IRRetAux { 406 u8 present; /* 0 → void return; ret(NULL) at replay */ 407 CGABIValue val; 408 } IRRetAux; 409 410 typedef struct IRScopeAux { 411 CGScopeDesc desc; 412 u32 scope_id; /* 1-based; the CGScope handed back to the caller */ 413 /* The caller-supplied break/continue labels translated to block ids; if the 414 * desc passed LABEL_NONE we leave 0 (unused — break_to/continue_to is 415 * illegal in that case). */ 416 u32 loop_break_block; 417 u32 loop_continue_block; 418 } IRScopeAux; 419 420 typedef struct IRAtomicAux { 421 MemAccess mem; 422 KitCgMemOrder mo; 423 u8 op; /* KitCgAtomicOp; valid for IR_ATOMIC_RMW */ 424 } IRAtomicAux; 425 426 typedef struct IRCasAux { 427 MemAccess mem; 428 KitCgMemOrder success; 429 KitCgMemOrder failure; 430 } IRCasAux; 431 432 typedef struct IRAsmAux { 433 const char* tmpl; 434 AsmConstraint* outs; 435 AsmConstraint* ins; 436 Sym* clobbers; 437 Operand* 438 out_ops; /* nout slots; the wrapped target may fill in REG location */ 439 Operand* in_ops; /* nin slots; recorded by w_asm_block, xlat'd at replay */ 440 u32 nout, nin, nclob; 441 /* KitCgAsmClobberAbiSet bits: an arch-neutral "clobbers the whole caller/ 442 * callee-saved set" the backend expands against its own register file. */ 443 u32 clobber_abi_sets; 444 /* Filled by opt_machinize from backend register-name resolution. */ 445 u32 clobber_mask[OPT_REG_CLASSES]; 446 i32* out_fixed_regs; /* nout, -1 when unconstrained */ 447 i32* in_fixed_regs; /* nin, -1 when unconstrained */ 448 u8* out_fixed_cls; /* RegClass, parallel to out_fixed_regs */ 449 u8* in_fixed_cls; /* RegClass, parallel to in_fixed_regs */ 450 u32* out_allowed_masks; /* nout, 0 when the whole class is allowed */ 451 u32* in_allowed_masks; /* nin, 0 when the whole class is allowed */ 452 u8* out_allowed_cls; /* RegClass, parallel to out_allowed_masks */ 453 u8* in_allowed_cls; /* RegClass, parallel to in_allowed_masks */ 454 } IRAsmAux; 455 456 typedef struct IRIntrinAux { 457 IntrinKind kind; 458 Operand* dsts; /* ndst */ 459 Operand* args; /* narg */ 460 Val* result_vals; /* one per dst that's a REG, parallel to dsts */ 461 u32 ndst, narg; 462 } IRIntrinAux; 463 464 typedef struct IRParamDeclAux { 465 CGParamDesc desc; 466 } IRParamDeclAux; 467 468 /* ---- frame slots / params ---- */ 469 470 typedef struct IRFrameSlot { 471 FrameSlot id; 472 KitCgTypeId type; 473 Sym name; 474 SrcLoc loc; 475 u32 size; 476 u32 align; 477 u8 kind; /* FrameSlotKind */ 478 u8 pad; 479 u16 flags; /* FrameSlotFlag */ 480 } IRFrameSlot; 481 482 typedef struct IRParam { 483 u32 index; 484 Sym name; 485 KitCgTypeId type; 486 u32 size; 487 u32 align; 488 u32 flags; /* CGLocalFlag */ 489 CGLocalStorage storage; 490 const ABIArgInfo* abi; 491 SrcLoc loc; 492 } IRParam; 493 494 typedef struct IRLocal { 495 u32 id; 496 CGLocalDesc desc; 497 CGLocalStorage storage; 498 FrameSlot home_slot; 499 u8 address_taken; 500 u8 pad[3]; 501 } IRLocal; 502 503 /* ---- Inst / Block / Func ---- */ 504 505 typedef struct Inst { 506 u16 op; 507 u16 flags; 508 InstId id; 509 SrcLoc loc; /* sticky from CGTarget.set_loc at recording */ 510 KitCgTypeId type; 511 /* Primary and multi-result OPK_REG definitions. Before opt_build_reg_ssa, 512 * these hold PReg ids matching destination operands. After opt_build_reg_ssa, 513 * they hold Val ids. */ 514 Val def; 515 u32 ndefs; 516 Val* defs; 517 /* Operands. We use Operand instead of Val so that the original 518 * CGTarget call shape (IMM / LOCAL / GLOBAL / INDIRECT in addition to 519 * REG) round-trips at replay. Before opt_build_reg_ssa, OPK_REG operands 520 * are mutable PReg uses/defs; after it, they are Val uses/defs. */ 521 u32 nopnds; 522 Operand* opnds; 523 union { 524 i64 imm; 525 ConstBytes cbytes; 526 MemAccess mem; 527 void* aux; 528 } extra; 529 } Inst; 530 531 typedef struct Block { 532 u32 id; 533 Inst* insts; 534 u32 ninsts, cap; 535 u32* preds; 536 u32 npreds; 537 /* Variable-length successor list. ir_block_new arena-allocates a 538 * 2-slot array (large enough for ordinary terminators); ops with 539 * more successors (IR_SWITCH, IR_INDIRECT_BRANCH) reallocate via 540 * ir_block_set_nsucc before writing. nsucc names the prefix in use. */ 541 u32* succ; 542 u32 nsucc; 543 u32 succ_cap; 544 u32 loop_depth; 545 u32 frequency; 546 /* MCLabel id pre-allocated by w_label_new for blocks created via 547 * cg_label_new. Stable from recording through pass_emit. Blocks 548 * created internally by opt (fallthroughs, scope-implicit blocks) 549 * leave this at MC_LABEL_NONE; pass_emit's ensure_label mints one 550 * on demand for those. */ 551 MCLabel mc_label; 552 } Block; 553 554 typedef struct MFunc { 555 Block* blocks; 556 u32 nblocks; 557 u32 entry; 558 u32* emit_order; 559 u32 emit_order_n; 560 u32 emit_order_cap; 561 } MFunc; 562 563 typedef enum OptAllocKind { 564 OPT_ALLOC_NONE, 565 OPT_ALLOC_HARD, 566 OPT_ALLOC_SPILL, 567 OPT_ALLOC_SPLIT, 568 } OptAllocKind; 569 570 typedef enum OptLocKind { 571 OPT_LOC_NONE, 572 OPT_LOC_HARD, 573 OPT_LOC_STACK, 574 } OptLocKind; 575 576 typedef struct OptLoc { 577 u8 kind; 578 u8 cls; 579 Reg hard_reg; 580 FrameSlot spill_slot; 581 } OptLoc; 582 583 typedef struct OptAllocSegment { 584 u32 start; 585 u32 end; 586 u32 block; 587 u8 loc_kind; 588 u8 cls; 589 Reg hard_reg; 590 FrameSlot spill_slot; 591 FrameSlot spill_home; 592 u8 reload_at_start; 593 u8 store_at_end; 594 u8 pad[2]; 595 u32 next; 596 } OptAllocSegment; 597 598 typedef struct OptPRegInfo { 599 u32 first_pos; 600 u32 last_pos; 601 u32 live_length; 602 u32 frequency; /* legacy aggregate priority score */ 603 u32 use_freq; 604 u32 def_freq; 605 u32 live_block_freq; 606 u32 live_across_call_freq; 607 u32 spill_cost; 608 i32 tied_hard_reg; /* -1 means no fixed/tied physical register need. */ 609 Reg hard_reg; 610 FrameSlot spill_slot; 611 u8 alloc_kind; /* OptAllocKind */ 612 u8 cls; /* RegClass */ 613 i8 preferred_hard_reg; /* soft hint for allocator; -1 = no hint */ 614 u8 pad[1]; 615 u32 forbidden_hard_regs; /* bit r means PReg may not allocate hard reg r. */ 616 u32 allowed_hard_regs; /* 0 means unrestricted; otherwise positive mask. */ 617 /* Subset of forbidden_hard_regs that comes from a fixed-register machine 618 * clobber (an instruction live across this value destroys reg r — see 619 * Func.inst_clobbers). Unlike soft forbids, the return-register hint must not 620 * clear these: a value cannot live in a register clobbered within its range. 621 */ 622 u32 clobbered_hard_regs; 623 } OptPRegInfo; 624 625 typedef enum OptUseKind { 626 OPT_USE_OPERAND, 627 OPT_USE_INDIRECT_BASE, 628 OPT_USE_INDIRECT_INDEX, 629 OPT_USE_PHI_INPUT, 630 } OptUseKind; 631 632 typedef struct OptUse { 633 Val val; 634 u32 block; 635 u32 inst; 636 InstId inst_id; 637 u32 next_for_val; 638 u32 operand_index; 639 u32 phi_pred_index; 640 Operand* operand; 641 u8 kind; /* OptUseKind */ 642 u8 pad[3]; 643 } OptUse; 644 645 typedef struct Func { 646 Arena* arena; 647 Compiler* c; 648 CGFuncDesc desc; /* preserved for level-1 replay func_begin */ 649 ObjSymId name; /* alias for desc.sym (kept for older callers) */ 650 KitCgTypeId type; 651 Block* blocks; 652 u32 nblocks, blocks_cap; 653 u32 entry; 654 655 IRFrameSlot* frame_slots; 656 u32 nframe_slots, frame_slots_cap; 657 IRParam* params; 658 u32 nparams, params_cap; 659 IRLocal* locals; 660 u32 nlocals, locals_cap; 661 662 /* Value table. Index 0 is VAL_NONE; first allocated Val is 1. */ 663 u32* val_def_block; 664 u32* val_def_inst; 665 KitCgTypeId* val_type; 666 u8* val_cls; /* RegClass per Val, used by replay to reconstruct REG operands 667 */ 668 u32 nvals, vals_cap; 669 670 /* Mutable pseudo-register table. Index 0 is unused so CG virtual Reg ids can 671 * be used directly. During initial recording and O1, OPK_REG operands name 672 * these persistent storage locations. O2 converts them to Val ids with 673 * opt_build_reg_ssa before running SSA passes. */ 674 KitCgTypeId* preg_type; 675 u8* preg_cls; 676 u32 npregs, pregs_cap; 677 678 /* Scope id table. Indexed by scope_id (1-based). Values map to 679 * IRScopeAux entries (via the IR_SCOPE_BEGIN inst). Stored as a flat 680 * pointer table for O(1) lookup during scope_end/break/continue 681 * recording and replay. */ 682 Inst** scope_aux_inst; 683 u32 nscopes, scopes_cap; 684 685 /* Emit order: the sequence in which blocks first became `cur` during 686 * recording. This is the natural order CG's emit cursor visited each 687 * block, so replay must follow it (block-creation order can differ — 688 * e.g. label_new(L) precedes cmp_branch but the cmp_branch's 689 * fallthrough block is what physically follows the cmp_branch in 690 * code). Blocks not present here are unreachable / unplaced; replay 691 * skips them. */ 692 u32* emit_order; 693 u32 emit_order_n, emit_order_cap; 694 695 Target opt_target; 696 u8 opt_has_target; 697 u8 opt_rewritten; 698 u8 opt_reg_ssa; 699 u8 pad0; 700 u16 opt_live_words; 701 u32 opt_used_loc_words; 702 u32 opt_alloc_hard_loc_words; 703 u32 opt_alloc_stack_loc_words; 704 u32 opt_alloc_stack_slots; 705 u32 opt_position_count; 706 u64 opt_alloc_hard_point_visits; 707 u64 opt_alloc_stack_point_visits; 708 u64 opt_alloc_hard_word_ors; 709 u64 opt_alloc_stack_word_ors; 710 u64 opt_alloc_hard_mark_points; 711 u64 opt_alloc_stack_mark_points; 712 u64 opt_rewrite_inserted_insts; 713 u64 opt_rewrite_live_words_touched; 714 u64 opt_dde_live_words_touched; 715 u64 opt_coalesce_moves_seen; 716 u64 opt_coalesce_candidates; 717 u64 opt_coalesce_conflicts; 718 u64 opt_coalesce_merge_attempts; 719 u64 opt_coalesce_merges; 720 InstId next_inst_id; 721 /* Per-instruction fixed-register clobbers (one bitmask per reg class), 722 * indexed by InstId, sized [next_inst_id]. Built in opt_machinize_native from 723 * the target's machine_op_clobbers hook; consulted by the allocator 724 * (pass_lower) to keep values live across an instruction out of the registers 725 * its encoding destroys (x86 idiv → rax/rdx, etc.). NULL when no instruction 726 * clobbers. */ 727 OptInstClobberMask* inst_clobbers; 728 u32 inst_clobbers_cap; 729 OptPRegInfo* preg_info; /* indexed by the current allocation reg namespace */ 730 OptLoc* preg_locs; /* canonical final allocation locations by PReg */ 731 MFunc* mir; /* physical post-allocation IR; HIR stays virtual */ 732 u32* opt_coalesce_parent; 733 u32* opt_coalesce_size; 734 OptAllocSegment* opt_alloc_segments; 735 u32 opt_nalloc_segments; 736 u32 opt_alloc_segments_cap; 737 u32* opt_first_segment_by_preg; 738 739 OptUse* opt_uses; 740 u32 opt_nuses, opt_uses_cap; 741 u32* opt_first_use_by_val; /* indexed by Val, OPT_USE_NONE if no uses */ 742 u32 opt_first_use_by_val_cap; 743 u32 opt_valid_analyses; 744 745 Reg opt_hard_regs[OPT_REG_CLASSES][OPT_MAX_HARD_REGS]; 746 u32 opt_hard_reg_count[OPT_REG_CLASSES]; 747 CGPhysRegInfo opt_phys_regs[OPT_REG_CLASSES][OPT_MAX_HARD_REGS]; 748 u32 opt_phys_reg_count[OPT_REG_CLASSES]; 749 Reg opt_scratch_regs[OPT_REG_CLASSES][OPT_MAX_SCRATCH_REGS]; 750 u32 opt_scratch_reg_count[OPT_REG_CLASSES]; 751 u32 opt_caller_saved[OPT_REG_CLASSES]; /* bit r set if hard reg r is 752 caller-saved */ 753 u32 opt_callee_saved[OPT_REG_CLASSES]; 754 u32 opt_reserved_regs[OPT_REG_CLASSES]; 755 u32 opt_arg_regs[OPT_REG_CLASSES]; 756 u32 opt_ret_regs[OPT_REG_CLASSES]; 757 } Func; 758 759 /* ---- API ---- */ 760 761 Func* ir_func_new(Compiler*, const CGFuncDesc*); 762 763 u32 ir_block_new(Func*); 764 FrameSlot ir_frame_slot_new(Func*, const FrameSlotDesc*); 765 void ir_param_add(Func*, const CGParamDesc*); 766 u32 ir_local_add(Func*, const CGLocalDesc*, CGLocalStorage); 767 768 Val ir_alloc_val(Func*, KitCgTypeId, u8 cls); 769 void ir_ensure_val(Func*, Val, KitCgTypeId, u8 cls); 770 PReg ir_alloc_preg(Func*, KitCgTypeId, u8 cls); 771 void ir_ensure_preg(Func*, PReg, KitCgTypeId, u8 cls); 772 773 Inst* ir_emit(Func*, u32 block, IROp); 774 InstId ir_inst_id_new(Func*); 775 void ir_assign_inst_id(Func*, Inst*); 776 777 /* Resize a block's successor array. Used by ops with >2 successors 778 * (IR_SWITCH, IR_INDIRECT_BRANCH). Always sets nsucc to n. */ 779 void ir_block_set_nsucc(Func*, u32 block, u32 n); 780 781 /* Append `block` to f->emit_order if not already present. Called by 782 * the wrapper whenever cur transitions to a block. */ 783 void ir_note_emit(Func*, u32 block); 784 /* Append Inst to block; caller fills op-specific fields. The Inst is 785 * arena-resident; its address is stable until the Block.insts array is 786 * reallocated by phi insertion (which fixes up references). */ 787 788 #endif