diff --git a/src/amd/compiler/aco_interface.cpp b/src/amd/compiler/aco_interface.cpp index 8af190fbb6f..a08f6560578 100644 --- a/src/amd/compiler/aco_interface.cpp +++ b/src/amd/compiler/aco_interface.cpp @@ -447,7 +447,7 @@ aco_get_codegen_flags() init(); /* Exclude flags which don't affect code generation. */ uint64_t exclude = DEBUG_VALIDATE_IR | DEBUG_VALIDATE_RA | DEBUG_PERF_INFO | DEBUG_LIVE_INFO | - DEBUG_NO_VALIDATE | DEBUG_VALIDATE_LIVE_VARS; + DEBUG_NO_VALIDATE | DEBUG_VALIDATE_LIVE_VARS | DEBUG_VALIDATE_OPT; return debug_flags & ~exclude; } diff --git a/src/amd/compiler/aco_ir.cpp b/src/amd/compiler/aco_ir.cpp index e4c8b7c1e76..ba5dc303e34 100644 --- a/src/amd/compiler/aco_ir.cpp +++ b/src/amd/compiler/aco_ir.cpp @@ -22,6 +22,7 @@ static const struct debug_control aco_debug_options[] = { {"validateir", DEBUG_VALIDATE_IR}, {"validatera", DEBUG_VALIDATE_RA}, {"validate-livevars", DEBUG_VALIDATE_LIVE_VARS}, + {"validateopt", DEBUG_VALIDATE_OPT}, {"novalidate", DEBUG_NO_VALIDATE}, {"force-waitcnt", DEBUG_FORCE_WAITCNT}, {"force-waitdeps", DEBUG_FORCE_WAITDEPS}, @@ -44,7 +45,7 @@ init_once() #ifndef NDEBUG /* enable some flags by default on debug builds */ if (!(debug_flags & aco::DEBUG_NO_VALIDATE)) { - debug_flags |= aco::DEBUG_VALIDATE_IR; + debug_flags |= aco::DEBUG_VALIDATE_IR | DEBUG_VALIDATE_OPT; } #endif } diff --git a/src/amd/compiler/aco_ir.h b/src/amd/compiler/aco_ir.h index f9be67a5ab0..dcd76f76845 100644 --- a/src/amd/compiler/aco_ir.h +++ b/src/amd/compiler/aco_ir.h @@ -43,6 +43,7 @@ enum { DEBUG_NO_VALIDATE = 0x400, DEBUG_NO_SCHED_ILP = 0x800, DEBUG_NO_SCHED_VOPD = 0x1000, + DEBUG_VALIDATE_OPT = 0x2000, }; enum storage_class : uint8_t { diff --git a/src/amd/compiler/aco_optimizer.cpp b/src/amd/compiler/aco_optimizer.cpp index 9c8d95df8ae..e6fbba97415 100644 --- a/src/amd/compiler/aco_optimizer.cpp +++ b/src/amd/compiler/aco_optimizer.cpp @@ -5060,6 +5060,51 @@ apply_literals(opt_ctx& ctx, aco_ptr& instr) ctx.instructions.emplace_back(std::move(instr)); } +void +validate_opt_ctx(opt_ctx& ctx) +{ + if (!(debug_flags & DEBUG_VALIDATE_OPT)) + return; + + Program* program = ctx.program; + + bool is_valid = true; + auto check = [&program, &is_valid](bool success, const char* msg, + aco::Instruction* instr) -> void + { + if (!success) { + char* out; + size_t outsize; + struct u_memstream mem; + u_memstream_open(&mem, &out, &outsize); + FILE* const memf = u_memstream_get(&mem); + + fprintf(memf, "Optimizer: %s: ", msg); + aco_print_instr(program->gfx_level, instr, memf); + u_memstream_close(&mem); + + aco_err(program, "%s", out); + free(out); + + is_valid = false; + } + }; + + for (Block& block : program->blocks) { + for (aco_ptr& instr : block.instructions) { + if (!instr) + continue; + for (const Definition& def : instr->definitions) { + check(ctx.info[def.tempId()].parent_instr == instr.get(), "parent_instr incorrect", + instr.get()); + } + } + } + if (!is_valid) { + abort(); + } +} + } /* end namespace */ void @@ -5076,11 +5121,15 @@ optimize(Program* program) label_instruction(ctx, instr); } + validate_opt_ctx(ctx); + ctx.uses = dead_code_analysis(program); /* 2. Rematerialize constants in every block. */ rematerialize_constants(ctx); + validate_opt_ctx(ctx); + /* 3. Combine v_mad, omod, clamp and propagate sgpr on VALU instructions */ for (Block& block : program->blocks) { ctx.fp_mode = block.fp_mode; @@ -5088,6 +5137,8 @@ optimize(Program* program) combine_instruction(ctx, instr); } + validate_opt_ctx(ctx); + /* 4. Top-Down DAG pass (backward) to select instructions (includes DCE) */ for (auto block_rit = program->blocks.rbegin(); block_rit != program->blocks.rend(); ++block_rit) { @@ -5098,6 +5149,8 @@ optimize(Program* program) select_instruction(ctx, *instr_rit); } + validate_opt_ctx(ctx); + /* 5. Add literals to instructions */ for (Block& block : program->blocks) { ctx.instructions.reserve(block.instructions.size()); @@ -5106,6 +5159,8 @@ optimize(Program* program) apply_literals(ctx, instr); block.instructions = std::move(ctx.instructions); } + + validate_opt_ctx(ctx); } } // namespace aco