fold.h (5229B)
1 #ifndef KIT_CG_FOLD_H 2 #define KIT_CG_FOLD_H 3 4 /* The semantic-layer peephole optimizer (Track 6). 5 * 6 * The value stack is not just a lowering buffer — it is also a small, named 7 * `-O0` peephole optimizer (a kept feature: free unoptimized-build quality). 8 * This header is its contract; the implementation is src/cg/fold.c. Op families 9 * (arith.c, value.c, memory.c, control.c) call *into* these helpers rather than 10 * reaching into the peephole's internals. 11 * 12 * This header is part of cg/internal.h's surface: cg/internal.h includes it 13 * after the core operand/value types are defined, so anything that includes 14 * cg/internal.h sees these declarations. Do not include fold.h on its own. 15 * 16 * Three responsibilities live here: 17 * 18 * 1. Integer constant folding. Pure width-aware integer arithmetic on 19 * immediates: a binop/unop/cmp of two constants becomes one constant. 20 * The width/mask/sign helpers and the foldable-type predicates back this. 21 * 22 * 2. Delayed-form lifecycle. Two stack entries are held un-emitted so a 23 * consumer can fuse: 24 * - SV_CMP — a compare held so a following branch fuses cmp_branch 25 * instead of materializing a 0/1 then testing it. The 26 * consumer is api_branch_if (control.c); api_ensure_local 27 * materializes it to a 0/1 when used as a value. LIVE. 28 * - SV_ARITH — a small immediate/local arith held so it can flow into a 29 * following binop or collapse via identities. LIVE: 30 * admitted by api_can_delay_int_arith for an unflagged foldable int op. It was 31 * gated off while the load/store EA rider existed; Track 7 removed the rider 32 * and Track 6.3 re-enabled it. Each delayed form has make / release / 33 * materialize-to-dst entry points, plus the fold-chain and identity-collapse 34 * helpers for SV_ARITH. 35 * 36 * 3. Const-local store-to-load forwarding. A scalar auto local with a known 37 * constant value is tracked so a later load reads the immediate directly. 38 * The invalidation boundaries are explicit: 39 * api_local_const_memory_boundary (a possibly-aliasing store/call), 40 * api_local_const_control_boundary (a label/branch/jump — no CFG, so values 41 * cannot cross edges), and api_local_const_address_taken (the local escaped). 42 */ 43 44 /* ---- 1. integer constant folding ---- */ 45 46 u32 api_int_like_width(Compiler* c, KitCgTypeId id); 47 int api_type_is_bool(Compiler* c, KitCgTypeId id); 48 u64 api_width_mask(u32 width); 49 u64 api_mask_width(u64 v, u32 width); 50 i64 api_sign_extend_width(u64 v, u32 width); 51 int api_foldable_int_like_type(Compiler* c, KitCgTypeId ty, u32* width_out); 52 int api_foldable_int_type(Compiler* c, KitCgTypeId ty, u32* width_out); 53 i64 api_fold_result(Compiler* c, KitCgTypeId ty, u64 v, u32 width); 54 int api_try_fold_int_binop(KitCg* g, BinOp op, KitCgTypeId ty, i64 a, i64 b, 55 i64* out); 56 int api_try_fold_int_unop(KitCg* g, UnOp op, KitCgTypeId ty, i64 a, i64* out); 57 int api_try_fold_int_cmp(KitCg* g, CmpOp op, KitCgTypeId ty, i64 a, i64 b, 58 i64* out); 59 60 /* ---- 2a. delayed compare (SV_CMP) lifecycle ---- */ 61 62 ApiSValue api_make_cmp(CmpOp op, Operand a, Operand b, KitCgTypeId result_ty, 63 int a_owned, int b_owned); 64 void api_release_cmp(KitCg* g, ApiSValue* sv); 65 void api_materialize_cmp_to(KitCg* g, ApiSValue* sv, Operand dst); 66 CmpOp api_invert_cmp(CmpOp op); 67 68 /* ---- 2b. delayed arith (SV_ARITH) lifecycle — live (Track 6.3) ---- */ 69 70 ApiSValue api_make_arith_unop(UnOp op, Operand a, KitCgTypeId ty, int a_owned); 71 ApiSValue api_make_arith_binop(BinOp op, Operand a, Operand b, KitCgTypeId ty, 72 int a_owned, int b_owned); 73 void api_release_arith(KitCg* g, ApiSValue* sv); 74 void api_materialize_arith_to(KitCg* g, ApiSValue* sv, Operand dst); 75 int api_arith_rhs_reusable(const ApiSValue* sv); 76 int api_can_delay_int_arith(KitCg* g, KitCgTypeId ty, u32 flags); 77 int api_try_strength_reduce(KitCg* g, BinOp* op, KitCgTypeId ty, ApiSValue* a, 78 ApiSValue* b); 79 int api_op_is_int_identity(KitCg* g, BinOp op, KitCgTypeId ty, i64 imm); 80 int api_try_collapse_binop_identity(KitCg* g, BinOp op, KitCgTypeId ty, 81 ApiSValue* a, ApiSValue* b, ApiSValue* out); 82 int api_try_fold_arith_chain(KitCg* g, BinOp op, KitCgTypeId ty, ApiSValue* a, 83 ApiSValue* b, ApiSValue* out); 84 int api_try_fold_unary_chain(ApiSValue* a, UnOp op, KitCgTypeId ty, 85 ApiSValue* out); 86 87 /* ---- 3. const-local store-to-load forwarding ---- */ 88 89 void api_local_const_clear(ApiSourceLocal* rec); 90 void api_local_const_clear_all(KitCg* g); 91 void api_local_const_memory_boundary(KitCg* g); 92 void api_local_const_control_boundary(KitCg* g); 93 void api_local_const_address_taken(KitCg* g, KitCgLocal local); 94 int api_local_const_can_track(KitCg* g, const ApiSourceLocal* rec, 95 KitCgMemAccess access); 96 void api_local_const_store(KitCg* g, KitCgLocal local, KitCgMemAccess access, 97 i64 value); 98 int api_local_const_load(KitCg* g, KitCgLocal local, KitCgMemAccess access, 99 Operand* out); 100 101 #endif