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 }