aco: Introduce a new, post-RA optimizer.

This commit adds the skeleton of a new ACO post-RA optimizer,
which is intended to be a simple pass called after RA, and
is meant to do code changes which can only be done
after RA.

It is currently empty, the actual optimizations will be added
in their own commits. It only has a DCE pass, which deletes
some dead code generated by the spiller.

Fossil DB results on Sienna Cichlid:

Totals from 375 (0.25% of 149839) affected shaders:
CodeSize: 2933056 -> 2907192 (-0.88%)
Instrs: 534154 -> 530706 (-0.65%)
Latency: 12088064 -> 12084907 (-0.03%); split: -0.03%, +0.00%
InvThroughput: 4433454 -> 4432421 (-0.02%); split: -0.02%, +0.00%
Copies: 81649 -> 78203 (-4.22%)

Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
Reviewed-by: Daniel Schürmann <daniel@schuermann.dev>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7779>
This commit is contained in:
Timur Kristóf 2020-11-24 11:39:28 +01:00 committed by Marge Bot
parent 6f3c472f2e
commit 0e4747d3fb
8 changed files with 195 additions and 0 deletions

View File

@ -150,6 +150,12 @@ void aco_compile_shader(unsigned shader_count,
validate(program.get());
/* Optimization */
if (!args->options->disable_optimizations && !(aco::debug_flags & aco::DEBUG_NO_OPT)) {
aco::optimize_postRA(program.get());
validate(program.get());
}
aco::ssa_elimination(program.get());
}

View File

@ -2013,6 +2013,7 @@ void dominator_tree(Program* program);
void insert_exec_mask(Program *program);
void value_numbering(Program* program);
void optimize(Program* program);
void optimize_postRA(Program* program);
void setup_reduce_temp(Program* program);
void lower_to_cssa(Program* program, live& live_vars);
void register_allocation(Program *program, std::vector<IDSet>& live_out_per_block,

View File

@ -0,0 +1,149 @@
/*
* Copyright © 2021 Valve Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Timur Kristóf <timur.kristof@gmail.com
*
*/
#include "aco_ir.h"
#include <vector>
#include <bitset>
#include <algorithm>
#include <array>
namespace aco {
namespace {
constexpr const size_t max_reg_cnt = 512;
enum {
not_written_in_block = -1,
clobbered = -2,
const_or_undef = -3,
written_by_multiple_instrs = -4,
};
struct pr_opt_ctx
{
Program *program;
Block *current_block;
int current_instr_idx;
std::vector<uint16_t> uses;
std::array<int, max_reg_cnt * 4u> instr_idx_by_regs;
void reset_block(Block *block)
{
current_block = block;
current_instr_idx = -1;
std::fill(instr_idx_by_regs.begin(), instr_idx_by_regs.end(), not_written_in_block);
}
};
void save_reg_writes(pr_opt_ctx &ctx, aco_ptr<Instruction> &instr)
{
for (const Definition &def : instr->definitions) {
assert(def.regClass().type() != RegType::sgpr || def.physReg().reg() <= 255);
assert(def.regClass().type() != RegType::vgpr || def.physReg().reg() >= 256);
unsigned dw_size = DIV_ROUND_UP(def.bytes(), 4u);
unsigned r = def.physReg().reg();
int idx = ctx.current_instr_idx;
if (def.regClass().is_subdword())
idx = clobbered;
assert(def.size() == dw_size || def.regClass().is_subdword());
std::fill(&ctx.instr_idx_by_regs[r], &ctx.instr_idx_by_regs[r + dw_size], idx);
}
}
int last_writer_idx(pr_opt_ctx &ctx, PhysReg physReg, RegClass rc)
{
/* Verify that all of the operand's registers are written by the same instruction. */
int instr_idx = ctx.instr_idx_by_regs[physReg.reg()];
unsigned dw_size = DIV_ROUND_UP(rc.bytes(), 4u);
unsigned r = physReg.reg();
bool all_same = std::all_of(
&ctx.instr_idx_by_regs[r], &ctx.instr_idx_by_regs[r + dw_size],
[instr_idx](int i) { return i == instr_idx; });
return all_same ? instr_idx : written_by_multiple_instrs;
}
int last_writer_idx(pr_opt_ctx &ctx, const Operand &op)
{
if (op.isConstant() || op.isUndefined())
return const_or_undef;
int instr_idx = ctx.instr_idx_by_regs[op.physReg().reg()];
#ifndef NDEBUG
/* Debug mode: */
instr_idx = last_writer_idx(ctx, op.physReg(), op.regClass());
assert(instr_idx != written_by_multiple_instrs);
#endif
return instr_idx;
}
void process_instruction(pr_opt_ctx &ctx, aco_ptr<Instruction> &instr)
{
ctx.current_instr_idx++;
if (instr)
save_reg_writes(ctx, instr);
}
} /* End of empty namespace */
void optimize_postRA(Program* program)
{
pr_opt_ctx ctx;
ctx.program = program;
ctx.uses = dead_code_analysis(program);
/* Forward pass
* Goes through each instruction exactly once, and can transform
* instructions or adjust the use counts of temps.
*/
for (auto &block : program->blocks) {
ctx.reset_block(&block);
for (aco_ptr<Instruction> &instr : block.instructions)
process_instruction(ctx, instr);
}
/* Cleanup pass
* Gets rid of instructions which are manually deleted or
* no longer have any uses.
*/
for (auto &block : program->blocks) {
auto new_end = std::remove_if(
block.instructions.begin(), block.instructions.end(),
[&ctx](const aco_ptr<Instruction> &instr) { return !instr || is_dead(ctx.uses, instr.get()); });
block.instructions.resize(new_end - block.instructions.begin());
}
}
} /* End of aco namespace */

View File

@ -75,6 +75,7 @@ libaco_files = files(
'aco_lower_to_cssa.cpp',
'aco_lower_to_hw_instr.cpp',
'aco_optimizer.cpp',
'aco_optimizer_postRA.cpp',
'aco_opt_value_numbering.cpp',
'aco_print_asm.cpp',
'aco_print_ir.cpp',

View File

@ -180,6 +180,15 @@ void finish_ra_test(ra_test_policy policy)
fail_test("Validation after register allocation failed");
return;
}
finish_program(program.get());
aco::optimize_postRA(program.get());
}
void finish_optimizer_postRA_test()
{
finish_program(program.get());
aco::optimize_postRA(program.get());
aco_print_program(program.get(), output);
}

View File

@ -80,6 +80,7 @@ void finish_program(aco::Program *program);
void finish_validator_test();
void finish_opt_test();
void finish_ra_test(aco::ra_test_policy);
void finish_optimizer_postRA_test();
void finish_to_hw_instr_test();
void finish_insert_nops_test();
void finish_assembler_test();

View File

@ -28,6 +28,7 @@ aco_tests_files = files(
'test_isel.cpp',
'test_optimizer.cpp',
'test_regalloc.cpp',
'test_optimizer_postRA.cpp',
'test_to_hw_instr.cpp',
'test_tests.cpp',
)

View File

@ -0,0 +1,27 @@
/*
* Copyright © 2021 Valve Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "helpers.h"
using namespace aco;