kit

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

pass_analysis.c (31714B)


      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 static void order_dfs(OptAnalysis* a, u32 block);
    221 
    222 static void order_label_addr_target(OptAnalysis* a, const Inst* in) {
    223   switch ((IROp)in->op) {
    224     case IR_LOAD_LABEL_ADDR:
    225       order_dfs(a, (u32)in->extra.imm);
    226       break;
    227     case IR_LOCAL_STATIC_DATA_LABEL_ADDR: {
    228       CgIrLocalStaticLabelAux* aux =
    229           (CgIrLocalStaticLabelAux*)in->extra.aux;
    230       if (aux) order_dfs(a, (u32)aux->target);
    231       break;
    232     }
    233     default:
    234       break;
    235   }
    236 }
    237 
    238 static void order_dfs(OptAnalysis* a, u32 block) {
    239   if (block >= a->nblocks || a->reachable[block]) return;
    240   a->reachable[block] = 1;
    241   Block* bl = &a->f->blocks[block];
    242   for (u32 i = 0; i < bl->nsucc; ++i) order_dfs(a, bl->succ[i]);
    243   for (u32 i = 0; i < bl->ninsts; ++i)
    244     order_label_addr_target(a, &bl->insts[i]);
    245   a->po[a->npo] = block;
    246   a->po_index[block] = a->npo;
    247   ++a->npo;
    248 }
    249 
    250 void opt_analysis_build_order(Func* f, OptAnalysis* a) {
    251   memset(a, 0, sizeof *a);
    252   a->arena = f->arena;
    253   a->f = f;
    254   a->nblocks = f->nblocks;
    255   a->entry = f->entry;
    256   u32 n = f->nblocks ? f->nblocks : 1u;
    257   a->po = arena_array(f->arena, u32, n);
    258   a->rpo = arena_array(f->arena, u32, n);
    259   a->po_index = arena_array(f->arena, u32, n);
    260   a->reachable = arena_zarray(f->arena, u8, n);
    261   for (u32 i = 0; i < n; ++i) a->po_index[i] = OPT_BLK_NONE;
    262   if (f->entry < f->nblocks) order_dfs(a, f->entry);
    263   a->nrpo = a->npo;
    264   for (u32 i = 0; i < a->npo; ++i) a->rpo[i] = a->po[a->npo - 1u - i];
    265 }
    266 
    267 static u32 dom_intersect(u32 b1, u32 b2, const u32* idom, const u32* po_index) {
    268   while (b1 != b2) {
    269     while (po_index[b1] < po_index[b2]) b1 = idom[b1];
    270     while (po_index[b2] < po_index[b1]) b2 = idom[b2];
    271   }
    272   return b1;
    273 }
    274 
    275 void opt_analysis_build_dominators(Func* f, OptAnalysis* a) {
    276   if (!a->reachable) opt_analysis_build_order(f, a);
    277   u32 n = f->nblocks ? f->nblocks : 1u;
    278   a->idom = arena_array(f->arena, u32, n);
    279   a->dom_children = arena_zarray(f->arena, OptBlockList, n);
    280   for (u32 i = 0; i < n; ++i) a->idom[i] = OPT_BLK_NONE;
    281   if (f->entry >= f->nblocks || !a->reachable[f->entry]) {
    282     opt_analysis_mark_valid(f, OPT_ANALYSIS_DOM);
    283     return;
    284   }
    285   a->idom[f->entry] = f->entry;
    286 
    287   int changed = 1;
    288   while (changed) {
    289     changed = 0;
    290     for (u32 ri = 0; ri < a->nrpo; ++ri) {
    291       u32 b = a->rpo[ri];
    292       if (b == f->entry) continue;
    293       Block* bl = &f->blocks[b];
    294       u32 new_idom = OPT_BLK_NONE;
    295       for (u32 p = 0; p < bl->npreds; ++p) {
    296         u32 pred = bl->preds[p];
    297         if (pred >= f->nblocks || !a->reachable[pred]) continue;
    298         if (a->idom[pred] == OPT_BLK_NONE) continue;
    299         new_idom = new_idom == OPT_BLK_NONE
    300                        ? pred
    301                        : dom_intersect(pred, new_idom, a->idom, a->po_index);
    302       }
    303       if (new_idom != OPT_BLK_NONE && a->idom[b] != new_idom) {
    304         a->idom[b] = new_idom;
    305         changed = 1;
    306       }
    307     }
    308   }
    309 
    310   for (u32 i = 0; i < a->npo; ++i) {
    311     u32 b = a->po[i];
    312     u32 idom = a->idom[b];
    313     if (idom == OPT_BLK_NONE || idom == b) continue;
    314     block_list_add(f->arena, &a->dom_children[idom], b);
    315   }
    316   opt_analysis_mark_valid(f, OPT_ANALYSIS_DOM);
    317 }
    318 
    319 void opt_analysis_build_dom_frontier(Func* f, OptAnalysis* a) {
    320   if (!a->idom) opt_analysis_build_dominators(f, a);
    321   u32 n = f->nblocks ? f->nblocks : 1u;
    322   a->dom_frontier = arena_zarray(f->arena, OptBlockList, n);
    323   for (u32 i = 0; i < a->npo; ++i) {
    324     u32 b = a->po[i];
    325     Block* bl = &f->blocks[b];
    326     if (bl->npreds < 2 || a->idom[b] == OPT_BLK_NONE) continue;
    327     for (u32 p = 0; p < bl->npreds; ++p) {
    328       u32 runner = bl->preds[p];
    329       while (runner != OPT_BLK_NONE && runner != a->idom[b]) {
    330         block_list_add_unique(f->arena, &a->dom_frontier[runner], b);
    331         runner = a->idom[runner];
    332       }
    333     }
    334   }
    335 }
    336 
    337 int opt_analysis_dominates(const OptAnalysis* a, u32 dom, u32 node) {
    338   if (!a || !a->idom || dom >= a->nblocks || node >= a->nblocks) return 0;
    339   if (!a->reachable || !a->reachable[dom] || !a->reachable[node]) return 0;
    340   u32 cur = node;
    341   while (cur != OPT_BLK_NONE) {
    342     if (cur == dom) return 1;
    343     if (cur == a->entry) break;
    344     cur = a->idom[cur];
    345   }
    346   return 0;
    347 }
    348 
    349 #ifndef NDEBUG
    350 static int block_has_pred(const Block* bl, u32 pred) {
    351   for (u32 i = 0; i < bl->npreds; ++i)
    352     if (bl->preds[i] == pred) return 1;
    353   return 0;
    354 }
    355 
    356 static int block_has_succ(const Block* bl, u32 succ) {
    357   for (u32 i = 0; i < bl->nsucc; ++i)
    358     if (bl->succ[i] == succ) return 1;
    359   return 0;
    360 }
    361 
    362 static int fixed_terminator_succ_count(const Inst* in, u32* count_out) {
    363   switch ((IROp)in->op) {
    364     case IR_RET:
    365     case IR_UNREACHABLE:
    366       *count_out = 0;
    367       return 1;
    368     case IR_BR:
    369     case IR_BREAK_TO:
    370     case IR_CONTINUE_TO:
    371       *count_out = 1;
    372       return 1;
    373     case IR_CONDBR:
    374     case IR_CMP_BRANCH:
    375       *count_out = 2;
    376       return 1;
    377     case IR_INTRINSIC: {
    378       IRIntrinAux* aux = (IRIntrinAux*)in->extra.aux;
    379       if (aux && (aux->kind == INTRIN_LONGJMP || aux->kind == INTRIN_TRAP)) {
    380         *count_out = 0;
    381         return 1;
    382       }
    383       return 0;
    384     }
    385     default:
    386       return 0;
    387   }
    388 }
    389 #endif /* !NDEBUG (verify-only helpers) */
    390 
    391 static void opt_use_add(Func* f, Val v, u32 b, u32 i, u8 kind, u32 op_idx,
    392                         u32 pred_idx, Operand* op) {
    393   if (v == VAL_NONE || v >= f->nvals) return;
    394   if (f->opt_nuses == f->opt_uses_cap) {
    395     u32 ncap = f->opt_uses_cap ? f->opt_uses_cap * 2u : 32u;
    396     OptUse* uses = arena_zarray(f->arena, OptUse, ncap);
    397     if (f->opt_uses) memcpy(uses, f->opt_uses, sizeof(uses[0]) * f->opt_nuses);
    398     f->opt_uses = uses;
    399     f->opt_uses_cap = ncap;
    400   }
    401   u32 id = f->opt_nuses++;
    402   OptUse* u = &f->opt_uses[id];
    403   u->val = v;
    404   u->block = b;
    405   u->inst = i;
    406   u->inst_id = f->blocks[b].insts[i].id;
    407   u->kind = kind;
    408   u->operand_index = op_idx;
    409   u->phi_pred_index = pred_idx;
    410   u->operand = op;
    411   u->next_for_val = f->opt_first_use_by_val[v];
    412   f->opt_first_use_by_val[v] = id;
    413 }
    414 
    415 static void opt_use_add_operand(Func* f, u32 b, u32 i, u32 op_idx, Operand* op,
    416                                 int is_def) {
    417   if (!op || is_def) return;
    418   if (op->kind == OPK_REG) {
    419     opt_use_add(f, (Val)op->v.reg, b, i, OPT_USE_OPERAND, op_idx, OPT_USE_NONE,
    420                 op);
    421   } else if (op->kind == OPK_INDIRECT) {
    422     opt_use_add(f, (Val)op->v.ind.base, b, i, OPT_USE_INDIRECT_BASE, op_idx,
    423                 OPT_USE_NONE, op);
    424     if (op->v.ind.index != (Reg)REG_NONE) {
    425       opt_use_add(f, (Val)op->v.ind.index, b, i, OPT_USE_INDIRECT_INDEX, op_idx,
    426                   OPT_USE_NONE, op);
    427     }
    428   }
    429 }
    430 
    431 static void opt_use_add_abivalue(Func* f, u32 b, u32 i, CGABIValue* v,
    432                                  int storage_def) {
    433   if (!v) return;
    434   opt_use_add_operand(f, b, i, OPT_USE_NONE, &v->storage, storage_def);
    435   for (u32 p = 0; p < v->nparts; ++p)
    436     opt_use_add_operand(f, b, i, p, (Operand*)&v->parts[p].op, storage_def);
    437 }
    438 
    439 static int collect_operand_index_is_def(const Inst* in, u32 i) {
    440   if (!in || i >= in->nopnds || in->opnds[i].kind != OPK_REG) return 0;
    441   if (!opt_val_in_inst_defs(in, (Val)in->opnds[i].v.reg)) return 0;
    442   switch ((IROp)in->op) {
    443     case IR_ATOMIC_CAS:
    444       return i == 0 || i == 1;
    445     default:
    446       return i == 0;
    447   }
    448 }
    449 
    450 static void opt_collect_inst_uses(Func* f, u32 b, u32 i, Inst* in) {
    451   for (u32 o = 0; o < in->nopnds; ++o) {
    452     int is_def = collect_operand_index_is_def(in, o);
    453     opt_use_add_operand(f, b, i, o, &in->opnds[o], is_def);
    454   }
    455 
    456   switch ((IROp)in->op) {
    457     case IR_PHI: {
    458       IRPhiAux* aux = (IRPhiAux*)in->extra.aux;
    459       if (!aux) break;
    460       for (u32 p = 0; p < aux->npreds; ++p)
    461         opt_use_add(f, aux->pred_vals[p], b, i, OPT_USE_PHI_INPUT, OPT_USE_NONE,
    462                     p, NULL);
    463       break;
    464     }
    465     case IR_CALL: {
    466       IRCallAux* aux = (IRCallAux*)in->extra.aux;
    467       if (!aux) break;
    468       if (aux->use_plan_replay) {
    469         opt_use_add_operand(f, b, i, OPT_USE_NONE, &aux->plan.callee, 0);
    470         for (u32 a = 0; a < aux->plan.nargs; ++a)
    471           opt_use_add_operand(f, b, i, a, &aux->plan.args[a].src, 0);
    472       } else {
    473         opt_use_add_operand(f, b, i, OPT_USE_NONE, &aux->desc.callee, 0);
    474         for (u32 a = 0; a < aux->desc.nargs; ++a)
    475           opt_use_add_abivalue(f, b, i, (CGABIValue*)&aux->desc.args[a], 0);
    476       }
    477       break;
    478     }
    479     case IR_RET: {
    480       IRRetAux* aux = (IRRetAux*)in->extra.aux;
    481       if (aux && aux->present) opt_use_add_abivalue(f, b, i, &aux->val, 0);
    482       break;
    483     }
    484     case IR_SCOPE_BEGIN:
    485       break;
    486     case IR_ASM_BLOCK: {
    487       IRAsmAux* aux = (IRAsmAux*)in->extra.aux;
    488       if (!aux) break;
    489       for (u32 a = 0; a < aux->nin; ++a)
    490         opt_use_add_operand(f, b, i, a, &aux->in_ops[a], 0);
    491       break;
    492     }
    493     case IR_INTRINSIC: {
    494       IRIntrinAux* aux = (IRIntrinAux*)in->extra.aux;
    495       if (!aux) break;
    496       for (u32 a = 0; a < aux->narg; ++a)
    497         opt_use_add_operand(f, b, i, a, &aux->args[a], 0);
    498       break;
    499     }
    500     default:
    501       break;
    502   }
    503 }
    504 
    505 void opt_rebuild_def_use(Func* f) {
    506   u32 nheads;
    507   if (!f) return;
    508   f->opt_nuses = 0;
    509   nheads = f->nvals ? f->nvals : 1u;
    510   if (nheads > f->opt_first_use_by_val_cap) {
    511     u32 ncap = f->opt_first_use_by_val_cap ? f->opt_first_use_by_val_cap : 16u;
    512     while (ncap < nheads) ncap *= 2u;
    513     f->opt_first_use_by_val = arena_array(f->arena, u32, ncap);
    514     f->opt_first_use_by_val_cap = ncap;
    515   }
    516   for (u32 v = 0; v < f->nvals; ++v) f->opt_first_use_by_val[v] = OPT_USE_NONE;
    517   for (u32 b = 0; b < f->nblocks; ++b) {
    518     Block* bl = &f->blocks[b];
    519     for (u32 i = 0; i < bl->ninsts; ++i)
    520       opt_collect_inst_uses(f, b, i, &bl->insts[i]);
    521   }
    522   opt_analysis_mark_valid(f, OPT_ANALYSIS_DEF_USE);
    523 }
    524 
    525 #ifndef NDEBUG
    526 static void verify_operand(Func* f, Inst* in, Operand* op, int is_def,
    527                            void* arg) {
    528   (void)in;
    529   const char* stage = (const char*)arg;
    530   if (op->kind != OPK_REG) return;
    531   Val v = (Val)op->v.reg;
    532   u32 nregs = verify_stage_is_ssa(stage) ? f->nvals : opt_reg_count(f);
    533   if (v == VAL_NONE || v >= nregs)
    534     opt_fail(f, stage, is_def ? "bad def val" : "bad use val", v, nregs);
    535   if (!verify_stage_is_ssa(stage)) return;
    536   if (op->cls != f->val_cls[v])
    537     opt_fail(f, stage, is_def ? "def class mismatch" : "use class mismatch", v,
    538              op->cls);
    539 }
    540 
    541 static void verify_values(Func* f, const char* stage) {
    542   if (f->opt_rewritten) return;
    543   u32 inst_cap = f->next_inst_id ? f->next_inst_id : 1u;
    544   u8* seen_inst = arena_zarray(f->arena, u8, inst_cap);
    545   for (u32 b = 0; b < f->nblocks; ++b) {
    546     Block* bl = &f->blocks[b];
    547     for (u32 i = 0; i < bl->ninsts; ++i) {
    548       Inst* in = &bl->insts[i];
    549       if (in->id == INST_ID_NONE || in->id >= f->next_inst_id)
    550         opt_fail(f, stage, "bad inst id", b, i);
    551       if (seen_inst[in->id]) opt_fail(f, stage, "duplicate inst id", in->id, b);
    552       seen_inst[in->id] = 1;
    553       if (in->def != VAL_NONE) {
    554         u32 ndefs = verify_stage_is_ssa(stage) ? f->nvals : opt_reg_count(f);
    555         if (in->def >= ndefs) opt_fail(f, stage, "bad inst def", b, i);
    556         if (verify_stage_is_ssa(stage) && (IROp)in->op == IR_PHI && in->type &&
    557             f->val_type[in->def] && in->type != f->val_type[in->def])
    558           opt_fail(f, stage, "inst def type mismatch", in->def, b);
    559       }
    560       for (u32 d = 0; d < in->ndefs; ++d) {
    561         Val v = in->defs[d];
    562         u32 ndefs = verify_stage_is_ssa(stage) ? f->nvals : opt_reg_count(f);
    563         if (v == VAL_NONE || v >= ndefs)
    564           opt_fail(f, stage, "bad inst multi-def", b, d);
    565       }
    566       for (u32 o = 0; o < in->nopnds; ++o)
    567         verify_operand_shape(f, stage, &in->opnds[o], 0);
    568       verify_aux_shapes(f, stage, in, 0);
    569       opt_walk_inst_operands(f, in, verify_operand, (void*)stage);
    570       if ((IROp)in->op == IR_PHI) {
    571         IRPhiAux* aux = (IRPhiAux*)in->extra.aux;
    572         if (!aux) opt_fail(f, stage, "phi missing aux", b, i);
    573         if (in->def == VAL_NONE) opt_fail(f, stage, "phi missing def", b, i);
    574         if (in->nopnds || in->opnds)
    575           opt_fail(f, stage, "phi should not carry operands", b, i);
    576         if (aux->slot_id > f->nframe_slots)
    577           opt_fail(f, stage, "phi bad slot id", aux->slot_id, f->nframe_slots);
    578         if (aux->reg_id != 0 && aux->reg_id >= f->npregs)
    579           opt_fail(f, stage, "phi bad reg id", aux->reg_id, f->npregs);
    580         if (aux->npreds != bl->npreds)
    581           opt_fail(f, stage, "phi pred count mismatch", aux->npreds,
    582                    bl->npreds);
    583         for (u32 p = 0; p < aux->npreds; ++p) {
    584           if (p >= bl->npreds || aux->pred_blocks[p] != bl->preds[p])
    585             opt_fail(f, stage, "phi pred block mismatch", b, p);
    586           if (aux->pred_vals[p] != VAL_NONE && aux->pred_vals[p] >= f->nvals)
    587             opt_fail(f, stage, "phi bad pred value", aux->pred_vals[p],
    588                      f->nvals);
    589           if (aux->pred_vals[p] != VAL_NONE && f->val_type[aux->pred_vals[p]] &&
    590               f->val_type[aux->pred_vals[p]] != in->type)
    591             opt_fail(f, stage, "phi input type mismatch", b, p);
    592         }
    593       } else if ((IROp)in->op == IR_PARAM_DECL) {
    594         IRParamDeclAux* aux = (IRParamDeclAux*)in->extra.aux;
    595         if (in->nopnds || in->opnds)
    596           opt_fail(f, stage, "param_decl should not carry operands", b, i);
    597         if ((!aux || aux->desc.storage.kind == CG_LOCAL_STORAGE_REG) &&
    598             in->def == VAL_NONE)
    599           opt_fail(f, stage, "param_decl missing def", b, i);
    600       }
    601     }
    602   }
    603 }
    604 
    605 static void verify_function_storage(Func* f, const char* stage) {
    606   for (u32 i = 0; i < f->nframe_slots; ++i) {
    607     IRFrameSlot* s = &f->frame_slots[i];
    608     if (s->id != i + 1u) opt_fail(f, stage, "frame slot id mismatch", s->id, i);
    609     if (s->kind > FS_SPILL)
    610       opt_fail(f, stage, "bad frame slot kind", s->kind, i);
    611   }
    612   for (u32 i = 0; i < f->nparams; ++i) {
    613     IRParam* p = &f->params[i];
    614     u8 cls = verify_type_reg_class(f, p->type);
    615     if (p->index != i) opt_fail(f, stage, "param index mismatch", p->index, i);
    616     verify_storage(f, stage, p->storage, p->type, cls, "bad param storage");
    617   }
    618   for (u32 i = 0; i < f->nlocals; ++i) {
    619     IRLocal* l = &f->locals[i];
    620     u8 cls = verify_type_reg_class(f, l->desc.type);
    621     verify_storage(f, stage, l->storage, l->desc.type, cls,
    622                    "bad local storage");
    623     if (l->home_slot != FRAME_SLOT_NONE)
    624       verify_frame_slot(f, stage, l->home_slot, "bad local home slot");
    625   }
    626 }
    627 
    628 static void verify_allocations(Func* f, const char* stage) {
    629   if (!f->preg_info && !f->preg_locs) return;
    630   for (PReg r = 1; r < opt_reg_count(f); ++r) {
    631     OptPRegInfo* pi = f->preg_info ? &f->preg_info[r] : NULL;
    632     OptLoc* loc = f->preg_locs ? &f->preg_locs[r] : NULL;
    633     u8 alloc_kind = opt_preg_alloc_kind(f, r);
    634     u8 cls = opt_preg_loc_cls(f, r);
    635     if (cls >= OPT_REG_CLASSES)
    636       opt_fail(f, stage, "bad preg alloc class", r, cls);
    637     if (pi && pi->alloc_kind != alloc_kind &&
    638         !(pi->alloc_kind == OPT_ALLOC_SPLIT && alloc_kind == OPT_ALLOC_SPLIT))
    639       opt_fail(f, stage, "alloc kind mirror mismatch", r, pi->alloc_kind);
    640     switch ((OptAllocKind)alloc_kind) {
    641       case OPT_ALLOC_NONE:
    642         if (loc && loc->kind != OPT_LOC_NONE)
    643           opt_fail(f, stage, "alloc location mismatch", r, loc->kind);
    644         break;
    645       case OPT_ALLOC_HARD:
    646         if (opt_preg_hard_reg(f, r) == (Reg)REG_NONE ||
    647             opt_preg_hard_reg(f, r) >= OPT_MAX_HARD_REGS)
    648           opt_fail(f, stage, "bad hard allocation", r, opt_preg_hard_reg(f, r));
    649         if (pi && (pi->cls != cls || pi->hard_reg != opt_preg_hard_reg(f, r)))
    650           opt_fail(f, stage, "hard alloc mirror mismatch", r, pi->hard_reg);
    651         if (loc && (loc->kind != OPT_LOC_HARD || loc->cls != cls))
    652           opt_fail(f, stage, "hard alloc location mismatch", r,
    653                    opt_preg_hard_reg(f, r));
    654         break;
    655       case OPT_ALLOC_SPILL:
    656         verify_frame_slot(f, stage, opt_preg_spill_slot(f, r),
    657                           "bad spill slot");
    658         if (f->frame_slots[opt_preg_spill_slot(f, r) - 1u].kind != FS_SPILL)
    659           opt_fail(f, stage, "spill slot is not FS_SPILL", r,
    660                    opt_preg_spill_slot(f, r));
    661         if (pi &&
    662             (pi->cls != cls || pi->spill_slot != opt_preg_spill_slot(f, r)))
    663           opt_fail(f, stage, "spill alloc mirror mismatch", r, pi->spill_slot);
    664         if (loc && (loc->kind != OPT_LOC_STACK || loc->cls != cls))
    665           opt_fail(f, stage, "spill alloc location mismatch", r,
    666                    opt_preg_spill_slot(f, r));
    667         break;
    668       case OPT_ALLOC_SPLIT:
    669         if (!f->opt_first_segment_by_preg)
    670           opt_fail(f, stage, "split allocation missing segments", r, 0);
    671         if (loc && loc->kind != OPT_LOC_NONE)
    672           opt_fail(f, stage, "split alloc location mismatch", r, loc->kind);
    673         break;
    674       default:
    675         opt_fail(f, stage, "bad allocation kind", r, alloc_kind);
    676         break;
    677     }
    678   }
    679   if (f->opt_first_segment_by_preg && f->opt_alloc_segments) {
    680     for (PReg r = 1; r < opt_reg_count(f); ++r) {
    681       for (u32 si = f->opt_first_segment_by_preg[r]; si != OPT_RANGE_NONE;
    682            si = f->opt_alloc_segments[si].next) {
    683         OptAllocSegment* s = &f->opt_alloc_segments[si];
    684         if (s->block >= f->nblocks)
    685           opt_fail(f, stage, "bad split block", r, si);
    686         if (s->start > s->end) opt_fail(f, stage, "bad split range", r, si);
    687         if (s->cls >= OPT_REG_CLASSES)
    688           opt_fail(f, stage, "bad split class", r, s->cls);
    689         if (s->loc_kind == OPT_LOC_HARD) {
    690           if (s->hard_reg == (Reg)REG_NONE || s->hard_reg >= OPT_MAX_HARD_REGS)
    691             opt_fail(f, stage, "bad split hard reg", r, s->hard_reg);
    692         } else if (s->loc_kind == OPT_LOC_STACK) {
    693           verify_frame_slot(f, stage, s->spill_slot, "bad split spill slot");
    694         } else if (s->loc_kind != OPT_LOC_NONE) {
    695           opt_fail(f, stage, "bad split loc kind", r, s->loc_kind);
    696         }
    697       }
    698     }
    699   }
    700 }
    701 
    702 static void verify_rewritten(Func* f, const char* stage) {
    703   if (!f->opt_rewritten) return;
    704   for (u32 b = 0; b < f->nblocks; ++b) {
    705     Block* bl = &f->blocks[b];
    706     for (u32 i = 0; i < bl->ninsts; ++i) {
    707       Inst* in = &bl->insts[i];
    708       if ((IROp)in->op == IR_PHI)
    709         opt_fail(f, stage, "phi survived rewrite", b, i);
    710       if ((IROp)in->op == IR_PARAM_DECL) {
    711         IRParamDeclAux* aux = (IRParamDeclAux*)in->extra.aux;
    712         if (in->nopnds || in->opnds)
    713           opt_fail(f, stage, "param_decl carries operands after rewrite", b, i);
    714         if ((!aux || aux->desc.storage.kind == CG_LOCAL_STORAGE_REG) &&
    715             (in->def == VAL_NONE || in->def >= opt_reg_count(f)))
    716           opt_fail(f, stage, "bad param_decl def after rewrite", b, i);
    717         continue;
    718       }
    719       for (u32 o = 0; o < in->nopnds; ++o)
    720         verify_operand_shape(f, stage, &in->opnds[o], 1);
    721       verify_aux_shapes(f, stage, in, 1);
    722     }
    723   }
    724 }
    725 
    726 static void verify_use_site(Func* f, const char* stage, const OptUse* use) {
    727   Inst* in = &f->blocks[use->block].insts[use->inst];
    728   if (in->id != use->inst_id)
    729     opt_fail(f, stage, "def-use stale inst id", use->inst_id, in->id);
    730   switch ((OptUseKind)use->kind) {
    731     case OPT_USE_OPERAND:
    732       if (!use->operand)
    733         opt_fail(f, stage, "def-use missing operand", use->block, use->inst);
    734       if (use->operand->kind != OPK_REG || (Val)use->operand->v.reg != use->val)
    735         opt_fail(f, stage, "def-use operand mismatch", use->val, use->kind);
    736       break;
    737     case OPT_USE_INDIRECT_BASE:
    738       if (!use->operand || use->operand->kind != OPK_INDIRECT ||
    739           (Val)use->operand->v.ind.base != use->val)
    740         opt_fail(f, stage, "def-use indirect mismatch", use->val, use->kind);
    741       break;
    742     case OPT_USE_INDIRECT_INDEX:
    743       if (!use->operand || use->operand->kind != OPK_INDIRECT ||
    744           use->operand->v.ind.index == (Reg)REG_NONE ||
    745           (Val)use->operand->v.ind.index != use->val)
    746         opt_fail(f, stage, "def-use indirect index mismatch", use->val,
    747                  use->kind);
    748       break;
    749     case OPT_USE_PHI_INPUT: {
    750       if ((IROp)in->op != IR_PHI)
    751         opt_fail(f, stage, "def-use phi site mismatch", use->block, use->inst);
    752       IRPhiAux* aux = (IRPhiAux*)in->extra.aux;
    753       if (!aux || use->phi_pred_index >= aux->npreds)
    754         opt_fail(f, stage, "def-use phi pred mismatch", use->val,
    755                  use->phi_pred_index);
    756       if (aux->pred_vals[use->phi_pred_index] != use->val)
    757         opt_fail(f, stage, "def-use phi value mismatch", use->val,
    758                  use->phi_pred_index);
    759       break;
    760     }
    761     default:
    762       opt_fail(f, stage, "def-use bad kind", use->kind, use->val);
    763   }
    764 }
    765 
    766 static void verify_def_use(Func* f, const char* stage) {
    767   if (f->opt_rewritten) return;
    768   if (opt_analysis_has(f, OPT_ANALYSIS_DEF_USE)) {
    769     for (u32 u = 0; u < f->opt_nuses; ++u) {
    770       OptUse* use = &f->opt_uses[u];
    771       if (use->val == VAL_NONE || use->val >= f->nvals)
    772         opt_fail(f, stage, "def-use bad cached val", use->val, f->nvals);
    773       if (use->block >= f->nblocks)
    774         opt_fail(f, stage, "def-use bad cached block", use->block, f->nblocks);
    775       if (use->inst >= f->blocks[use->block].ninsts)
    776         opt_fail(f, stage, "def-use bad cached inst", use->inst,
    777                  f->blocks[use->block].ninsts);
    778       verify_use_site(f, stage, use);
    779     }
    780   }
    781   opt_rebuild_def_use(f);
    782   for (u32 u = 0; u < f->opt_nuses; ++u) {
    783     OptUse* use = &f->opt_uses[u];
    784     if (use->val == VAL_NONE || use->val >= f->nvals)
    785       opt_fail(f, stage, "def-use bad use val", use->val, f->nvals);
    786     if (use->block >= f->nblocks)
    787       opt_fail(f, stage, "def-use bad block", use->block, f->nblocks);
    788     if (use->inst >= f->blocks[use->block].ninsts)
    789       opt_fail(f, stage, "def-use bad inst", use->inst,
    790                f->blocks[use->block].ninsts);
    791     verify_use_site(f, stage, use);
    792     if (f->val_def_block[use->val] >= f->nblocks)
    793       opt_fail(f, stage, "def-use bad def block", use->val,
    794                f->val_def_block[use->val]);
    795   }
    796   for (Val v = 1; v < f->nvals; ++v) {
    797     for (u32 u = f->opt_first_use_by_val[v]; u != OPT_USE_NONE;
    798          u = f->opt_uses[u].next_for_val) {
    799       if (u >= f->opt_nuses) opt_fail(f, stage, "def-use bad next", v, u);
    800       if (f->opt_uses[u].val != v)
    801         opt_fail(f, stage, "def-use wrong value list", v, u);
    802     }
    803   }
    804 }
    805 
    806 #endif /* !NDEBUG */
    807 
    808 void opt_verify(Func* f, const char* stage) {
    809 #ifdef NDEBUG
    810   (void)f;
    811   (void)stage;
    812   return;
    813 #else
    814   if (!f) return;
    815   if (f->nblocks && f->entry >= f->nblocks)
    816     opt_fail(f, stage, "entry out of range", f->entry, f->nblocks);
    817   OptAnalysis a;
    818   opt_analysis_build_order(f, &a);
    819   for (u32 b = 0; b < f->nblocks; ++b) {
    820     Block* bl = &f->blocks[b];
    821     if (bl->id != b) opt_fail(f, stage, "block id mismatch", bl->id, b);
    822     if (!a.reachable[b] && (bl->ninsts || bl->nsucc || bl->npreds))
    823       opt_fail(f, stage, "unreachable block still connected", b, bl->ninsts);
    824     if (bl->ninsts) {
    825       u32 expected = 0;
    826       if (fixed_terminator_succ_count(&bl->insts[bl->ninsts - 1], &expected) &&
    827           bl->nsucc != expected)
    828         opt_fail(f, stage, "terminator successor count mismatch", b, bl->nsucc);
    829     }
    830     for (u32 s = 0; s < bl->nsucc; ++s) {
    831       u32 succ = bl->succ[s];
    832       if (succ >= f->nblocks)
    833         opt_fail(f, stage, "successor out of range", b, s);
    834       if (!block_has_pred(&f->blocks[succ], b))
    835         opt_fail(f, stage, "successor missing reciprocal predecessor", b, succ);
    836     }
    837     for (u32 p = 0; p < bl->npreds; ++p) {
    838       u32 pred = bl->preds[p];
    839       if (pred >= f->nblocks)
    840         opt_fail(f, stage, "predecessor out of range", b, p);
    841       if (!block_has_succ(&f->blocks[pred], b))
    842         opt_fail(f, stage, "predecessor missing reciprocal successor", b, pred);
    843     }
    844   }
    845   u8* seen_emit = arena_zarray(f->arena, u8, f->nblocks ? f->nblocks : 1u);
    846   for (u32 i = 0; i < f->emit_order_n; ++i) {
    847     u32 b = f->emit_order[i];
    848     if (b >= f->nblocks) opt_fail(f, stage, "emit block out of range", b, i);
    849     if (seen_emit[b]) opt_fail(f, stage, "duplicate emit block", b, i);
    850     seen_emit[b] = 1;
    851   }
    852   verify_function_storage(f, stage);
    853   verify_allocations(f, stage);
    854   verify_values(f, stage);
    855   verify_rewritten(f, stage);
    856   verify_def_use(f, stage);
    857 #endif
    858 }