From 09f1c40f2e2f3d3e06eed57a9c0b98ae4d714e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 19 Jun 2024 14:11:51 +0200 Subject: [PATCH] aco: track and use the live-in register demand per basic block Part-of: --- src/amd/compiler/aco_ir.h | 1 + src/amd/compiler/aco_live_var_analysis.cpp | 11 +++++-- src/amd/compiler/aco_spill.cpp | 35 ++-------------------- 3 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/amd/compiler/aco_ir.h b/src/amd/compiler/aco_ir.h index 5dc17491172..fe36cdba829 100644 --- a/src/amd/compiler/aco_ir.h +++ b/src/amd/compiler/aco_ir.h @@ -1887,6 +1887,7 @@ struct Block { edge_vec logical_succs; edge_vec linear_succs; RegisterDemand register_demand = RegisterDemand(); + RegisterDemand live_in_demand = RegisterDemand(); uint32_t kind = 0; int32_t logical_idom = -1; int32_t linear_idom = -1; diff --git a/src/amd/compiler/aco_live_var_analysis.cpp b/src/amd/compiler/aco_live_var_analysis.cpp index 374e2f33f8f..7dbb849081f 100644 --- a/src/amd/compiler/aco_live_var_analysis.cpp +++ b/src/amd/compiler/aco_live_var_analysis.cpp @@ -200,7 +200,6 @@ process_live_temps_per_block(Program* program, Block* block, unsigned& worklist, uint16_t linear_phi_defs = 0; int phi_idx = idx; while (phi_idx >= 0) { - register_demand[phi_idx] = new_demand; Instruction* insn = block->instructions[phi_idx].get(); assert(is_phi(insn) && insn->definitions.size() == 1); @@ -215,10 +214,12 @@ process_live_temps_per_block(Program* program, Block* block, unsigned& worklist, const Temp temp = definition.getTemp(); const size_t n = live.erase(temp.id()); - if (n) + if (n) { definition.setKill(false); - else + } else { + new_demand += temp; definition.setKill(true); + } if (insn->opcode == aco_opcode::p_linear_phi) { assert(definition.getTemp().type() == RegType::sgpr); @@ -268,6 +269,7 @@ process_live_temps_per_block(Program* program, Block* block, unsigned& worklist, /* handle phi operands */ phi_idx = idx; while (phi_idx >= 0) { + register_demand[phi_idx] = new_demand; Instruction* insn = block->instructions[phi_idx].get(); assert(is_phi(insn)); /* directly insert into the predecessors live-out set */ @@ -297,6 +299,9 @@ process_live_temps_per_block(Program* program, Block* block, unsigned& worklist, phi_idx--; } + block->live_in_demand = new_demand; + block->live_in_demand.sgpr += 2; /* Add 2 SGPRs for potential long-jumps. */ + assert(!block->linear_preds.empty() || (new_demand == RegisterDemand() && live.empty())); } diff --git a/src/amd/compiler/aco_spill.cpp b/src/amd/compiler/aco_spill.cpp index da9efc65677..59ffdf3fab5 100644 --- a/src/amd/compiler/aco_spill.cpp +++ b/src/amd/compiler/aco_spill.cpp @@ -308,34 +308,6 @@ get_demand_before(spill_ctx& ctx, unsigned block_idx, unsigned idx) } } -RegisterDemand -get_live_in_demand(spill_ctx& ctx, unsigned block_idx) -{ - unsigned idx = 0; - RegisterDemand reg_pressure = RegisterDemand(); - Block& block = ctx.program->blocks[block_idx]; - for (aco_ptr& phi : block.instructions) { - if (!is_phi(phi)) - break; - idx++; - - /* Killed phi definitions increase pressure in the predecessor but not - * the block they're in. Since the loops below are both to control - * pressure of the start of this block and the ends of it's - * predecessors, we need to count killed unspilled phi definitions here. */ - if (phi->definitions[0].isTemp() && phi->definitions[0].isKill() && - !ctx.spills_entry[block_idx].count(phi->definitions[0].getTemp())) - reg_pressure += phi->definitions[0].getTemp(); - } - - reg_pressure += get_demand_before(ctx, block_idx, idx); - - /* In order to create long jumps, we might need an empty SGPR pair. */ - reg_pressure.sgpr += 2; - - return reg_pressure; -} - RegisterDemand init_live_in_vars(spill_ctx& ctx, Block* block, unsigned block_idx) { @@ -354,7 +326,7 @@ init_live_in_vars(spill_ctx& ctx, Block* block, unsigned block_idx) assert(block->logical_preds[0] == block_idx - 1); /* check how many live-through variables should be spilled */ - RegisterDemand reg_pressure = get_live_in_demand(ctx, block_idx); + RegisterDemand reg_pressure = block->live_in_demand; RegisterDemand loop_demand = reg_pressure; unsigned i = block_idx; while (ctx.program->blocks[i].loop_nest_depth >= block->loop_nest_depth) @@ -570,7 +542,7 @@ init_live_in_vars(spill_ctx& ctx, Block* block, unsigned block_idx) } /* if reg pressure at first instruction is still too high, add partially spilled variables */ - RegisterDemand reg_pressure = get_live_in_demand(ctx, block_idx); + RegisterDemand reg_pressure = block->live_in_demand; reg_pressure -= spilled_registers; while (reg_pressure.exceeds(ctx.target_pressure)) { @@ -929,11 +901,10 @@ add_coupling_code(spill_ctx& ctx, Block* block, IDSet& live_in) if (!ctx.processed[block_idx]) { assert(!(block->kind & block_kind_loop_header)); - RegisterDemand demand_before = get_demand_before(ctx, block_idx, idx); std::vector& register_demand = ctx.program->live.register_demand[block->index]; register_demand.erase(register_demand.begin(), register_demand.begin() + idx); - register_demand.insert(register_demand.begin(), instructions.size(), demand_before); + register_demand.insert(register_demand.begin(), instructions.size(), block->live_in_demand); } std::vector>::iterator start = std::next(block->instructions.begin(), idx);