diff options
author | Daniel Schürmann <[email protected]> | 2019-10-16 16:39:06 +0200 |
---|---|---|
committer | Daniel Schürmann <[email protected]> | 2019-10-30 19:48:33 +0000 |
commit | cd20e29de14496225de5ff4503e04701e1affc52 (patch) | |
tree | f1f4de1647ccf88229ba1be9a5c05a3b0a34f023 /src/amd/compiler/aco_spill.cpp | |
parent | 8023dcd71ee9eb1c5db012d716e959e973323906 (diff) |
aco: fix transitive affinities of spilled variables
Variables spilled on both branch legs need to be assigned to the same spilling slot.
These affinities can be transitive through multiple merge blocks.
Reviewed-by: Rhys Perry <[email protected]>
Diffstat (limited to 'src/amd/compiler/aco_spill.cpp')
-rw-r--r-- | src/amd/compiler/aco_spill.cpp | 104 |
1 files changed, 79 insertions, 25 deletions
diff --git a/src/amd/compiler/aco_spill.cpp b/src/amd/compiler/aco_spill.cpp index d17e02d6165..b7f4fd1992c 100644 --- a/src/amd/compiler/aco_spill.cpp +++ b/src/amd/compiler/aco_spill.cpp @@ -55,7 +55,7 @@ struct spill_ctx { std::vector<std::map<Temp, std::pair<uint32_t, uint32_t>>> next_use_distances_start; std::vector<std::map<Temp, std::pair<uint32_t, uint32_t>>> next_use_distances_end; std::vector<std::pair<RegClass, std::set<uint32_t>>> interferences; - std::vector<std::pair<uint32_t, uint32_t>> affinities; + std::vector<std::vector<uint32_t>> affinities; std::vector<bool> is_reloaded; std::map<Temp, remat_info> remat; std::map<Instruction *, bool> remat_used; @@ -67,6 +67,34 @@ struct spill_ctx { spills_entry(program->blocks.size()), spills_exit(program->blocks.size()), processed(program->blocks.size(), false) {} + void add_affinity(uint32_t first, uint32_t second) + { + unsigned found_first = affinities.size(); + unsigned found_second = affinities.size(); + for (unsigned i = 0; i < affinities.size(); i++) { + std::vector<uint32_t>& vec = affinities[i]; + for (uint32_t entry : vec) { + if (entry == first) + found_first = i; + else if (entry == second) + found_second = i; + } + } + if (found_first == affinities.size() && found_second == affinities.size()) { + affinities.emplace_back(std::vector<uint32_t>({first, second})); + } else if (found_first < affinities.size() && found_second == affinities.size()) { + affinities[found_first].push_back(second); + } else if (found_second < affinities.size() && found_first == affinities.size()) { + affinities[found_second].push_back(first); + } else if (found_first != found_second) { + /* merge second into first */ + affinities[found_first].insert(affinities[found_first].end(), affinities[found_second].begin(), affinities[found_second].end()); + affinities.erase(std::next(affinities.begin(), found_second)); + } else { + assert(found_first == found_second); + } + } + uint32_t allocate_spill_id(RegClass rc) { interferences.emplace_back(rc, std::set<uint32_t>()); @@ -740,7 +768,7 @@ void add_coupling_code(spill_ctx& ctx, Block* block, unsigned block_idx) 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}); + ctx.add_affinity(def_spill_id, spilled->second); continue; } @@ -752,7 +780,7 @@ void add_coupling_code(spill_ctx& ctx, Block* block, unsigned block_idx) } uint32_t spill_id = ctx.allocate_spill_id(phi->definitions[0].regClass()); - ctx.affinities.emplace_back(std::pair<uint32_t, uint32_t>{def_spill_id, spill_id}); + ctx.add_affinity(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] = Operand(var); spill->operands[1] = Operand(spill_id); @@ -789,7 +817,7 @@ void add_coupling_code(spill_ctx& ctx, Block* block, unsigned block_idx) std::map<Temp, uint32_t>::iterator spilled = ctx.spills_exit[pred_idx].find(pair.first); if (spilled != ctx.spills_exit[pred_idx].end()) { if (spilled->second != pair.second) - ctx.affinities.emplace_back(std::pair<uint32_t, uint32_t>{pair.second, spilled->second}); + ctx.add_affinity(pair.second, spilled->second); continue; } @@ -1227,17 +1255,22 @@ void assign_spill_slots(spill_ctx& ctx, unsigned spills_to_vgpr) { std::vector<bool> is_assigned(ctx.interferences.size()); /* first, handle affinities: just merge all interferences into both spill ids */ - for (std::pair<uint32_t, uint32_t> pair : ctx.affinities) { - assert(pair.first != pair.second); - for (uint32_t id : ctx.interferences[pair.first].second) - ctx.interferences[id].second.insert(pair.second); - for (uint32_t id : ctx.interferences[pair.second].second) - ctx.interferences[id].second.insert(pair.first); - ctx.interferences[pair.first].second.insert(ctx.interferences[pair.second].second.begin(), ctx.interferences[pair.second].second.end()); - ctx.interferences[pair.second].second.insert(ctx.interferences[pair.first].second.begin(), ctx.interferences[pair.first].second.end()); - - bool reloaded = ctx.is_reloaded[pair.first] || ctx.is_reloaded[pair.second]; - ctx.is_reloaded[pair.first] = ctx.is_reloaded[pair.second] = reloaded; + for (std::vector<uint32_t>& vec : ctx.affinities) { + for (unsigned i = 0; i < vec.size(); i++) { + for (unsigned j = i + 1; j < vec.size(); j++) { + assert(vec[i] != vec[j]); + for (uint32_t id : ctx.interferences[vec[i]].second) + ctx.interferences[id].second.insert(vec[j]); + for (uint32_t id : ctx.interferences[vec[j]].second) + ctx.interferences[id].second.insert(vec[i]); + ctx.interferences[vec[i]].second.insert(ctx.interferences[vec[j]].second.begin(), ctx.interferences[vec[j]].second.end()); + ctx.interferences[vec[j]].second.insert(ctx.interferences[vec[i]].second.begin(), ctx.interferences[vec[i]].second.end()); + + bool reloaded = ctx.is_reloaded[vec[i]] || ctx.is_reloaded[vec[j]]; + ctx.is_reloaded[vec[i]] = reloaded; + ctx.is_reloaded[vec[j]] = reloaded; + } + } } for (ASSERTED uint32_t i = 0; i < ctx.interferences.size(); i++) for (ASSERTED uint32_t id : ctx.interferences[i].second) @@ -1277,6 +1310,23 @@ void assign_spill_slots(spill_ctx& ctx, unsigned spills_to_vgpr) { is_assigned[id] = true; for (unsigned i = slot_idx; i < slot_idx + ctx.interferences[id].first.size(); i++) spill_slot_interferences[i].insert(ctx.interferences[id].second.begin(), ctx.interferences[id].second.end()); + + /* add all affinities: there are no additional interferences */ + for (std::vector<uint32_t>& vec : ctx.affinities) { + bool found_affinity = false; + for (uint32_t entry : vec) { + if (entry == id) { + found_affinity = true; + break; + } + } + if (!found_affinity) + continue; + for (uint32_t entry : vec) { + sgpr_slot[entry] = slot_idx; + is_assigned[entry] = true; + } + } } slot_idx++; } @@ -1321,16 +1371,20 @@ void assign_spill_slots(spill_ctx& ctx, unsigned spills_to_vgpr) { for (unsigned id = 0; id < is_assigned.size(); id++) assert(is_assigned[id] || !ctx.is_reloaded[id]); - for (std::pair<uint32_t, uint32_t> pair : ctx.affinities) { - assert(is_assigned[pair.first] == is_assigned[pair.second]); - if (!is_assigned[pair.first]) - continue; - assert(ctx.is_reloaded[pair.first] == ctx.is_reloaded[pair.second]); - assert(ctx.interferences[pair.first].first.type() == ctx.interferences[pair.second].first.type()); - if (ctx.interferences[pair.first].first.type() == RegType::sgpr) - assert(sgpr_slot[pair.first] == sgpr_slot[pair.second]); - else - assert(vgpr_slot[pair.first] == vgpr_slot[pair.second]); + for (std::vector<uint32_t>& vec : ctx.affinities) { + for (unsigned i = 0; i < vec.size(); i++) { + for (unsigned j = i + 1; j < vec.size(); j++) { + assert(is_assigned[vec[i]] == is_assigned[vec[j]]); + if (!is_assigned[vec[i]]) + continue; + assert(ctx.is_reloaded[vec[i]] == ctx.is_reloaded[vec[j]]); + assert(ctx.interferences[vec[i]].first.type() == ctx.interferences[vec[j]].first.type()); + if (ctx.interferences[vec[i]].first.type() == RegType::sgpr) + assert(sgpr_slot[vec[i]] == sgpr_slot[vec[j]]); + else + assert(vgpr_slot[vec[i]] == vgpr_slot[vec[j]]); + } + } } /* hope, we didn't mess up */ |