aco: remove live-out variables from IR

Since we changed all passes to use the live-in variables,
these are not needed anymore.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30120>
This commit is contained in:
Daniel Schürmann
2024-07-09 15:45:01 +02:00
committed by Marge Bot
parent f86816ca85
commit bb5af6bede
3 changed files with 92 additions and 62 deletions

View File

@@ -2064,8 +2064,6 @@ public:
struct {
monotonic_buffer_resource memory;
/* live temps out per block */
std::vector<IDSet> live_out;
/* live-in temps per block */
std::vector<IDSet> live_in;
} live;

View File

@@ -70,7 +70,8 @@ namespace {
struct live_ctx {
monotonic_buffer_resource m;
Program* program;
int worklist;
int32_t worklist;
uint32_t handled_once;
};
bool
@@ -88,12 +89,81 @@ instr_needs_vcc(Instruction* instr)
return false;
}
IDSet
compute_live_out(live_ctx& ctx, Block* block)
{
IDSet live(ctx.m);
if (block->logical_succs.empty()) {
/* Linear blocks:
* Directly insert the successor if it is a linear block as well.
*/
for (unsigned succ : block->linear_succs) {
if (ctx.program->blocks[succ].logical_preds.empty()) {
live.insert(ctx.program->live.live_in[succ]);
} else {
for (unsigned t : ctx.program->live.live_in[succ]) {
if (ctx.program->temp_rc[t].is_linear())
live.insert(t);
}
}
}
} else {
/* Logical blocks:
* Linear successors are either linear blocks or logical targets.
*/
live = IDSet(ctx.program->live.live_in[block->linear_succs[0]], ctx.m);
if (block->linear_succs.size() == 2)
live.insert(ctx.program->live.live_in[block->linear_succs[1]]);
/* At most one logical target needs a separate insertion. */
if (block->logical_succs.back() != block->linear_succs.back()) {
for (unsigned t : ctx.program->live.live_in[block->logical_succs.back()]) {
if (!ctx.program->temp_rc[t].is_linear())
live.insert(t);
}
} else {
assert(block->logical_succs[0] == block->linear_succs[0]);
}
}
/* Handle phi operands */
if (block->linear_succs.size() == 1 && block->linear_succs[0] >= ctx.handled_once) {
Block& succ = ctx.program->blocks[block->linear_succs[0]];
auto it = std::find(succ.linear_preds.begin(), succ.linear_preds.end(), block->index);
unsigned op_idx = std::distance(succ.linear_preds.begin(), it);
for (aco_ptr<Instruction>& phi : succ.instructions) {
if (!is_phi(phi))
break;
if (phi->opcode == aco_opcode::p_phi || phi->definitions[0].isKill())
continue;
if (phi->operands[op_idx].isTemp())
live.insert(phi->operands[op_idx].tempId());
}
}
if (block->logical_succs.size() == 1 && block->logical_succs[0] >= ctx.handled_once) {
Block& succ = ctx.program->blocks[block->logical_succs[0]];
auto it = std::find(succ.logical_preds.begin(), succ.logical_preds.end(), block->index);
unsigned op_idx = std::distance(succ.logical_preds.begin(), it);
for (aco_ptr<Instruction>& phi : succ.instructions) {
if (!is_phi(phi))
break;
if (phi->opcode == aco_opcode::p_linear_phi || phi->definitions[0].isKill())
continue;
if (phi->operands[op_idx].isTemp())
live.insert(phi->operands[op_idx].tempId());
}
}
return live;
}
void
process_live_temps_per_block(live_ctx& ctx, Block* block)
{
RegisterDemand new_demand;
block->register_demand = RegisterDemand();
IDSet live(ctx.program->live.live_out[block->index], ctx.m);
IDSet live = compute_live_out(ctx, block);
/* initialize register demand */
for (unsigned t : live)
@@ -176,48 +246,16 @@ process_live_temps_per_block(live_ctx& ctx, Block* block)
Definition& definition = insn->definitions[0];
if (definition.isFixed() && definition.physReg() == vcc)
ctx.program->needs_vcc = true;
const Temp temp = definition.getTemp();
const size_t n = live.erase(temp.id());
if (n) {
definition.setKill(false);
} else {
definition.setKill(true);
}
}
/* now, we need to merge the live-ins into the live-out sets */
bool fast_merge =
block->logical_preds.size() == 0 || block->logical_preds == block->linear_preds;
#ifndef NDEBUG
if ((block->linear_preds.empty() && !live.empty()) ||
(block->logical_preds.empty() && new_demand.vgpr > 0))
fast_merge = false; /* we might have errors */
#endif
if (fast_merge) {
for (unsigned pred_idx : block->linear_preds) {
if (ctx.program->live.live_out[pred_idx].insert(live))
ctx.worklist = std::max<int>(ctx.worklist, pred_idx);
}
} else {
for (unsigned t : live) {
RegClass rc = ctx.program->temp_rc[t];
Block::edge_vec& preds = rc.is_linear() ? block->linear_preds : block->logical_preds;
#ifndef NDEBUG
if (preds.empty())
aco_err(ctx.program, "Temporary never defined or are defined after use: %%%d in BB%d",
t, block->index);
#endif
for (unsigned pred_idx : preds) {
auto it = ctx.program->live.live_out[pred_idx].insert(t);
if (it.second)
ctx.worklist = std::max<int>(ctx.worklist, pred_idx);
const size_t n = live.erase(definition.tempId());
if (n && (definition.isKill() || ctx.handled_once > block->index)) {
Block::edge_vec& preds =
insn->opcode == aco_opcode::p_phi ? block->logical_preds : block->linear_preds;
for (unsigned i = 0; i < preds.size(); i++) {
if (insn->operands[i].isTemp())
ctx.worklist = std::max<int>(ctx.worklist, preds[i]);
}
}
definition.setKill(!n);
}
/* handle phi operands */
@@ -227,19 +265,11 @@ process_live_temps_per_block(live_ctx& ctx, Block* block)
/* Ignore dead phis. */
if (insn->definitions[0].isKill())
continue;
/* directly insert into the predecessors live-out set */
Block::edge_vec& preds =
insn->opcode == aco_opcode::p_phi ? block->logical_preds : block->linear_preds;
for (unsigned i = 0; i < preds.size(); ++i) {
Operand& operand = insn->operands[i];
for (Operand& operand : insn->operands) {
if (!operand.isTemp())
continue;
if (operand.isFixed() && operand.physReg() == vcc)
ctx.program->needs_vcc = true;
/* check if we changed an already processed block */
const bool inserted = ctx.program->live.live_out[preds[i]].insert(operand.tempId()).second;
if (inserted)
ctx.worklist = std::max<int>(ctx.worklist, preds[i]);
/* set if the operand is killed by this (or another) phi instruction */
operand.setKill(!live.count(operand.tempId()));
@@ -247,14 +277,23 @@ process_live_temps_per_block(live_ctx& ctx, Block* block)
}
if (ctx.program->live.live_in[block->index].insert(live)) {
if (block->linear_preds.size())
if (block->linear_preds.size()) {
assert(block->logical_preds.empty() ||
block->logical_preds.back() <= block->linear_preds.back());
ctx.worklist = std::max<int>(ctx.worklist, block->linear_preds.back());
} else {
for (unsigned t : live) {
aco_err(ctx.program, "Temporary never defined or are defined after use: %%%d in BB%d",
t, block->index);
}
}
}
block->live_in_demand = new_demand;
block->live_in_demand.sgpr += 2; /* Add 2 SGPRs for potential long-jumps. */
block->register_demand.update(block->live_in_demand);
ctx.program->max_reg_demand.update(block->register_demand);
ctx.handled_once = std::min(ctx.handled_once, block->index);
assert(!block->linear_preds.empty() || (new_demand == RegisterDemand() && live.empty()));
}
@@ -421,10 +460,8 @@ update_vgpr_sgpr_demand(Program* program, const RegisterDemand new_demand)
void
live_var_analysis(Program* program)
{
program->live.live_out.clear();
program->live.live_in.clear();
program->live.memory.release();
program->live.live_out.resize(program->blocks.size(), IDSet(program->live.memory));
program->live.live_in.resize(program->blocks.size(), IDSet(program->live.memory));
program->max_reg_demand = RegisterDemand();
program->needs_vcc = program->gfx_level >= GFX10;
@@ -432,6 +469,7 @@ live_var_analysis(Program* program)
live_ctx ctx;
ctx.program = program;
ctx.worklist = program->blocks.size() - 1;
ctx.handled_once = program->blocks.size();
/* this implementation assumes that the block idx corresponds to the block's position in
* program->blocks vector */

View File

@@ -84,12 +84,6 @@ reindex_ssa(Program* program, bool update_live_out = false)
idx_ctx ctx;
reindex_program(ctx, program);
if (update_live_out) {
for (IDSet& set : program->live.live_out) {
IDSet new_set(program->live.memory);
for (uint32_t id : set)
new_set.insert(ctx.renames[id]);
set = new_set;
}
for (IDSet& set : program->live.live_in) {
IDSet new_set(program->live.memory);
for (uint32_t id : set)