aboutsummaryrefslogtreecommitdiffstats
path: root/src/amd/compiler/aco_spill.cpp
diff options
context:
space:
mode:
authorDaniel Schürmann <[email protected]>2019-10-15 18:23:52 +0200
committerDaniel Schürmann <[email protected]>2019-10-30 19:48:32 +0000
commit0b8216b2cdbcaccfd2bd1a65be6b8ac5654e3067 (patch)
tree3efb44b589f7cf4131ed316cca0df23e25adb514 /src/amd/compiler/aco_spill.cpp
parent329d322a16af3139e1ed6c74ec90f6408680f051 (diff)
aco: Lower to CSSA
Converting to 'Conventional SSA Form' ensures correctness w.r.t. spilling of phi nodes. Previously, it was possible that phi operands have intersecting live-ranges, and thus, couldn't get spilled to the same spilling slot. For this reason, ACO tried to avoid to spill phis, even if it was beneficial. This patch implements a conversion pass which is currently only called if spilling is necessary. Reviewed-by: Rhys Perry <[email protected]>
Diffstat (limited to 'src/amd/compiler/aco_spill.cpp')
-rw-r--r--src/amd/compiler/aco_spill.cpp49
1 files changed, 16 insertions, 33 deletions
diff --git a/src/amd/compiler/aco_spill.cpp b/src/amd/compiler/aco_spill.cpp
index fefa8a8221b..d17e02d6165 100644
--- a/src/amd/compiler/aco_spill.cpp
+++ b/src/amd/compiler/aco_spill.cpp
@@ -541,9 +541,10 @@ RegisterDemand init_live_in_vars(spill_ctx& ctx, Block* block, unsigned block_id
bool spill = true;
for (unsigned i = 0; i < phi->operands.size(); i++) {
- if (!phi->operands[i].isTemp())
- spill = false;
- else if (ctx.spills_exit[preds[i]].find(phi->operands[i].getTemp()) == ctx.spills_exit[preds[i]].end())
+ if (phi->operands[i].isUndefined())
+ continue;
+ assert(phi->operands[i].isTemp());
+ if (ctx.spills_exit[preds[i]].find(phi->operands[i].getTemp()) == ctx.spills_exit[preds[i]].end())
spill = false;
else
partial_spills.insert(phi->definitions[0].getTemp());
@@ -720,43 +721,23 @@ void add_coupling_code(spill_ctx& ctx, Block* block, unsigned block_idx)
uint32_t def_spill_id = ctx.spills_entry[block_idx][phi->definitions[0].getTemp()];
for (unsigned i = 0; i < phi->operands.size(); i++) {
- unsigned pred_idx = preds[i];
-
- /* we have to spill constants to the same memory address */
- if (phi->operands[i].isConstant()) {
- uint32_t spill_id = ctx.allocate_spill_id(phi->definitions[0].regClass());
- for (std::pair<Temp, uint32_t> pair : ctx.spills_exit[pred_idx]) {
- ctx.interferences[def_spill_id].second.emplace(pair.second);
- ctx.interferences[pair.second].second.emplace(def_spill_id);
- }
- ctx.affinities.emplace_back(std::pair<uint32_t, uint32_t>{def_spill_id, spill_id});
-
- aco_ptr<Pseudo_instruction> spill{create_instruction<Pseudo_instruction>(aco_opcode::p_spill, Format::PSEUDO, 2, 0)};
- spill->operands[0] = phi->operands[i];
- spill->operands[1] = Operand(spill_id);
- Block& pred = ctx.program->blocks[pred_idx];
- unsigned idx = pred.instructions.size();
- do {
- assert(idx != 0);
- idx--;
- } while (phi->opcode == aco_opcode::p_phi && pred.instructions[idx]->opcode != aco_opcode::p_logical_end);
- std::vector<aco_ptr<Instruction>>::iterator it = std::next(pred.instructions.begin(), idx);
- pred.instructions.insert(it, std::move(spill));
- continue;
- }
- if (!phi->operands[i].isTemp())
+ if (phi->operands[i].isUndefined())
continue;
+ unsigned pred_idx = preds[i];
+ assert(phi->operands[i].isTemp() && phi->operands[i].isKill());
+ Temp var = phi->operands[i].getTemp();
+
/* build interferences between the phi def and all spilled variables at the predecessor blocks */
for (std::pair<Temp, uint32_t> pair : ctx.spills_exit[pred_idx]) {
- if (phi->operands[i].getTemp() == pair.first)
+ if (var == pair.first)
continue;
ctx.interferences[def_spill_id].second.emplace(pair.second);
ctx.interferences[pair.second].second.emplace(def_spill_id);
}
- /* variable is already spilled at predecessor */
- std::map<Temp, uint32_t>::iterator spilled = ctx.spills_exit[pred_idx].find(phi->operands[i].getTemp());
+ /* check if variable is already spilled at predecessor */
+ std::map<Temp, uint32_t>::iterator spilled = ctx.spills_exit[pred_idx].find(var);
if (spilled != ctx.spills_exit[pred_idx].end()) {
if (spilled->second != def_spill_id)
ctx.affinities.emplace_back(std::pair<uint32_t, uint32_t>{def_spill_id, spilled->second});
@@ -764,7 +745,6 @@ void add_coupling_code(spill_ctx& ctx, Block* block, unsigned block_idx)
}
/* rename if necessary */
- Temp var = phi->operands[i].getTemp();
std::map<Temp, Temp>::iterator rename_it = ctx.renames[pred_idx].find(var);
if (rename_it != ctx.renames[pred_idx].end()) {
var = rename_it->second;
@@ -813,7 +793,7 @@ void add_coupling_code(spill_ctx& ctx, Block* block, unsigned block_idx)
continue;
}
- /* variable is dead at predecessor, it must be from a phi: this works because of CSSA form */ // FIXME: lower_to_cssa()
+ /* variable is dead at predecessor, it must be from a phi: this works because of CSSA form */
if (ctx.next_use_distances_end[pred_idx].find(pair.first) == ctx.next_use_distances_end[pred_idx].end())
continue;
@@ -1567,6 +1547,9 @@ void spill(Program* program, live& live_vars, const struct radv_nir_compiler_opt
if (program->num_waves >= 6)
return;
+ /* lower to CSSA before spilling to ensure correctness w.r.t. phis */
+ lower_to_cssa(program, live_vars, options);
+
/* else, we check if we can improve things a bit */
/* calculate target register demand */