pass_mir.c (23736B)
1 #include "opt/opt_internal.h" 2 3 int opt_mir_view(Func* f, Func* out) { 4 if (!f || !f->mir) return 0; 5 *out = *f; 6 out->blocks = f->mir->blocks; 7 out->nblocks = f->mir->nblocks; 8 out->blocks_cap = f->mir->blocks_cap; 9 out->entry = f->mir->entry; 10 out->emit_order = f->mir->emit_order; 11 out->emit_order_n = f->mir->emit_order_n; 12 out->emit_order_cap = f->mir->emit_order_cap; 13 out->opt_rewritten = 1; 14 /* HIR def-use records contain direct pointers into HIR operands. MIR passes 15 * must rebuild any analysis they need over this physical graph. */ 16 out->opt_uses = NULL; 17 out->opt_nuses = 0; 18 out->opt_uses_cap = 0; 19 out->opt_first_use_by_val = NULL; 20 out->opt_first_use_by_val_cap = 0; 21 out->opt_valid_analyses = 0; 22 /* Scope lookup is a recording/semantic cache of direct Inst pointers into 23 * HIR. Structured scopes have already been lowered before MIR exists, and a 24 * physical pass must never inherit pointers back into the semantic graph. */ 25 out->scope_aux_inst = NULL; 26 out->nscopes = 0; 27 out->scopes_cap = 0; 28 out->mir = NULL; 29 return 1; 30 } 31 32 void opt_mir_commit(Func* f, const Func* view) { 33 if (!f || !f->mir || !view) return; 34 f->mir->blocks = view->blocks; 35 f->mir->nblocks = view->nblocks; 36 f->mir->blocks_cap = view->blocks_cap; 37 f->mir->entry = view->entry; 38 f->mir->emit_order = view->emit_order; 39 f->mir->emit_order_n = view->emit_order_n; 40 f->mir->emit_order_cap = view->emit_order_cap; 41 /* Instruction ids are function-wide side-table keys, but a physical pass 42 * allocates them through its independently mutable Func view. Commit that 43 * namespace with the graph so later MIR analyses can size their tables for 44 * every instruction the pass inserted. */ 45 f->next_inst_id = view->next_inst_id; 46 } 47 48 #ifndef NDEBUG 49 50 typedef struct MirVerifyCtx { 51 const char* stage; 52 /* opt_walk_operand presents an indirect owner immediately followed by 53 * transient scalar views of its base and (when present) index. Track that 54 * sequence so a stored OPT_OPERAND_WALK_INDIRECT_PART flag cannot masquerade 55 * as a legitimate walker annotation. */ 56 const Operand* indirect; 57 u8 indirect_part; /* 1 = base, 2 = index */ 58 } MirVerifyCtx; 59 60 static void mir_fail(Func* f, const Inst* in, const char* stage, 61 const char* msg, u32 a, u32 b) { 62 compiler_panic(f->c, in ? in->loc : (SrcLoc){0, 0, 0}, 63 "opt MIR verify %s: %s [op %u, inst %u] (%u, %u)", 64 stage ? stage : "?", msg, in ? (unsigned)in->op : 0u, 65 in ? (unsigned)in->id : 0u, (unsigned)a, (unsigned)b); 66 } 67 68 static int mir_pow2(u32 n) { return n && !(n & (n - 1u)); } 69 70 static int mir_type_known(Func* f, KitCgTypeId type) { 71 return type != KIT_CG_TYPE_NONE && cg_type_get(f->c, type) != NULL; 72 } 73 74 static int mir_type_valid(Func* f, KitCgTypeId type) { 75 return mir_type_known(f, type) && 76 kit_cg_type_is_sized((KitCompiler*)f->c, type) && 77 cg_type_size(f->c, type) != 0 && cg_type_align(f->c, type) != 0; 78 } 79 80 static int mir_type_scalar(Func* f, KitCgTypeId type) { 81 const CgType* ty; 82 if (!mir_type_valid(f, type)) return 0; 83 ty = cg_type_get(f->c, type); 84 switch (ty->kind) { 85 case KIT_CG_TYPE_BOOL: 86 case KIT_CG_TYPE_INT: 87 case KIT_CG_TYPE_FLOAT: 88 case KIT_CG_TYPE_PTR: 89 case KIT_CG_TYPE_ENUM: 90 case KIT_CG_TYPE_VARARG_STATE: 91 return 1; 92 default: 93 return 0; 94 } 95 } 96 97 static int mir_type_address_component(Func* f, KitCgTypeId type) { 98 return mir_type_scalar(f, type) && 99 opt_value_reg_class(f->c, type) == RC_INT && 100 cg_type_size(f->c, type) == f->c->target.ptr_size; 101 } 102 103 static int mir_reg_known(Func* f, Reg r, u8 cls) { 104 if (cls >= OPT_REG_CLASSES || r == (Reg)REG_NONE || 105 r >= OPT_MAX_HARD_REGS) 106 return 0; 107 for (u32 i = 0; i < f->opt_phys_reg_count[cls]; ++i) { 108 const CGPhysRegInfo* phys = &f->opt_phys_regs[cls][i]; 109 if (phys->reg == r && phys->cls == cls) return 1; 110 } 111 return 0; 112 } 113 114 static u32 mir_known_reg_mask(Func* f, u8 cls) { 115 u32 mask = 0; 116 if (!f || cls >= OPT_REG_CLASSES) return 0; 117 for (u32 i = 0; i < f->opt_phys_reg_count[cls]; ++i) { 118 Reg r = f->opt_phys_regs[cls][i].reg; 119 if (r < OPT_MAX_HARD_REGS) mask |= 1u << r; 120 } 121 return mask; 122 } 123 124 static int mir_reg_is_emit_temp(Func* f, Reg r, u8 cls) { 125 if (cls >= OPT_REG_CLASSES) return 0; 126 for (u32 i = 0; i < f->emit_temp_reg_count[cls]; ++i) 127 if (f->emit_temp_regs[cls][i] == r) return 1; 128 return 0; 129 } 130 131 static int mir_reg_is_asm_temp(Func* f, Reg r, u8 cls) { 132 return cls < OPT_REG_CLASSES && r < OPT_MAX_HARD_REGS && 133 (f->asm_temp_mask[cls] & (1u << r)) != 0; 134 } 135 136 static void mir_verify_reg(Func* f, const Inst* in, const char* stage, Reg r, 137 u8 cls, const char* what) { 138 if (!mir_reg_known(f, r, cls)) 139 mir_fail(f, in, stage, what, cls, (u32)r); 140 if (mir_reg_is_emit_temp(f, r, cls)) 141 mir_fail(f, in, stage, "emitter-owned temp escaped into MIR", cls, 142 (u32)r); 143 if (mir_reg_is_asm_temp(f, r, cls)) 144 mir_fail(f, in, stage, "asm-internal temp escaped into MIR", cls, 145 (u32)r); 146 } 147 148 static IRFrameSlot* mir_frame_slot(Func* f, const Inst* in, const char* stage, 149 FrameSlot id, const char* what) { 150 if (id == FRAME_SLOT_NONE || id > f->nframe_slots) 151 mir_fail(f, in, stage, what, id, f->nframe_slots); 152 return &f->frame_slots[id - 1u]; 153 } 154 155 static void mir_verify_slot_contains(Func* f, const Inst* in, 156 const char* stage, 157 const IRFrameSlot* slot, 158 KitCgTypeId type, const char* what) { 159 u64 size; 160 if (!mir_type_valid(f, type)) 161 mir_fail(f, in, stage, what, type, slot ? slot->id : 0u); 162 size = cg_type_size(f->c, type); 163 if (!slot || size > slot->size) 164 mir_fail(f, in, stage, what, slot ? slot->id : 0u, type); 165 } 166 167 static void mir_verify_slot_fits(Func* f, const Inst* in, const char* stage, 168 const IRFrameSlot* slot, KitCgTypeId type, 169 const char* what) { 170 mir_verify_slot_contains(f, in, stage, slot, type, what); 171 if (cg_type_align(f->c, type) > slot->align) 172 mir_fail(f, in, stage, what, slot->id, type); 173 } 174 175 static void mir_verify_frame_table(Func* f, const char* stage) { 176 const u16 allowed_flags = 177 (u16)(FSF_ADDR_TAKEN | FSF_MEMORY_REQUIRED | FSF_VOLATILE); 178 for (u32 i = 0; i < f->nframe_slots; ++i) { 179 IRFrameSlot* slot = &f->frame_slots[i]; 180 if (slot->id != i + 1u) 181 mir_fail(f, NULL, stage, "non-canonical frame slot id", slot->id, 182 i + 1u); 183 if (slot->kind != FS_LOCAL && slot->kind != FS_PARAM && 184 slot->kind != FS_SPILL) 185 mir_fail(f, NULL, stage, "invalid optimizer frame slot kind", slot->id, 186 slot->kind); 187 if (!mir_type_valid(f, slot->type)) 188 mir_fail(f, NULL, stage, "invalid frame slot type", slot->id, 189 slot->type); 190 if (!slot->size || !mir_pow2(slot->align)) 191 mir_fail(f, NULL, stage, "invalid frame slot size/alignment", slot->size, 192 slot->align); 193 if (cg_type_size(f->c, slot->type) > slot->size || 194 cg_type_align(f->c, slot->type) > slot->align) 195 mir_fail(f, NULL, stage, "frame slot does not fit descriptor type", 196 slot->id, slot->type); 197 if (slot->flags & ~allowed_flags) 198 mir_fail(f, NULL, stage, "invalid frame slot flags", slot->id, 199 slot->flags); 200 if (slot->kind == FS_SPILL) { 201 if (slot->flags) 202 mir_fail(f, NULL, stage, "spill slot carries semantic flags", slot->id, 203 slot->flags); 204 } else if (slot->priority) { 205 mir_fail(f, NULL, stage, "semantic frame slot carries spill priority", 206 slot->id, slot->priority); 207 } 208 } 209 } 210 211 static void mir_verify_asm_requirement(Func* f, const Inst* in, 212 const char* stage, 213 const IRAsmRegRequirement* req, 214 const Operand* op) { 215 u32 known; 216 if (!req->present) { 217 if (req->allowed_mask || req->fixed_reg != -1 || req->cls) 218 mir_fail(f, in, stage, "non-canonical absent asm requirement", 219 req->allowed_mask, (u32)req->fixed_reg); 220 return; 221 } 222 if (req->cls >= OPT_REG_CLASSES || !op || !mir_type_scalar(f, op->type) || 223 opt_value_reg_class(f->c, op->type) != req->cls) 224 mir_fail(f, in, stage, "invalid asm requirement class/type", req->cls, 225 op ? op->type : 0u); 226 known = mir_known_reg_mask(f, req->cls); 227 if (req->allowed_mask & ~known) 228 mir_fail(f, in, stage, "asm allowed mask names unknown register", 229 req->cls, req->allowed_mask & ~known); 230 if (req->fixed_reg < -1 || req->fixed_reg >= (i32)OPT_MAX_HARD_REGS || 231 (req->fixed_reg >= 0 && 232 !(known & (1u << (u32)req->fixed_reg)))) 233 mir_fail(f, in, stage, "asm fixed requirement names unknown register", 234 req->cls, (u32)req->fixed_reg); 235 if (req->fixed_reg >= 0 && req->allowed_mask && 236 !(req->allowed_mask & (1u << (u32)req->fixed_reg))) 237 mir_fail(f, in, stage, "asm fixed register violates allowed mask", 238 req->cls, (u32)req->fixed_reg); 239 } 240 241 static void mir_verify_asm_aux(Func* f, const Inst* in, const char* stage) { 242 const IRAsmAux* aux = (const IRAsmAux*)in->extra.aux; 243 if (!aux) 244 mir_fail(f, in, stage, "asm instruction has no descriptor", 0, 0); 245 if ((aux->nout != 0u) != (aux->outs && aux->out_ops && aux->out_reg_reqs) || 246 (aux->nin != 0u) != (aux->ins && aux->in_ops && aux->in_reg_reqs) || 247 (aux->nclob != 0u) != (aux->clobbers != NULL) || 248 aux->has_memory_constraint > 1u) 249 mir_fail(f, in, stage, "inconsistent asm descriptor arrays", aux->nout, 250 aux->nin); 251 for (u32 cls = 0; cls < OPT_REG_CLASSES; ++cls) 252 if (aux->clobber_mask[cls] & ~mir_known_reg_mask(f, (u8)cls)) 253 mir_fail(f, in, stage, "asm clobber mask names unknown register", cls, 254 aux->clobber_mask[cls]); 255 for (u32 i = 0; i < aux->nout; ++i) 256 mir_verify_asm_requirement(f, in, stage, &aux->out_reg_reqs[i], 257 &aux->out_ops[i]); 258 for (u32 i = 0; i < aux->nin; ++i) 259 mir_verify_asm_requirement(f, in, stage, &aux->in_reg_reqs[i], 260 &aux->in_ops[i]); 261 } 262 263 static void mir_verify_scalar_location(Func* f, Inst* in, Operand* op, 264 int is_def, MirVerifyCtx* ctx) { 265 IRFrameSlot* slot; 266 if (op->flags) 267 mir_fail(f, in, ctx->stage, "stored operand has transient flags", op->kind, 268 op->flags); 269 if (op->shift) { 270 if (op->kind != OPK_REG || is_def || op->cls != RC_INT || 271 op->shift > 4u || (IROp)in->op != IR_BINOP || in->nopnds != 3u || 272 op != &in->opnds[2]) 273 mir_fail(f, in, ctx->stage, "invalid shifted-register rider", op->kind, 274 op->shift); 275 } 276 switch ((OptOperandKind)op->kind) { 277 case OPK_IMM: 278 /* A zero operand is the canonical absent ABI value (notably a void call 279 * result). Every present immediate must still carry a real scalar type. */ 280 if (op->type == KIT_CG_TYPE_NONE) { 281 if (op->cls || op->v.imm) 282 mir_fail(f, in, ctx->stage, "malformed absent immediate", op->cls, 283 (u32)op->v.imm); 284 } else if (!mir_type_scalar(f, op->type) || op->cls != RC_INT) { 285 mir_fail(f, in, ctx->stage, "invalid immediate type/class", op->type, 286 op->cls); 287 } 288 return; 289 case OPK_GLOBAL: 290 /* A symbol-address recipe may retain an incomplete array or function 291 * referent type. Native emission needs the symbol identity and address 292 * class, not sized storage; size/alignment checks belong to operations 293 * that actually access the referent. */ 294 if (!mir_type_known(f, op->type) || op->cls != RC_INT) 295 mir_fail(f, in, ctx->stage, "invalid global type/class", op->type, 296 op->cls); 297 return; 298 case OPK_LOCAL: 299 if (op->cls != RC_INT) 300 mir_fail(f, in, ctx->stage, "frame local has non-address class", 301 op->cls, op->v.frame_slot); 302 slot = mir_frame_slot(f, in, ctx->stage, op->v.frame_slot, 303 "invalid local frame slot"); 304 if (slot->kind != FS_LOCAL && slot->kind != FS_PARAM) 305 mir_fail(f, in, ctx->stage, "local operand names allocator spill", 306 op->v.frame_slot, slot->kind); 307 /* A semantic local may be a typed subobject view into packed storage. 308 * Its access alignment lives in MemAccess and may be lower than the 309 * viewed type's natural alignment; only containment is required here. 310 * Allocator spills below retain the stronger alignment invariant. */ 311 mir_verify_slot_contains(f, in, ctx->stage, slot, op->type, 312 "local operand type does not fit frame slot"); 313 return; 314 case OPK_STACK: 315 if (!mir_type_scalar(f, op->type) || op->cls >= OPT_REG_CLASSES || 316 opt_value_reg_class(f->c, op->type) != op->cls) 317 mir_fail(f, in, ctx->stage, "invalid spill value type/class", op->type, 318 op->cls); 319 slot = mir_frame_slot(f, in, ctx->stage, op->v.frame_slot, 320 "invalid spill frame slot"); 321 if (slot->kind != FS_SPILL) 322 mir_fail(f, in, ctx->stage, "spill value names semantic frame slot", 323 op->v.frame_slot, slot->kind); 324 mir_verify_slot_fits(f, in, ctx->stage, slot, op->type, 325 "spill value type does not fit frame slot"); 326 return; 327 case OPK_FRAME_ADDR: 328 if (is_def || op->cls != RC_INT || !cg_type_is_ptr(f->c, op->type) || 329 !mir_type_address_component(f, op->type)) 330 mir_fail(f, in, ctx->stage, "invalid frame-address recipe", op->type, 331 op->cls); 332 slot = mir_frame_slot(f, in, ctx->stage, op->v.frame_slot, 333 "invalid frame-address slot"); 334 if (slot->kind != FS_LOCAL && slot->kind != FS_PARAM) 335 mir_fail(f, in, ctx->stage, "frame-address recipe names spill slot", 336 op->v.frame_slot, slot->kind); 337 return; 338 case OPK_REG: 339 if (!mir_type_scalar(f, op->type) || op->cls >= OPT_REG_CLASSES || 340 opt_value_reg_class(f->c, op->type) != op->cls) 341 mir_fail(f, in, ctx->stage, "invalid register value type/class", 342 op->type, op->cls); 343 mir_verify_reg(f, in, ctx->stage, op->v.reg, op->cls, 344 "unknown physical register operand"); 345 return; 346 case OPK_INDIRECT: 347 mir_fail(f, in, ctx->stage, "nested indirect operand", op->kind, 0); 348 return; 349 default: 350 mir_fail(f, in, ctx->stage, "unknown operand kind", op->kind, 0); 351 return; 352 } 353 } 354 355 static void mir_verify_indirect_component(Func* f, Inst* in, Operand* part, 356 int is_def, MirVerifyCtx* ctx) { 357 const Operand* owner = ctx->indirect; 358 u32 value; 359 u8 kind; 360 KitCgTypeId type; 361 u8 expect_kind; 362 if (!owner || (ctx->indirect_part != 1u && ctx->indirect_part != 2u)) 363 mir_fail(f, in, ctx->stage, "unexpected indirect component", part->kind, 364 part->flags); 365 if (part->flags != OPT_OPERAND_WALK_INDIRECT_PART || is_def || part->shift || 366 part->cls != RC_INT) 367 mir_fail(f, in, ctx->stage, "malformed indirect component view", 368 part->flags, part->kind); 369 if (ctx->indirect_part == 1u) { 370 value = owner->v.ind.base; 371 kind = owner->v.ind.base_kind; 372 type = owner->v.ind.base_type; 373 } else { 374 value = owner->v.ind.index; 375 kind = owner->v.ind.index_kind; 376 type = owner->v.ind.index_type; 377 } 378 expect_kind = kind == OPT_INDIRECT_REG 379 ? OPK_REG 380 : (kind == OPT_INDIRECT_FRAME ? OPK_STACK 381 : OPK_FRAME_ADDR); 382 if (part->kind != expect_kind || part->type != type || 383 (part->kind == OPK_REG ? (u32)part->v.reg 384 : (u32)part->v.frame_slot) != value) 385 mir_fail(f, in, ctx->stage, "indirect component view disagrees with owner", 386 ctx->indirect_part, part->kind); 387 388 if (ctx->indirect_part == 1u && 389 !(owner->v.ind.index_kind == OPT_INDIRECT_REG && 390 owner->v.ind.index == (Reg)REG_NONE)) { 391 ctx->indirect_part = 2u; 392 } else { 393 ctx->indirect = NULL; 394 ctx->indirect_part = 0; 395 } 396 } 397 398 static void mir_verify_indirect(Func* f, Inst* in, Operand* op, 399 MirVerifyCtx* ctx) { 400 IRFrameSlot* slot; 401 int has_index; 402 int address_only = (IROp)in->op == IR_ADDR_OF && in->nopnds >= 2u && 403 op == &in->opnds[1]; 404 if (op->flags || op->shift || op->cls != RC_INT) 405 mir_fail(f, in, ctx->stage, "invalid indirect owner shape", op->flags, 406 op->shift); 407 /* IR_ADDR_OF computes the identity of its lvalue and may therefore retain an 408 * incomplete flexible-array referent. Instructions that dereference the 409 * recipe still require sized storage. */ 410 if (!(address_only ? mir_type_known(f, op->type) 411 : mir_type_valid(f, op->type))) 412 mir_fail(f, in, ctx->stage, "invalid indirect owner type", op->type, 413 (u32)address_only); 414 if (op->v.ind.base_kind > OPT_INDIRECT_FRAME_ADDR) 415 mir_fail(f, in, ctx->stage, "invalid indirect base location kind", 416 op->v.ind.base_kind, op->v.ind.base); 417 if (!mir_type_address_component(f, op->v.ind.base_type)) 418 mir_fail(f, in, ctx->stage, "invalid indirect base type", 419 op->v.ind.base_type, op->v.ind.base_kind); 420 switch ((OptIndirectLocKind)op->v.ind.base_kind) { 421 case OPT_INDIRECT_REG: 422 mir_verify_reg(f, in, ctx->stage, op->v.ind.base, RC_INT, 423 "unknown indirect base register"); 424 break; 425 case OPT_INDIRECT_FRAME: 426 slot = mir_frame_slot(f, in, ctx->stage, (FrameSlot)op->v.ind.base, 427 "invalid indirect base spill slot"); 428 if (slot->kind != FS_SPILL) 429 mir_fail(f, in, ctx->stage, "indirect base value names semantic slot", 430 op->v.ind.base, slot->kind); 431 mir_verify_slot_fits(f, in, ctx->stage, slot, op->v.ind.base_type, 432 "indirect base type does not fit spill slot"); 433 break; 434 case OPT_INDIRECT_FRAME_ADDR: 435 slot = mir_frame_slot(f, in, ctx->stage, (FrameSlot)op->v.ind.base, 436 "invalid indirect frame-address base slot"); 437 if (slot->kind != FS_LOCAL && slot->kind != FS_PARAM) 438 mir_fail(f, in, ctx->stage, 439 "indirect frame-address base names spill slot", 440 op->v.ind.base, slot->kind); 441 break; 442 } 443 444 if (op->v.ind.index_kind > OPT_INDIRECT_FRAME_ADDR) 445 mir_fail(f, in, ctx->stage, "invalid indirect index location kind", 446 op->v.ind.index_kind, op->v.ind.index); 447 has_index = !(op->v.ind.index_kind == OPT_INDIRECT_REG && 448 op->v.ind.index == (Reg)REG_NONE); 449 if (!has_index) { 450 if (op->v.ind.index_type != KIT_CG_TYPE_NONE || op->v.ind.log2_scale || 451 op->v.ind.index_ext != OPT_IDX_EXT_NONE) 452 mir_fail(f, in, ctx->stage, "non-canonical absent indirect index", 453 op->v.ind.index_type, op->v.ind.log2_scale); 454 } else { 455 if (!opt_indirect_index_type_valid(f, op->v.ind.index_type)) 456 mir_fail(f, in, ctx->stage, "invalid indirect index type", 457 op->v.ind.index_type, op->v.ind.index_kind); 458 switch ((OptIndirectLocKind)op->v.ind.index_kind) { 459 case OPT_INDIRECT_REG: 460 mir_verify_reg(f, in, ctx->stage, op->v.ind.index, RC_INT, 461 "unknown indirect index register"); 462 break; 463 case OPT_INDIRECT_FRAME: 464 slot = mir_frame_slot(f, in, ctx->stage, (FrameSlot)op->v.ind.index, 465 "invalid indirect index spill slot"); 466 if (slot->kind != FS_SPILL) 467 mir_fail(f, in, ctx->stage, 468 "indirect index value names semantic slot", 469 op->v.ind.index, slot->kind); 470 mir_verify_slot_fits(f, in, ctx->stage, slot, op->v.ind.index_type, 471 "indirect index type does not fit spill slot"); 472 break; 473 case OPT_INDIRECT_FRAME_ADDR: 474 mir_fail(f, in, ctx->stage, 475 "frame address cannot be an indirect index", 476 op->v.ind.index, op->v.ind.index_type); 477 break; 478 } 479 } 480 if (op->v.ind.log2_scale > 3u) 481 mir_fail(f, in, ctx->stage, "invalid indirect scale", 482 op->v.ind.log2_scale, op->v.ind.index); 483 if (op->v.ind.index_ext > OPT_IDX_EXT_UXTW || 484 (op->v.ind.index_ext != OPT_IDX_EXT_NONE && 485 (!has_index || op->v.ind.index_kind == OPT_INDIRECT_FRAME_ADDR || 486 cg_type_size(f->c, op->v.ind.index_type) != 4u))) 487 mir_fail(f, in, ctx->stage, "invalid indirect index extension", 488 op->v.ind.index_ext, op->v.ind.index_type); 489 490 ctx->indirect = op; 491 ctx->indirect_part = 1u; 492 } 493 494 static void mir_verify_operand(Func* f, Inst* in, Operand* op, int is_def, 495 void* arg) { 496 MirVerifyCtx* ctx = (MirVerifyCtx*)arg; 497 if (!op) return; 498 if (ctx->indirect) { 499 mir_verify_indirect_component(f, in, op, is_def, ctx); 500 return; 501 } 502 if (op->flags) 503 mir_fail(f, in, ctx->stage, "stored operand has transient flags", op->kind, 504 op->flags); 505 if (op->kind == OPK_INDIRECT) { 506 mir_verify_indirect(f, in, op, ctx); 507 return; 508 } 509 mir_verify_scalar_location(f, in, op, is_def, ctx); 510 } 511 512 #endif /* !NDEBUG */ 513 514 void opt_mir_verify(Func* f, const char* stage) { 515 #ifdef NDEBUG 516 (void)f; 517 (void)stage; 518 return; 519 #else 520 Func v; 521 if (!opt_mir_view(f, &v)) return; 522 mir_verify_frame_table(&v, stage); 523 for (u32 b = 0; b < v.nblocks; ++b) { 524 Block* bl = &v.blocks[b]; 525 if (bl->id != b) 526 mir_fail(&v, NULL, stage, "non-canonical MIR block id", bl->id, b); 527 for (u32 i = 0; i < bl->ninsts; ++i) { 528 Inst* in = &bl->insts[i]; 529 MirVerifyCtx ctx; 530 memset(&ctx, 0, sizeof ctx); 531 ctx.stage = stage; 532 if ((IROp)in->op == IR_PHI) { 533 mir_fail(&v, in, stage, "phi survived lowering", b, i); 534 } 535 if ((IROp)in->op > IR_INTRINSIC) 536 mir_fail(&v, in, stage, "invalid MIR opcode", in->op, in->id); 537 if ((in->nopnds != 0u) != (in->opnds != NULL)) 538 mir_fail(&v, in, stage, "inconsistent MIR operand array", in->nopnds, 539 in->opnds != NULL); 540 if (in->def != VAL_NONE || in->ndefs != 0u || in->defs != NULL) 541 mir_fail(&v, in, stage, "stale semantic definition metadata", in->def, 542 in->ndefs); 543 if ((IROp)in->op == IR_PARAM_DECL) { 544 if (in->nopnds) 545 mir_fail(&v, in, stage, "MIR parameter marker carries operands", b, 546 i); 547 continue; 548 } 549 if ((IROp)in->op == IR_ASM_BLOCK) mir_verify_asm_aux(&v, in, stage); 550 opt_walk_inst_operands(&v, in, mir_verify_operand, &ctx); 551 if (ctx.indirect) 552 mir_fail(&v, in, stage, "incomplete indirect component walk", 553 ctx.indirect_part, in->id); 554 } 555 } 556 #endif 557 } 558 559 void opt_mir_combine(Func* f, NativeTarget* target) { 560 Func v; 561 if (!opt_mir_view(f, &v)) return; 562 opt_combine(&v, target); 563 opt_mir_commit(f, &v); 564 } 565 566 void opt_mir_dce(Func* f) { 567 Func v; 568 if (!opt_mir_view(f, &v)) return; 569 opt_dce(&v); 570 opt_mir_commit(f, &v); 571 } 572 573 void opt_mir_build_cfg(Func* f) { 574 Func v; 575 if (!opt_mir_view(f, &v)) return; 576 opt_build_cfg(&v); 577 opt_mir_commit(f, &v); 578 } 579 580 void opt_mir_jump_cleanup(Func* f, OptJumpCleanupStage stage) { 581 Func v; 582 if (!opt_mir_view(f, &v)) return; 583 opt_jump_cleanup(&v, stage); 584 opt_mir_commit(f, &v); 585 }