opt_internal.h (6497B)
1 #ifndef KIT_OPT_INTERNAL_H 2 #define KIT_OPT_INTERNAL_H 3 4 #include "opt/opt.h" 5 6 #define OPT_USE_NONE 0xffffffffu 7 8 typedef struct OptHardRegSet { 9 u32 cls[OPT_REG_CLASSES]; 10 } OptHardRegSet; 11 12 typedef struct OptHardBlockLive { 13 OptHardRegSet live_in; 14 OptHardRegSet live_out; 15 OptHardRegSet live_use; 16 OptHardRegSet live_def; 17 } OptHardBlockLive; 18 19 typedef struct OptPassCtx { 20 Compiler* c; 21 Func* f; 22 Arena* arena; 23 const char* stage; 24 } OptPassCtx; 25 26 typedef struct FuncSet FuncSet; 27 struct FuncSet { 28 Compiler* c; 29 Arena* arena; 30 Func** funcs; 31 u32 nfuncs; 32 u32 cap; 33 }; 34 35 typedef struct OptBlockList { 36 u32* items; 37 u32 n; 38 u32 cap; 39 } OptBlockList; 40 41 typedef struct OptAnalysis { 42 Arena* arena; 43 Func* f; 44 u32 nblocks; 45 u32 entry; 46 u32* po; 47 u32* rpo; 48 u32* po_index; 49 u8* reachable; 50 u32 npo; 51 u32 nrpo; 52 u32* idom; 53 OptBlockList* dom_children; 54 OptBlockList* dom_frontier; 55 } OptAnalysis; 56 57 typedef enum OptAnalysisFlag { 58 OPT_ANALYSIS_CFG = 1u << 0, 59 OPT_ANALYSIS_DEF_USE = 1u << 1, 60 OPT_ANALYSIS_DOM = 1u << 2, 61 OPT_ANALYSIS_LOOP = 1u << 3, 62 } OptAnalysisFlag; 63 64 typedef void (*OptOperandWalkFn)(Func*, Inst*, Operand*, int is_def, void*); 65 66 static inline u32 opt_reg_count(const Func* f) { 67 if (!f) return 0; 68 if (f->opt_reg_ssa) return f->nvals; 69 /* Real recorded O1 functions have npregs > 1. The nvals fallback keeps 70 * standalone pass tests that hand-build Val-shaped IR working without 71 * making ir_ensure_preg grow the Val table. */ 72 return f->npregs > 1 ? f->npregs : f->nvals; 73 } 74 75 static inline int opt_reg_valid(const Func* f, PReg r) { 76 return r != PREG_NONE && r != 0 && r < opt_reg_count(f); 77 } 78 79 static inline KitCgTypeId opt_reg_type(const Func* f, PReg r) { 80 if (!opt_reg_valid(f, r)) return 0; 81 if (f->opt_reg_ssa || f->npregs <= 1) return f->val_type[(Val)r]; 82 return f->preg_type[r]; 83 } 84 85 static inline u8 opt_reg_cls(const Func* f, PReg r) { 86 if (!opt_reg_valid(f, r)) return RC_INT; 87 if (f->opt_reg_ssa || f->npregs <= 1) return f->val_cls[(Val)r]; 88 return f->preg_cls[r]; 89 } 90 91 static inline const OptLoc* opt_preg_loc(const Func* f, PReg r) { 92 if (!f || !f->preg_locs || !opt_reg_valid(f, r)) return NULL; 93 return &f->preg_locs[r]; 94 } 95 96 static inline u8 opt_preg_alloc_kind(const Func* f, PReg r) { 97 const OptLoc* loc = opt_preg_loc(f, r); 98 if (loc) { 99 switch ((OptLocKind)loc->kind) { 100 case OPT_LOC_HARD: 101 return OPT_ALLOC_HARD; 102 case OPT_LOC_STACK: 103 return OPT_ALLOC_SPILL; 104 case OPT_LOC_NONE: 105 default: 106 break; 107 } 108 } 109 if (!f || !f->preg_info || !opt_reg_valid(f, r)) return OPT_ALLOC_NONE; 110 return f->preg_info[r].alloc_kind; 111 } 112 113 static inline u8 opt_preg_loc_cls(const Func* f, PReg r) { 114 const OptLoc* loc = opt_preg_loc(f, r); 115 if (loc && loc->kind != OPT_LOC_NONE) return loc->cls; 116 if (f && f->preg_info && opt_reg_valid(f, r)) return f->preg_info[r].cls; 117 return opt_reg_cls(f, r); 118 } 119 120 static inline Reg opt_preg_hard_reg(const Func* f, PReg r) { 121 const OptLoc* loc = opt_preg_loc(f, r); 122 if (loc && loc->kind == OPT_LOC_HARD) return loc->hard_reg; 123 if (f && f->preg_info && opt_reg_valid(f, r)) return f->preg_info[r].hard_reg; 124 return REG_NONE; 125 } 126 127 static inline FrameSlot opt_preg_spill_slot(const Func* f, PReg r) { 128 const OptLoc* loc = opt_preg_loc(f, r); 129 if (loc && loc->kind == OPT_LOC_STACK) return loc->spill_slot; 130 if (f && f->preg_info && opt_reg_valid(f, r)) 131 return f->preg_info[r].spill_slot; 132 return FRAME_SLOT_NONE; 133 } 134 135 void opt_analysis_mark_valid(Func*, u32 flags); 136 void opt_analysis_invalidate(Func*, u32 flags); 137 int opt_analysis_has(Func*, u32 flags); 138 void opt_analysis_build_order(Func*, OptAnalysis*); 139 void opt_analysis_build_dominators(Func*, OptAnalysis*); 140 void opt_analysis_build_dom_frontier(Func*, OptAnalysis*); 141 int opt_analysis_dominates(const OptAnalysis*, u32 dom, u32 node); 142 void opt_rebuild_def_use(Func*); 143 void opt_verify(Func*, const char* stage); 144 void opt_replace_succ_ref(Func*, u32 pred, u32 old_succ, u32 new_succ); 145 void opt_emit_order_insert_after(Func*, u32 after, u32 block); 146 int opt_edge_is_fallthrough(Func*, u32 pred, u32 succ); 147 u32 opt_split_edge(Func*, u32 pred, u32 succ); 148 149 int opt_val_in_inst_defs(const Inst*, Val); 150 void opt_walk_operand(Func*, Inst*, Operand*, int is_def, OptOperandWalkFn, 151 void*); 152 void opt_walk_abivalue(Func*, Inst*, CGABIValue*, int storage_def, 153 OptOperandWalkFn, void*); 154 void opt_walk_inst_operands(Func*, Inst*, OptOperandWalkFn, void*); 155 156 /* Make room for k new instructions starting at index `at` in block `bl`. 157 * Returns a pointer to the first new slot (zero-initialized). Grows the 158 * block's inst array (doubling) as needed. */ 159 Inst* opt_block_insert_at(Func*, Block* bl, u32 at, u32 k); 160 161 int opt_mem_observable(const MemAccess*); 162 u32 opt_call_clobber_mask_for(Func*, const Inst*, u8 cls); 163 164 int opt_inst_has_side_effect(Func*, const Inst*); 165 166 /* Inlining. opt_inline is the whole-program driver (FuncSet over all retained 167 * funcs). opt_try_tiny_inline is the streaming O1 entry: it inlines tiny 168 * direct callees into one caller, resolving callee bodies through `lookup` 169 * (returns a fresh pre-machinize Func for a symbol, or NULL to skip). Returns 170 * the number of call sites inlined. */ 171 typedef Func* (*OptInlineCalleeLookup)(void* ctx, ObjSymId callee_sym); 172 int opt_try_tiny_inline(Func* caller, OptInlineCalleeLookup lookup, void* ctx); 173 void opt_inline(FuncSet*, int max_iters); 174 175 int opt_hard_empty(const OptHardRegSet*); 176 int opt_hard_intersects(const OptHardRegSet*, const OptHardRegSet*); 177 void opt_hard_live_step(OptHardRegSet* live, const OptHardRegSet* use, 178 const OptHardRegSet* def); 179 void opt_hard_inst_use_def(Func*, const Inst*, OptHardRegSet* use, 180 OptHardRegSet* def); 181 OptHardBlockLive* opt_maybe_build_hard_live(Func*); 182 OptHardRegSet opt_hard_live_out_for_block(const OptHardBlockLive*); 183 int opt_block_live_out_has_phys_reg(Func*, const OptHardBlockLive*, u32 block, 184 const Operand*); 185 void opt_coalesce_ranges(Func*, const OptLiveRangeSet*); 186 /* Return 0 (no overlap), 1 (a single unit-length overlap), or 2 (real 187 * conflict: an overlap longer than one point, or two or more disjoint 188 * unit-length overlaps). A unit overlap is the safe swap-friendly case 189 * where one PReg dies exactly where another is born (`dst = op(... src ...)` 190 * with dst placed in src's reg). */ 191 int opt_ranges_overlap_kind(const OptLiveRangeSet*, PReg a, PReg b); 192 193 #endif