kit

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

pass_analysis.c (31986B)


      1 #include <string.h>
      2 
      3 #include "core/arena.h"
      4 #include "core/core.h"
      5 #include "core/slice.h"
      6 #include "opt/opt_internal.h"
      7 
      8 #define OPT_BLK_NONE 0xffffffffu
      9 
     10 #ifndef NDEBUG
     11 static SrcLoc opt_no_loc(void) {
     12   SrcLoc loc = {0, 0, 0};
     13   return loc;
     14 }
     15 
     16 static void opt_fail(Func* f, const char* stage, const char* msg, u32 a,
     17                      u32 b) {
     18   compiler_panic(f->c, opt_no_loc(), "opt verify[%.*s]: %.*s (%u, %u)",
     19                  SLICE_ARG(slice_from_cstr(stage ? stage : "?")),
     20                  SLICE_ARG(slice_from_cstr(msg)), (unsigned)a, (unsigned)b);
     21 }
     22 
     23 /* Does `hay` contain the bytes of NUL-terminated `needle`? Length-explicit
     24  * substring search; no strstr. */
     25 static int slice_contains_cstr(Slice hay, const char* needle) {
     26   Slice n = slice_from_cstr(needle);
     27   size_t i;
     28   if (n.len == 0) return 1;
     29   if (hay.len < n.len) return 0;
     30   for (i = 0; i + n.len <= hay.len; ++i)
     31     if (memcmp(hay.s + i, n.s, n.len) == 0) return 1;
     32   return 0;
     33 }
     34 
     35 static int verify_stage_is_ssa(const char* stage) {
     36   Slice s = slice_from_cstr(stage);
     37   return stage && slice_contains_cstr(s, "ssa") &&
     38          !slice_contains_cstr(s, "pre-ssa");
     39 }
     40 
     41 static u8 verify_type_reg_class(Func* f, KitCgTypeId ty) {
     42   return opt_value_reg_class(f->c, ty);
     43 }
     44 
     45 static void verify_frame_slot(Func* f, const char* stage, FrameSlot slot,
     46                               const char* msg) {
     47   if (slot == FRAME_SLOT_NONE || slot > f->nframe_slots)
     48     opt_fail(f, stage, msg, slot, f->nframe_slots);
     49 }
     50 
     51 static void verify_storage(Func* f, const char* stage, CGLocalStorage st,
     52                            KitCgTypeId type, u8 expect_cls, const char* msg) {
     53   switch ((CGLocalStorageKind)st.kind) {
     54     case CG_LOCAL_STORAGE_FRAME:
     55       verify_frame_slot(f, stage, st.v.frame_slot, msg);
     56       break;
     57     case CG_LOCAL_STORAGE_REG: {
     58       PReg r = (PReg)st.v.reg;
     59       if (r == PREG_NONE || r == 0 || r >= opt_reg_count(f))
     60         opt_fail(f, stage, msg, r, opt_reg_count(f));
     61       if (!f->opt_reg_ssa && f->preg_cls && f->preg_cls[r] != expect_cls)
     62         opt_fail(f, stage, "storage class mismatch", r, f->preg_cls[r]);
     63       if (!f->opt_reg_ssa && type && f->preg_type && f->preg_type[r] &&
     64           f->preg_type[r] != type)
     65         opt_fail(f, stage, "storage type mismatch", r, type);
     66       break;
     67     }
     68     default:
     69       opt_fail(f, stage, "bad storage kind", st.kind, 0);
     70       break;
     71   }
     72 }
     73 
     74 static void verify_operand_shape(Func* f, const char* stage, const Operand* op,
     75                                  int physical_regs) {
     76   if (!op) return;
     77   switch ((OptOperandKind)op->kind) {
     78     case OPK_IMM:
     79     case OPK_GLOBAL:
     80       break;
     81     case OPK_LOCAL:
     82       verify_frame_slot(f, stage, op->v.frame_slot, "bad local frame slot");
     83       break;
     84     case OPK_REG:
     85       if (op->cls >= OPT_REG_CLASSES)
     86         opt_fail(f, stage, "bad operand class", op->cls, OPT_REG_CLASSES);
     87       if (physical_regs) {
     88         if (op->v.reg == (Reg)REG_NONE || op->v.reg >= OPT_MAX_HARD_REGS)
     89           opt_fail(f, stage, "bad physical operand reg", op->v.reg,
     90                    OPT_MAX_HARD_REGS);
     91       }
     92       break;
     93     case OPK_INDIRECT:
     94       if (op->cls >= OPT_REG_CLASSES)
     95         opt_fail(f, stage, "bad indirect class", op->cls, OPT_REG_CLASSES);
     96       if (physical_regs) {
     97         if (op->v.ind.base == (Reg)REG_NONE ||
     98             op->v.ind.base >= OPT_MAX_HARD_REGS)
     99           opt_fail(f, stage, "bad physical indirect base", op->v.ind.base,
    100                    OPT_MAX_HARD_REGS);
    101         if (op->v.ind.index != (Reg)REG_NONE &&
    102             op->v.ind.index >= OPT_MAX_HARD_REGS)
    103           opt_fail(f, stage, "bad physical indirect index", op->v.ind.index,
    104                    OPT_MAX_HARD_REGS);
    105       }
    106       break;
    107     default:
    108       opt_fail(f, stage, "bad operand kind", op->kind, 0);
    109       break;
    110   }
    111 }
    112 
    113 static void verify_abivalue_shape(Func* f, const char* stage, CGABIValue* v,
    114                                   int physical_regs) {
    115   if (!v) return;
    116   verify_operand_shape(f, stage, &v->storage, physical_regs);
    117   for (u32 i = 0; i < v->nparts; ++i)
    118     verify_operand_shape(f, stage, &v->parts[i].op, physical_regs);
    119 }
    120 
    121 static void verify_call_plan_shape(Func* f, const char* stage, CGCallPlan* plan,
    122                                    int physical_regs) {
    123   if (!plan) return;
    124   verify_operand_shape(f, stage, &plan->callee, physical_regs);
    125   for (u32 i = 0; i < plan->nargs; ++i) {
    126     verify_operand_shape(f, stage, &plan->args[i].src, physical_regs);
    127     if (plan->args[i].dst_kind == CG_CALL_PLAN_REG &&
    128         plan->args[i].dst_reg >= OPT_MAX_HARD_REGS)
    129       opt_fail(f, stage, "bad call-plan dst reg", plan->args[i].dst_reg,
    130                OPT_MAX_HARD_REGS);
    131   }
    132   for (u32 i = 0; i < plan->nrets; ++i) {
    133     verify_operand_shape(f, stage, &plan->rets[i].dst, physical_regs);
    134     if (plan->rets[i].src_reg >= OPT_MAX_HARD_REGS)
    135       opt_fail(f, stage, "bad call-plan ret reg", plan->rets[i].src_reg,
    136                OPT_MAX_HARD_REGS);
    137   }
    138 }
    139 
    140 static void verify_aux_shapes(Func* f, const char* stage, Inst* in,
    141                               int physical_regs) {
    142   switch ((IROp)in->op) {
    143     case IR_CALL: {
    144       IRCallAux* aux = (IRCallAux*)in->extra.aux;
    145       if (!aux) break;
    146       if (aux->use_plan_replay) {
    147         verify_call_plan_shape(f, stage, &aux->plan, physical_regs);
    148       } else {
    149         verify_operand_shape(f, stage, &aux->desc.callee, physical_regs);
    150         for (u32 i = 0; i < aux->desc.nargs; ++i)
    151           verify_abivalue_shape(f, stage, (CGABIValue*)&aux->desc.args[i],
    152                                 physical_regs);
    153         verify_abivalue_shape(f, stage, &aux->desc.ret, physical_regs);
    154       }
    155       break;
    156     }
    157     case IR_RET: {
    158       IRRetAux* aux = (IRRetAux*)in->extra.aux;
    159       if (aux && aux->present)
    160         verify_abivalue_shape(f, stage, &aux->val, physical_regs);
    161       break;
    162     }
    163     case IR_SCOPE_BEGIN:
    164       break;
    165     case IR_ASM_BLOCK: {
    166       IRAsmAux* aux = (IRAsmAux*)in->extra.aux;
    167       if (!aux) break;
    168       for (u32 i = 0; i < aux->nin; ++i)
    169         verify_operand_shape(f, stage, &aux->in_ops[i], physical_regs);
    170       for (u32 i = 0; i < aux->nout; ++i)
    171         verify_operand_shape(f, stage, &aux->out_ops[i], physical_regs);
    172       break;
    173     }
    174     case IR_INTRINSIC: {
    175       IRIntrinAux* aux = (IRIntrinAux*)in->extra.aux;
    176       if (!aux) break;
    177       for (u32 i = 0; i < aux->narg; ++i)
    178         verify_operand_shape(f, stage, &aux->args[i], physical_regs);
    179       for (u32 i = 0; i < aux->ndst; ++i)
    180         verify_operand_shape(f, stage, &aux->dsts[i], physical_regs);
    181       break;
    182     }
    183     default:
    184       break;
    185   }
    186 }
    187 #endif
    188 
    189 void opt_analysis_mark_valid(Func* f, u32 flags) {
    190   if (!f) return;
    191   f->opt_valid_analyses |= flags;
    192 }
    193 
    194 void opt_analysis_invalidate(Func* f, u32 flags) {
    195   if (!f) return;
    196   f->opt_valid_analyses &= ~flags;
    197 }
    198 
    199 int opt_analysis_has(Func* f, u32 flags) {
    200   return f && (f->opt_valid_analyses & flags) == flags;
    201 }
    202 
    203 static void block_list_add(Arena* arena, OptBlockList* list, u32 block) {
    204   if (list->n == list->cap) {
    205     u32 ncap = list->cap ? list->cap * 2u : 4u;
    206     u32* items = arena_array(arena, u32, ncap);
    207     if (list->items) memcpy(items, list->items, sizeof(items[0]) * list->n);
    208     list->items = items;
    209     list->cap = ncap;
    210   }
    211   list->items[list->n++] = block;
    212 }
    213 
    214 static void block_list_add_unique(Arena* arena, OptBlockList* list, u32 block) {
    215   for (u32 i = 0; i < list->n; ++i)
    216     if (list->items[i] == block) return;
    217   block_list_add(arena, list, block);
    218 }
    219 
    220 /* The label-addr target block reachable from one instruction, if any
    221  * (computed gotos / local static-data label addresses keep their target block
    222  * live). Returns 1 and sets *out when the inst names a target. */
    223 static int order_inst_label_target(const Inst* in, u32* out) {
    224   switch ((IROp)in->op) {
    225     case IR_LOAD_LABEL_ADDR:
    226       *out = (u32)in->extra.imm;
    227       return 1;
    228     case IR_LOCAL_STATIC_DATA_LABEL_ADDR: {
    229       CgIrLocalStaticLabelAux* aux = (CgIrLocalStaticLabelAux*)in->extra.aux;
    230       if (!aux) return 0;
    231       *out = (u32)aux->target;
    232       return 1;
    233     }
    234     default:
    235       return 0;
    236   }
    237 }
    238 
    239 /* One in-progress DFS frame: the block plus cursors into its successor list
    240  * and instruction stream (the two child sources, walked in that order). */
    241 typedef struct OrderFrame {
    242   u32 block;
    243   u32 succ_i;
    244   u32 inst_i;
    245 } OrderFrame;
    246 
    247 /* Iterative post-order DFS over the block graph: successors first, then the
    248  * label-addr targets in instruction order, recording the block once its
    249  * children are exhausted. An explicit stack replaces recursion so a deeply
    250  * linear CFG cannot overflow the C stack; the visit/mark/emit sequence is
    251  * identical to the former recursive walk, so the post-order (and the
    252  * dominance/RPO numbering derived from it) is unchanged. */
    253 static void order_dfs(OptAnalysis* a, u32 entry) {
    254   OrderFrame* stack;
    255   u32 sp = 0;
    256   if (entry >= a->nblocks || a->reachable[entry]) return;
    257   stack = arena_array(a->arena, OrderFrame, a->nblocks);
    258   a->reachable[entry] = 1;
    259   stack[sp].block = entry;
    260   stack[sp].succ_i = 0;
    261   stack[sp].inst_i = 0;
    262   ++sp;
    263   while (sp > 0) {
    264     OrderFrame* fr = &stack[sp - 1];
    265     Block* bl = &a->f->blocks[fr->block];
    266     int pushed = 0;
    267     while (fr->succ_i < bl->nsucc) {
    268       u32 c = bl->succ[fr->succ_i++];
    269       if (c < a->nblocks && !a->reachable[c]) {
    270         a->reachable[c] = 1;
    271         stack[sp].block = c;
    272         stack[sp].succ_i = 0;
    273         stack[sp].inst_i = 0;
    274         ++sp;
    275         pushed = 1;
    276         break;
    277       }
    278     }
    279     if (pushed) continue;
    280     while (fr->inst_i < bl->ninsts) {
    281       u32 c;
    282       if (order_inst_label_target(&bl->insts[fr->inst_i++], &c) &&
    283           c < a->nblocks && !a->reachable[c]) {
    284         a->reachable[c] = 1;
    285         stack[sp].block = c;
    286         stack[sp].succ_i = 0;
    287         stack[sp].inst_i = 0;
    288         ++sp;
    289         pushed = 1;
    290         break;
    291       }
    292     }
    293     if (pushed) continue;
    294     a->po[a->npo] = fr->block;
    295     a->po_index[fr->block] = a->npo;
    296     ++a->npo;
    297     --sp;
    298   }
    299 }
    300 
    301 void opt_analysis_build_order(Func* f, OptAnalysis* a) {
    302   memset(a, 0, sizeof *a);
    303   a->arena = f->arena;
    304   a->f = f;
    305   a->nblocks = f->nblocks;
    306   a->entry = f->entry;
    307   u32 n = f->nblocks ? f->nblocks : 1u;
    308   a->po = arena_array(f->arena, u32, n);
    309   a->rpo = arena_array(f->arena, u32, n);
    310   a->po_index = arena_array(f->arena, u32, n);
    311   a->reachable = arena_zarray(f->arena, u8, n);
    312   for (u32 i = 0; i < n; ++i) a->po_index[i] = OPT_BLK_NONE;
    313   if (f->entry < f->nblocks) order_dfs(a, f->entry);
    314   a->nrpo = a->npo;
    315   for (u32 i = 0; i < a->npo; ++i) a->rpo[i] = a->po[a->npo - 1u - i];
    316 }
    317 
    318 static u32 dom_intersect(u32 b1, u32 b2, const u32* idom, const u32* po_index) {
    319   while (b1 != b2) {
    320     while (po_index[b1] < po_index[b2]) b1 = idom[b1];
    321     while (po_index[b2] < po_index[b1]) b2 = idom[b2];
    322   }
    323   return b1;
    324 }
    325 
    326 void opt_analysis_build_dominators(Func* f, OptAnalysis* a) {
    327   if (!a->reachable) opt_analysis_build_order(f, a);
    328   u32 n = f->nblocks ? f->nblocks : 1u;
    329   a->idom = arena_array(f->arena, u32, n);
    330   a->dom_children = arena_zarray(f->arena, OptBlockList, n);
    331   for (u32 i = 0; i < n; ++i) a->idom[i] = OPT_BLK_NONE;
    332   if (f->entry >= f->nblocks || !a->reachable[f->entry]) {
    333     opt_analysis_mark_valid(f, OPT_ANALYSIS_DOM);
    334     return;
    335   }
    336   a->idom[f->entry] = f->entry;
    337 
    338   int changed = 1;
    339   while (changed) {
    340     changed = 0;
    341     for (u32 ri = 0; ri < a->nrpo; ++ri) {
    342       u32 b = a->rpo[ri];
    343       if (b == f->entry) continue;
    344       Block* bl = &f->blocks[b];
    345       u32 new_idom = OPT_BLK_NONE;
    346       for (u32 p = 0; p < bl->npreds; ++p) {
    347         u32 pred = bl->preds[p];
    348         if (pred >= f->nblocks || !a->reachable[pred]) continue;
    349         if (a->idom[pred] == OPT_BLK_NONE) continue;
    350         new_idom = new_idom == OPT_BLK_NONE
    351                        ? pred
    352                        : dom_intersect(pred, new_idom, a->idom, a->po_index);
    353       }
    354       if (new_idom != OPT_BLK_NONE && a->idom[b] != new_idom) {
    355         a->idom[b] = new_idom;
    356         changed = 1;
    357       }
    358     }
    359   }
    360 
    361   for (u32 i = 0; i < a->npo; ++i) {
    362     u32 b = a->po[i];
    363     u32 idom = a->idom[b];
    364     if (idom == OPT_BLK_NONE || idom == b) continue;
    365     block_list_add(f->arena, &a->dom_children[idom], b);
    366   }
    367   opt_analysis_mark_valid(f, OPT_ANALYSIS_DOM);
    368 }
    369 
    370 void opt_analysis_build_dom_frontier(Func* f, OptAnalysis* a) {
    371   if (!a->idom) opt_analysis_build_dominators(f, a);
    372   u32 n = f->nblocks ? f->nblocks : 1u;
    373   a->dom_frontier = arena_zarray(f->arena, OptBlockList, n);
    374   for (u32 i = 0; i < a->npo; ++i) {
    375     u32 b = a->po[i];
    376     Block* bl = &f->blocks[b];
    377     if (bl->npreds < 2 || a->idom[b] == OPT_BLK_NONE) continue;
    378     for (u32 p = 0; p < bl->npreds; ++p) {
    379       u32 runner = bl->preds[p];
    380       while (runner != OPT_BLK_NONE && runner != a->idom[b]) {
    381         block_list_add_unique(f->arena, &a->dom_frontier[runner], b);
    382         runner = a->idom[runner];
    383       }
    384     }
    385   }
    386 }
    387 
    388 int opt_analysis_dominates(const OptAnalysis* a, u32 dom, u32 node) {
    389   if (!a || !a->idom || dom >= a->nblocks || node >= a->nblocks) return 0;
    390   if (!a->reachable || !a->reachable[dom] || !a->reachable[node]) return 0;
    391   u32 cur = node;
    392   while (cur != OPT_BLK_NONE) {
    393     if (cur == dom) return 1;
    394     if (cur == a->entry) break;
    395     cur = a->idom[cur];
    396   }
    397   return 0;
    398 }
    399 
    400 #ifndef NDEBUG
    401 static int block_has_pred(const Block* bl, u32 pred) {
    402   for (u32 i = 0; i < bl->npreds; ++i)
    403     if (bl->preds[i] == pred) return 1;
    404   return 0;
    405 }
    406 
    407 static int block_has_succ(const Block* bl, u32 succ) {
    408   for (u32 i = 0; i < bl->nsucc; ++i)
    409     if (bl->succ[i] == succ) return 1;
    410   return 0;
    411 }
    412 
    413 static int fixed_terminator_succ_count(const Inst* in, u32* count_out) {
    414   switch ((IROp)in->op) {
    415     case IR_RET:
    416     case IR_UNREACHABLE:
    417       *count_out = 0;
    418       return 1;
    419     case IR_BR:
    420     case IR_BREAK_TO:
    421     case IR_CONTINUE_TO:
    422       *count_out = 1;
    423       return 1;
    424     case IR_CONDBR:
    425     case IR_CMP_BRANCH:
    426       *count_out = 2;
    427       return 1;
    428     case IR_INTRINSIC: {
    429       IRIntrinAux* aux = (IRIntrinAux*)in->extra.aux;
    430       if (aux && (aux->kind == INTRIN_LONGJMP || aux->kind == INTRIN_TRAP)) {
    431         *count_out = 0;
    432         return 1;
    433       }
    434       return 0;
    435     }
    436     default:
    437       return 0;
    438   }
    439 }
    440 #endif /* !NDEBUG (verify-only helpers) */
    441 
    442 static void opt_use_add(Func* f, Val v, u32 b, u32 i, u8 kind, u32 op_idx,
    443                         u32 pred_idx, Operand* op) {
    444   if (v == VAL_NONE || v >= f->nvals) return;
    445   if (f->opt_nuses == f->opt_uses_cap) {
    446     u32 ncap = f->opt_uses_cap ? f->opt_uses_cap * 2u : 32u;
    447     OptUse* uses = arena_zarray(f->arena, OptUse, ncap);
    448     if (f->opt_uses) memcpy(uses, f->opt_uses, sizeof(uses[0]) * f->opt_nuses);
    449     f->opt_uses = uses;
    450     f->opt_uses_cap = ncap;
    451   }
    452   u32 id = f->opt_nuses++;
    453   OptUse* u = &f->opt_uses[id];
    454   u->val = v;
    455   u->block = b;
    456   u->inst = i;
    457   u->inst_id = f->blocks[b].insts[i].id;
    458   u->kind = kind;
    459   u->operand_index = op_idx;
    460   u->phi_pred_index = pred_idx;
    461   u->operand = op;
    462   u->next_for_val = f->opt_first_use_by_val[v];
    463   f->opt_first_use_by_val[v] = id;
    464 }
    465 
    466 static void opt_use_add_operand(Func* f, u32 b, u32 i, u32 op_idx, Operand* op,
    467                                 int is_def) {
    468   if (!op || is_def) return;
    469   if (op->kind == OPK_REG) {
    470     opt_use_add(f, (Val)op->v.reg, b, i, OPT_USE_OPERAND, op_idx, OPT_USE_NONE,
    471                 op);
    472   } else if (op->kind == OPK_INDIRECT) {
    473     opt_use_add(f, (Val)op->v.ind.base, b, i, OPT_USE_INDIRECT_BASE, op_idx,
    474                 OPT_USE_NONE, op);
    475     if (op->v.ind.index != (Reg)REG_NONE) {
    476       opt_use_add(f, (Val)op->v.ind.index, b, i, OPT_USE_INDIRECT_INDEX, op_idx,
    477                   OPT_USE_NONE, op);
    478     }
    479   }
    480 }
    481 
    482 static void opt_use_add_abivalue(Func* f, u32 b, u32 i, CGABIValue* v,
    483                                  int storage_def) {
    484   if (!v) return;
    485   opt_use_add_operand(f, b, i, OPT_USE_NONE, &v->storage, storage_def);
    486   for (u32 p = 0; p < v->nparts; ++p)
    487     opt_use_add_operand(f, b, i, p, (Operand*)&v->parts[p].op, storage_def);
    488 }
    489 
    490 static int collect_operand_index_is_def(const Inst* in, u32 i) {
    491   if (!in || i >= in->nopnds || in->opnds[i].kind != OPK_REG) return 0;
    492   if (!opt_val_in_inst_defs(in, (Val)in->opnds[i].v.reg)) return 0;
    493   switch ((IROp)in->op) {
    494     case IR_ATOMIC_CAS:
    495       return i == 0 || i == 1;
    496     default:
    497       return i == 0;
    498   }
    499 }
    500 
    501 static void opt_collect_inst_uses(Func* f, u32 b, u32 i, Inst* in) {
    502   for (u32 o = 0; o < in->nopnds; ++o) {
    503     int is_def = collect_operand_index_is_def(in, o);
    504     opt_use_add_operand(f, b, i, o, &in->opnds[o], is_def);
    505   }
    506 
    507   switch ((IROp)in->op) {
    508     case IR_PHI: {
    509       IRPhiAux* aux = (IRPhiAux*)in->extra.aux;
    510       if (!aux) break;
    511       for (u32 p = 0; p < aux->npreds; ++p)
    512         opt_use_add(f, aux->pred_vals[p], b, i, OPT_USE_PHI_INPUT, OPT_USE_NONE,
    513                     p, NULL);
    514       break;
    515     }
    516     case IR_CALL: {
    517       IRCallAux* aux = (IRCallAux*)in->extra.aux;
    518       if (!aux) break;
    519       if (aux->use_plan_replay) {
    520         opt_use_add_operand(f, b, i, OPT_USE_NONE, &aux->plan.callee, 0);
    521         for (u32 a = 0; a < aux->plan.nargs; ++a)
    522           opt_use_add_operand(f, b, i, a, &aux->plan.args[a].src, 0);
    523       } else {
    524         opt_use_add_operand(f, b, i, OPT_USE_NONE, &aux->desc.callee, 0);
    525         for (u32 a = 0; a < aux->desc.nargs; ++a)
    526           opt_use_add_abivalue(f, b, i, (CGABIValue*)&aux->desc.args[a], 0);
    527       }
    528       break;
    529     }
    530     case IR_RET: {
    531       IRRetAux* aux = (IRRetAux*)in->extra.aux;
    532       if (aux && aux->present) opt_use_add_abivalue(f, b, i, &aux->val, 0);
    533       break;
    534     }
    535     case IR_SCOPE_BEGIN:
    536       break;
    537     case IR_ASM_BLOCK: {
    538       IRAsmAux* aux = (IRAsmAux*)in->extra.aux;
    539       if (!aux) break;
    540       for (u32 a = 0; a < aux->nin; ++a)
    541         opt_use_add_operand(f, b, i, a, &aux->in_ops[a], 0);
    542       break;
    543     }
    544     case IR_INTRINSIC: {
    545       IRIntrinAux* aux = (IRIntrinAux*)in->extra.aux;
    546       if (!aux) break;
    547       for (u32 a = 0; a < aux->narg; ++a)
    548         opt_use_add_operand(f, b, i, a, &aux->args[a], 0);
    549       break;
    550     }
    551     default:
    552       break;
    553   }
    554 }
    555 
    556 void opt_rebuild_def_use(Func* f) {
    557   u32 nheads;
    558   if (!f) return;
    559   f->opt_nuses = 0;
    560   nheads = f->nvals ? f->nvals : 1u;
    561   if (nheads > f->opt_first_use_by_val_cap) {
    562     u32 ncap = f->opt_first_use_by_val_cap ? f->opt_first_use_by_val_cap : 16u;
    563     while (ncap < nheads) ncap *= 2u;
    564     f->opt_first_use_by_val = arena_array(f->arena, u32, ncap);
    565     f->opt_first_use_by_val_cap = ncap;
    566   }
    567   for (u32 v = 0; v < f->nvals; ++v) f->opt_first_use_by_val[v] = OPT_USE_NONE;
    568   for (u32 b = 0; b < f->nblocks; ++b) {
    569     Block* bl = &f->blocks[b];
    570     for (u32 i = 0; i < bl->ninsts; ++i)
    571       opt_collect_inst_uses(f, b, i, &bl->insts[i]);
    572   }
    573   opt_analysis_mark_valid(f, OPT_ANALYSIS_DEF_USE);
    574 }
    575 
    576 #ifndef NDEBUG
    577 static void verify_operand(Func* f, Inst* in, Operand* op, int is_def,
    578                            void* arg) {
    579   (void)in;
    580   const char* stage = (const char*)arg;
    581   if (op->kind != OPK_REG) return;
    582   Val v = (Val)op->v.reg;
    583   u32 nregs = verify_stage_is_ssa(stage) ? f->nvals : opt_reg_count(f);
    584   if (v == VAL_NONE || v >= nregs)
    585     opt_fail(f, stage, is_def ? "bad def val" : "bad use val", v, nregs);
    586   if (!verify_stage_is_ssa(stage)) return;
    587   if (op->cls != f->val_cls[v])
    588     opt_fail(f, stage, is_def ? "def class mismatch" : "use class mismatch", v,
    589              op->cls);
    590 }
    591 
    592 static void verify_values(Func* f, const char* stage) {
    593   if (f->opt_rewritten) return;
    594   u32 inst_cap = f->next_inst_id ? f->next_inst_id : 1u;
    595   u8* seen_inst = arena_zarray(f->arena, u8, inst_cap);
    596   for (u32 b = 0; b < f->nblocks; ++b) {
    597     Block* bl = &f->blocks[b];
    598     for (u32 i = 0; i < bl->ninsts; ++i) {
    599       Inst* in = &bl->insts[i];
    600       if (in->id == INST_ID_NONE || in->id >= f->next_inst_id)
    601         opt_fail(f, stage, "bad inst id", b, i);
    602       if (seen_inst[in->id]) opt_fail(f, stage, "duplicate inst id", in->id, b);
    603       seen_inst[in->id] = 1;
    604       if (in->def != VAL_NONE) {
    605         u32 ndefs = verify_stage_is_ssa(stage) ? f->nvals : opt_reg_count(f);
    606         if (in->def >= ndefs) opt_fail(f, stage, "bad inst def", b, i);
    607         if (verify_stage_is_ssa(stage) && (IROp)in->op == IR_PHI && in->type &&
    608             f->val_type[in->def] && in->type != f->val_type[in->def])
    609           opt_fail(f, stage, "inst def type mismatch", in->def, b);
    610       }
    611       for (u32 d = 0; d < in->ndefs; ++d) {
    612         Val v = in->defs[d];
    613         u32 ndefs = verify_stage_is_ssa(stage) ? f->nvals : opt_reg_count(f);
    614         if (v == VAL_NONE || v >= ndefs)
    615           opt_fail(f, stage, "bad inst multi-def", b, d);
    616       }
    617       for (u32 o = 0; o < in->nopnds; ++o)
    618         verify_operand_shape(f, stage, &in->opnds[o], 0);
    619       verify_aux_shapes(f, stage, in, 0);
    620       opt_walk_inst_operands(f, in, verify_operand, (void*)stage);
    621       if ((IROp)in->op == IR_PHI) {
    622         IRPhiAux* aux = (IRPhiAux*)in->extra.aux;
    623         if (!aux) opt_fail(f, stage, "phi missing aux", b, i);
    624         if (in->def == VAL_NONE) opt_fail(f, stage, "phi missing def", b, i);
    625         if (in->nopnds || in->opnds)
    626           opt_fail(f, stage, "phi should not carry operands", b, i);
    627         if (aux->slot_id > f->nframe_slots)
    628           opt_fail(f, stage, "phi bad slot id", aux->slot_id, f->nframe_slots);
    629         if (aux->reg_id != 0 && aux->reg_id >= f->npregs)
    630           opt_fail(f, stage, "phi bad reg id", aux->reg_id, f->npregs);
    631         if (aux->npreds != bl->npreds)
    632           opt_fail(f, stage, "phi pred count mismatch", aux->npreds,
    633                    bl->npreds);
    634         for (u32 p = 0; p < aux->npreds; ++p) {
    635           if (p >= bl->npreds || aux->pred_blocks[p] != bl->preds[p])
    636             opt_fail(f, stage, "phi pred block mismatch", b, p);
    637           if (aux->pred_vals[p] != VAL_NONE && aux->pred_vals[p] >= f->nvals)
    638             opt_fail(f, stage, "phi bad pred value", aux->pred_vals[p],
    639                      f->nvals);
    640           if (aux->pred_vals[p] != VAL_NONE && f->val_type[aux->pred_vals[p]] &&
    641               f->val_type[aux->pred_vals[p]] != in->type)
    642             opt_fail(f, stage, "phi input type mismatch", b, p);
    643         }
    644       } else if ((IROp)in->op == IR_PARAM_DECL) {
    645         IRParamDeclAux* aux = (IRParamDeclAux*)in->extra.aux;
    646         if (in->nopnds || in->opnds)
    647           opt_fail(f, stage, "param_decl should not carry operands", b, i);
    648         if ((!aux || aux->desc.storage.kind == CG_LOCAL_STORAGE_REG) &&
    649             in->def == VAL_NONE)
    650           opt_fail(f, stage, "param_decl missing def", b, i);
    651       }
    652     }
    653   }
    654 }
    655 
    656 static void verify_function_storage(Func* f, const char* stage) {
    657   for (u32 i = 0; i < f->nframe_slots; ++i) {
    658     IRFrameSlot* s = &f->frame_slots[i];
    659     if (s->id != i + 1u) opt_fail(f, stage, "frame slot id mismatch", s->id, i);
    660     if (s->kind > FS_SPILL)
    661       opt_fail(f, stage, "bad frame slot kind", s->kind, i);
    662   }
    663   for (u32 i = 0; i < f->nparams; ++i) {
    664     IRParam* p = &f->params[i];
    665     u8 cls = verify_type_reg_class(f, p->type);
    666     if (p->index != i) opt_fail(f, stage, "param index mismatch", p->index, i);
    667     verify_storage(f, stage, p->storage, p->type, cls, "bad param storage");
    668   }
    669   for (u32 i = 0; i < f->nlocals; ++i) {
    670     IRLocal* l = &f->locals[i];
    671     u8 cls = verify_type_reg_class(f, l->desc.type);
    672     verify_storage(f, stage, l->storage, l->desc.type, cls,
    673                    "bad local storage");
    674     if (l->home_slot != FRAME_SLOT_NONE)
    675       verify_frame_slot(f, stage, l->home_slot, "bad local home slot");
    676   }
    677 }
    678 
    679 static void verify_allocations(Func* f, const char* stage) {
    680   if (!f->preg_info && !f->preg_locs) return;
    681   for (PReg r = 1; r < opt_reg_count(f); ++r) {
    682     OptPRegInfo* pi = f->preg_info ? &f->preg_info[r] : NULL;
    683     OptLoc* loc = f->preg_locs ? &f->preg_locs[r] : NULL;
    684     u8 alloc_kind = opt_preg_alloc_kind(f, r);
    685     u8 cls = opt_preg_loc_cls(f, r);
    686     if (cls >= OPT_REG_CLASSES)
    687       opt_fail(f, stage, "bad preg alloc class", r, cls);
    688     if (pi && pi->alloc_kind != alloc_kind)
    689       opt_fail(f, stage, "alloc kind mirror mismatch", r, pi->alloc_kind);
    690     switch ((OptAllocKind)alloc_kind) {
    691       case OPT_ALLOC_NONE:
    692         if (loc && loc->kind != OPT_LOC_NONE)
    693           opt_fail(f, stage, "alloc location mismatch", r, loc->kind);
    694         break;
    695       case OPT_ALLOC_HARD:
    696         if (opt_preg_hard_reg(f, r) == (Reg)REG_NONE ||
    697             opt_preg_hard_reg(f, r) >= OPT_MAX_HARD_REGS)
    698           opt_fail(f, stage, "bad hard allocation", r, opt_preg_hard_reg(f, r));
    699         if (pi && (pi->cls != cls || pi->hard_reg != opt_preg_hard_reg(f, r)))
    700           opt_fail(f, stage, "hard alloc mirror mismatch", r, pi->hard_reg);
    701         if (loc && (loc->kind != OPT_LOC_HARD || loc->cls != cls))
    702           opt_fail(f, stage, "hard alloc location mismatch", r,
    703                    opt_preg_hard_reg(f, r));
    704         break;
    705       case OPT_ALLOC_SPILL:
    706         verify_frame_slot(f, stage, opt_preg_spill_slot(f, r),
    707                           "bad spill slot");
    708         if (f->frame_slots[opt_preg_spill_slot(f, r) - 1u].kind != FS_SPILL)
    709           opt_fail(f, stage, "spill slot is not FS_SPILL", r,
    710                    opt_preg_spill_slot(f, r));
    711         if (pi &&
    712             (pi->cls != cls || pi->spill_slot != opt_preg_spill_slot(f, r)))
    713           opt_fail(f, stage, "spill alloc mirror mismatch", r, pi->spill_slot);
    714         if (loc && (loc->kind != OPT_LOC_STACK || loc->cls != cls))
    715           opt_fail(f, stage, "spill alloc location mismatch", r,
    716                    opt_preg_spill_slot(f, r));
    717         break;
    718       default:
    719         opt_fail(f, stage, "bad allocation kind", r, alloc_kind);
    720         break;
    721     }
    722   }
    723 }
    724 
    725 static void verify_rewritten(Func* f, const char* stage) {
    726   if (!f->opt_rewritten) return;
    727   for (u32 b = 0; b < f->nblocks; ++b) {
    728     Block* bl = &f->blocks[b];
    729     for (u32 i = 0; i < bl->ninsts; ++i) {
    730       Inst* in = &bl->insts[i];
    731       if ((IROp)in->op == IR_PHI)
    732         opt_fail(f, stage, "phi survived rewrite", b, i);
    733       if ((IROp)in->op == IR_PARAM_DECL) {
    734         IRParamDeclAux* aux = (IRParamDeclAux*)in->extra.aux;
    735         if (in->nopnds || in->opnds)
    736           opt_fail(f, stage, "param_decl carries operands after rewrite", b, i);
    737         if ((!aux || aux->desc.storage.kind == CG_LOCAL_STORAGE_REG) &&
    738             (in->def == VAL_NONE || in->def >= opt_reg_count(f)))
    739           opt_fail(f, stage, "bad param_decl def after rewrite", b, i);
    740         continue;
    741       }
    742       for (u32 o = 0; o < in->nopnds; ++o)
    743         verify_operand_shape(f, stage, &in->opnds[o], 1);
    744       verify_aux_shapes(f, stage, in, 1);
    745     }
    746   }
    747 }
    748 
    749 static void verify_use_site(Func* f, const char* stage, const OptUse* use) {
    750   Inst* in = &f->blocks[use->block].insts[use->inst];
    751   if (in->id != use->inst_id)
    752     opt_fail(f, stage, "def-use stale inst id", use->inst_id, in->id);
    753   switch ((OptUseKind)use->kind) {
    754     case OPT_USE_OPERAND:
    755       if (!use->operand)
    756         opt_fail(f, stage, "def-use missing operand", use->block, use->inst);
    757       if (use->operand->kind != OPK_REG || (Val)use->operand->v.reg != use->val)
    758         opt_fail(f, stage, "def-use operand mismatch", use->val, use->kind);
    759       break;
    760     case OPT_USE_INDIRECT_BASE:
    761       if (!use->operand || use->operand->kind != OPK_INDIRECT ||
    762           (Val)use->operand->v.ind.base != use->val)
    763         opt_fail(f, stage, "def-use indirect mismatch", use->val, use->kind);
    764       break;
    765     case OPT_USE_INDIRECT_INDEX:
    766       if (!use->operand || use->operand->kind != OPK_INDIRECT ||
    767           use->operand->v.ind.index == (Reg)REG_NONE ||
    768           (Val)use->operand->v.ind.index != use->val)
    769         opt_fail(f, stage, "def-use indirect index mismatch", use->val,
    770                  use->kind);
    771       break;
    772     case OPT_USE_PHI_INPUT: {
    773       if ((IROp)in->op != IR_PHI)
    774         opt_fail(f, stage, "def-use phi site mismatch", use->block, use->inst);
    775       IRPhiAux* aux = (IRPhiAux*)in->extra.aux;
    776       if (!aux || use->phi_pred_index >= aux->npreds)
    777         opt_fail(f, stage, "def-use phi pred mismatch", use->val,
    778                  use->phi_pred_index);
    779       if (aux->pred_vals[use->phi_pred_index] != use->val)
    780         opt_fail(f, stage, "def-use phi value mismatch", use->val,
    781                  use->phi_pred_index);
    782       break;
    783     }
    784     default:
    785       opt_fail(f, stage, "def-use bad kind", use->kind, use->val);
    786   }
    787 }
    788 
    789 static void verify_def_use(Func* f, const char* stage) {
    790   if (f->opt_rewritten) return;
    791   if (opt_analysis_has(f, OPT_ANALYSIS_DEF_USE)) {
    792     for (u32 u = 0; u < f->opt_nuses; ++u) {
    793       OptUse* use = &f->opt_uses[u];
    794       if (use->val == VAL_NONE || use->val >= f->nvals)
    795         opt_fail(f, stage, "def-use bad cached val", use->val, f->nvals);
    796       if (use->block >= f->nblocks)
    797         opt_fail(f, stage, "def-use bad cached block", use->block, f->nblocks);
    798       if (use->inst >= f->blocks[use->block].ninsts)
    799         opt_fail(f, stage, "def-use bad cached inst", use->inst,
    800                  f->blocks[use->block].ninsts);
    801       verify_use_site(f, stage, use);
    802     }
    803   }
    804   opt_rebuild_def_use(f);
    805   for (u32 u = 0; u < f->opt_nuses; ++u) {
    806     OptUse* use = &f->opt_uses[u];
    807     if (use->val == VAL_NONE || use->val >= f->nvals)
    808       opt_fail(f, stage, "def-use bad use val", use->val, f->nvals);
    809     if (use->block >= f->nblocks)
    810       opt_fail(f, stage, "def-use bad block", use->block, f->nblocks);
    811     if (use->inst >= f->blocks[use->block].ninsts)
    812       opt_fail(f, stage, "def-use bad inst", use->inst,
    813                f->blocks[use->block].ninsts);
    814     verify_use_site(f, stage, use);
    815     if (f->val_def_block[use->val] >= f->nblocks)
    816       opt_fail(f, stage, "def-use bad def block", use->val,
    817                f->val_def_block[use->val]);
    818   }
    819   for (Val v = 1; v < f->nvals; ++v) {
    820     for (u32 u = f->opt_first_use_by_val[v]; u != OPT_USE_NONE;
    821          u = f->opt_uses[u].next_for_val) {
    822       if (u >= f->opt_nuses) opt_fail(f, stage, "def-use bad next", v, u);
    823       if (f->opt_uses[u].val != v)
    824         opt_fail(f, stage, "def-use wrong value list", v, u);
    825     }
    826   }
    827 }
    828 
    829 #endif /* !NDEBUG */
    830 
    831 void opt_verify(Func* f, const char* stage) {
    832 #ifdef NDEBUG
    833   (void)f;
    834   (void)stage;
    835   return;
    836 #else
    837   if (!f) return;
    838   if (f->nblocks && f->entry >= f->nblocks)
    839     opt_fail(f, stage, "entry out of range", f->entry, f->nblocks);
    840   OptAnalysis a;
    841   opt_analysis_build_order(f, &a);
    842   for (u32 b = 0; b < f->nblocks; ++b) {
    843     Block* bl = &f->blocks[b];
    844     if (bl->id != b) opt_fail(f, stage, "block id mismatch", bl->id, b);
    845     if (!a.reachable[b] && (bl->ninsts || bl->nsucc || bl->npreds))
    846       opt_fail(f, stage, "unreachable block still connected", b, bl->ninsts);
    847     if (bl->ninsts) {
    848       u32 expected = 0;
    849       if (fixed_terminator_succ_count(&bl->insts[bl->ninsts - 1], &expected) &&
    850           bl->nsucc != expected)
    851         opt_fail(f, stage, "terminator successor count mismatch", b, bl->nsucc);
    852     }
    853     for (u32 s = 0; s < bl->nsucc; ++s) {
    854       u32 succ = bl->succ[s];
    855       if (succ >= f->nblocks)
    856         opt_fail(f, stage, "successor out of range", b, s);
    857       if (!block_has_pred(&f->blocks[succ], b))
    858         opt_fail(f, stage, "successor missing reciprocal predecessor", b, succ);
    859     }
    860     for (u32 p = 0; p < bl->npreds; ++p) {
    861       u32 pred = bl->preds[p];
    862       if (pred >= f->nblocks)
    863         opt_fail(f, stage, "predecessor out of range", b, p);
    864       if (!block_has_succ(&f->blocks[pred], b))
    865         opt_fail(f, stage, "predecessor missing reciprocal successor", b, pred);
    866     }
    867   }
    868   u8* seen_emit = arena_zarray(f->arena, u8, f->nblocks ? f->nblocks : 1u);
    869   for (u32 i = 0; i < f->emit_order_n; ++i) {
    870     u32 b = f->emit_order[i];
    871     if (b >= f->nblocks) opt_fail(f, stage, "emit block out of range", b, i);
    872     if (seen_emit[b]) opt_fail(f, stage, "duplicate emit block", b, i);
    873     seen_emit[b] = 1;
    874   }
    875   verify_function_storage(f, stage);
    876   verify_allocations(f, stage);
    877   verify_values(f, stage);
    878   verify_rewritten(f, stage);
    879   verify_def_use(f, stage);
    880 #endif
    881 }