aco: implement aco::validate_live_vars()
This is intended for passes which manually update live variables and RegisterDemand, like e.g. the scheduler, and can be enabled with ACO_DEBUG=validate-livevars. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30182>
This commit is contained in:
committed by
Marge Bot
parent
c1a3330ac7
commit
b0c8c5e42e
@@ -21,6 +21,7 @@ uint64_t debug_flags = 0;
|
||||
static const struct debug_control aco_debug_options[] = {
|
||||
{"validateir", DEBUG_VALIDATE_IR},
|
||||
{"validatera", DEBUG_VALIDATE_RA},
|
||||
{"validate-livevars", DEBUG_VALIDATE_LIVE_VARS},
|
||||
{"novalidateir", DEBUG_NO_VALIDATE_IR},
|
||||
{"force-waitcnt", DEBUG_FORCE_WAITCNT},
|
||||
{"force-waitdeps", DEBUG_FORCE_WAITDEPS},
|
||||
|
||||
@@ -31,6 +31,7 @@ extern uint64_t debug_flags;
|
||||
enum {
|
||||
DEBUG_VALIDATE_IR = 0x1,
|
||||
DEBUG_VALIDATE_RA = 0x2,
|
||||
DEBUG_VALIDATE_LIVE_VARS = 0x4,
|
||||
DEBUG_FORCE_WAITCNT = 0x8,
|
||||
DEBUG_NO_VN = 0x10,
|
||||
DEBUG_NO_OPT = 0x20,
|
||||
@@ -2188,6 +2189,7 @@ bool print_asm(Program* program, std::vector<uint32_t>& binary, unsigned exec_si
|
||||
bool validate_ir(Program* program);
|
||||
bool validate_cfg(Program* program);
|
||||
bool validate_ra(Program* program);
|
||||
bool validate_live_vars(Program* program);
|
||||
|
||||
void collect_presched_stats(Program* program);
|
||||
void collect_preasm_stats(Program* program);
|
||||
|
||||
@@ -528,6 +528,23 @@ struct IDSet {
|
||||
explicit IDSet(monotonic_buffer_resource& m) : words(m) {}
|
||||
explicit IDSet(const IDSet& other, monotonic_buffer_resource& m) : words(other.words, m) {}
|
||||
|
||||
bool operator==(const IDSet& other) const
|
||||
{
|
||||
auto it = words.begin();
|
||||
for (auto block : other.words) {
|
||||
if (block.second == block_t{0})
|
||||
continue;
|
||||
while (it != words.end() && it->second == block_t{0})
|
||||
it++;
|
||||
if (it == words.end() || block != *it)
|
||||
return false;
|
||||
it++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const IDSet& other) const { return !(*this == other); }
|
||||
|
||||
private:
|
||||
static uint32_t get_first_set(const block_t& words)
|
||||
{
|
||||
|
||||
@@ -942,6 +942,116 @@ validate_cfg(Program* program)
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
bool
|
||||
validate_live_vars(Program* program)
|
||||
{
|
||||
if (!(debug_flags & DEBUG_VALIDATE_LIVE_VARS))
|
||||
return true;
|
||||
|
||||
bool is_valid = true;
|
||||
const int prev_num_waves = program->num_waves;
|
||||
const monotonic_buffer_resource old_memory = std::move(program->live.memory);
|
||||
const std::vector<IDSet> prev_live_in = std::move(program->live.live_in);
|
||||
const RegisterDemand prev_max_demand = program->max_reg_demand;
|
||||
std::vector<RegisterDemand> block_demands(program->blocks.size());
|
||||
std::vector<RegisterDemand> live_in_demands(program->blocks.size());
|
||||
std::vector<std::vector<RegisterDemand>> register_demands(program->blocks.size());
|
||||
|
||||
for (unsigned i = 0; i < program->blocks.size(); i++) {
|
||||
Block& b = program->blocks[i];
|
||||
block_demands[i] = b.register_demand;
|
||||
live_in_demands[i] = b.live_in_demand;
|
||||
register_demands[i].reserve(b.instructions.size());
|
||||
for (unsigned j = 0; j < b.instructions.size(); j++)
|
||||
register_demands[i].emplace_back(b.instructions[j]->register_demand);
|
||||
}
|
||||
|
||||
aco::live_var_analysis(program);
|
||||
|
||||
/* Validate RegisterDemand calculation */
|
||||
for (unsigned i = 0; i < program->blocks.size(); i++) {
|
||||
Block& b = program->blocks[i];
|
||||
|
||||
if (!(b.register_demand == block_demands[i])) {
|
||||
is_valid = false;
|
||||
aco_err(program,
|
||||
"Register Demand not updated correctly for BB%d: got (%3u vgpr, %3u sgpr), but "
|
||||
"should be (%3u vgpr, %3u sgpr)",
|
||||
i, block_demands[i].vgpr, block_demands[i].sgpr, b.register_demand.vgpr,
|
||||
b.register_demand.sgpr);
|
||||
}
|
||||
if (!(b.live_in_demand == live_in_demands[i])) {
|
||||
is_valid = false;
|
||||
aco_err(program,
|
||||
"Live-in Demand not updated correctly for BB%d: got (%3u vgpr, %3u sgpr), but "
|
||||
"should be (%3u vgpr, %3u sgpr)",
|
||||
i, live_in_demands[i].vgpr, live_in_demands[i].sgpr, b.live_in_demand.vgpr,
|
||||
b.live_in_demand.sgpr);
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < b.instructions.size(); j++) {
|
||||
if (b.instructions[j]->register_demand == register_demands[i][j])
|
||||
continue;
|
||||
|
||||
char* out;
|
||||
size_t outsize;
|
||||
struct u_memstream mem;
|
||||
u_memstream_open(&mem, &out, &outsize);
|
||||
FILE* const memf = u_memstream_get(&mem);
|
||||
|
||||
fprintf(memf,
|
||||
"Register Demand not updated correctly: got (%3u vgpr, %3u sgpr), but should be "
|
||||
"(%3u vgpr, %3u sgpr): \n\t",
|
||||
register_demands[i][j].vgpr, register_demands[i][j].sgpr,
|
||||
b.instructions[j]->register_demand.vgpr, b.instructions[j]->register_demand.sgpr);
|
||||
aco_print_instr(program->gfx_level, b.instructions[j].get(), memf, print_kill);
|
||||
u_memstream_close(&mem);
|
||||
|
||||
aco_err(program, "%s", out);
|
||||
free(out);
|
||||
|
||||
is_valid = false;
|
||||
}
|
||||
}
|
||||
if (!(program->max_reg_demand == prev_max_demand) || program->num_waves != prev_num_waves) {
|
||||
is_valid = false;
|
||||
aco_err(program,
|
||||
"Max Register Demand and Num Waves not updated correctly: got (%3u vgpr, %3u sgpr) "
|
||||
"and %2u waves, but should be (%3u vgpr, %3u sgpr) and %2u waves",
|
||||
prev_max_demand.vgpr, prev_max_demand.sgpr, prev_num_waves,
|
||||
program->max_reg_demand.vgpr, program->max_reg_demand.sgpr, program->num_waves);
|
||||
}
|
||||
|
||||
/* Validate Live-in sets */
|
||||
for (unsigned i = 0; i < program->blocks.size(); i++) {
|
||||
if (prev_live_in[i] != program->live.live_in[i]) {
|
||||
char* out;
|
||||
size_t outsize;
|
||||
struct u_memstream mem;
|
||||
u_memstream_open(&mem, &out, &outsize);
|
||||
FILE* const memf = u_memstream_get(&mem);
|
||||
|
||||
fprintf(memf, "Live-in set not updated correctly for BB%d:", i);
|
||||
fprintf(memf, "\nMissing values: ");
|
||||
for (unsigned t : program->live.live_in[i]) {
|
||||
if (prev_live_in[i].count(t) == 0)
|
||||
fprintf(memf, "%%%d, ", t);
|
||||
}
|
||||
fprintf(memf, "\nAdditional values: ");
|
||||
for (unsigned t : prev_live_in[i]) {
|
||||
if (program->live.live_in[i].count(t) == 0)
|
||||
fprintf(memf, "%%%d, ", t);
|
||||
}
|
||||
u_memstream_close(&mem);
|
||||
aco_err(program, "%s", out);
|
||||
free(out);
|
||||
is_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
/* RA validation */
|
||||
namespace {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user