kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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