From 3dfbed2a87cdac7003b7db533046b633579e8d2f Mon Sep 17 00:00:00 2001 From: Rhys Perry Date: Mon, 13 Jul 2020 13:42:24 +0100 Subject: [PATCH] aco: create s_clause on GFX10+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This seems to give no measurable benefit to Strange Brigade or Shadow of Mordor, but it's simple to do, helps in theory and all other compilers do it. Signed-off-by: Rhys Perry Reviewed-by: Timur Kristóf Part-of: --- src/amd/compiler/aco_form_hard_clauses.cpp | 111 +++++++++++++++++++++ src/amd/compiler/aco_interface.cpp | 3 + src/amd/compiler/aco_ir.h | 1 + src/amd/compiler/meson.build | 1 + 4 files changed, 116 insertions(+) create mode 100644 src/amd/compiler/aco_form_hard_clauses.cpp diff --git a/src/amd/compiler/aco_form_hard_clauses.cpp b/src/amd/compiler/aco_form_hard_clauses.cpp new file mode 100644 index 00000000000..950413589c9 --- /dev/null +++ b/src/amd/compiler/aco_form_hard_clauses.cpp @@ -0,0 +1,111 @@ +/* + * Copyright © 2020 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 "aco_ir.h" +#include "aco_builder.h" + +namespace aco { +namespace { + +/* there can also be LDS and VALU clauses, but I don't see how those are interesting */ +enum clause_type +{ + clause_vmem, + clause_flat, + clause_smem, + clause_other, +}; + +void emit_clause(Builder& bld, unsigned num_instrs, aco_ptr *instrs) +{ + unsigned start = 0; + + /* skip any stores at the start */ + for (; (start < num_instrs) && instrs[start]->definitions.empty(); start++) + bld.insert(std::move(instrs[start])); + + unsigned end = start; + for (; (end < num_instrs) && !instrs[end]->definitions.empty(); end++) + ; + unsigned clause_size = end - start; + + if (clause_size > 1) + bld.sopp(aco_opcode::s_clause, -1, clause_size - 1); + + for (unsigned i = start; i < num_instrs; i++) + bld.insert(std::move(instrs[i])); +} + +} /* end namespace */ + +void form_hard_clauses(Program *program) +{ + for (Block& block : program->blocks) { + unsigned num_instrs = 0; + aco_ptr current_instrs[64]; + clause_type current_type = clause_other; + unsigned current_resource = 0; + + std::vector> new_instructions; + new_instructions.reserve(block.instructions.size()); + Builder bld(program, &new_instructions); + + for (unsigned i = 0; i < block.instructions.size(); i++) { + aco_ptr& instr = block.instructions[i]; + + unsigned resource = 0; + clause_type type = clause_other; + if (instr->isVMEM() && !instr->operands.empty()) { + resource = instr->operands[0].tempId(); + type = clause_vmem; + } else if (instr->format == Format::SCRATCH || instr->format == Format::GLOBAL) { + type = clause_vmem; + } else if (instr->format == Format::FLAT) { + type = clause_flat; + } else if (instr->format == Format::SMEM && !instr->operands.empty()) { + type = clause_smem; + if (instr->operands[0].bytes() == 16) + resource = instr->operands[0].tempId(); + } + + if (type != current_type || resource != current_resource || num_instrs == 64) { + emit_clause(bld, num_instrs, current_instrs); + num_instrs = 0; + current_type = type; + current_resource = resource; + } + + if (type == clause_other) { + bld.insert(std::move(instr)); + continue; + } + + current_instrs[num_instrs++] = std::move(instr); + } + + emit_clause(bld, num_instrs, current_instrs); + + block.instructions = std::move(new_instructions); + } +} +} diff --git a/src/amd/compiler/aco_interface.cpp b/src/amd/compiler/aco_interface.cpp index 7a62fdb0220..8f2593c4bb7 100644 --- a/src/amd/compiler/aco_interface.cpp +++ b/src/amd/compiler/aco_interface.cpp @@ -156,6 +156,9 @@ void aco_compile_shader(unsigned shader_count, aco::insert_wait_states(program.get()); aco::insert_NOPs(program.get()); + if (program->chip_class >= GFX10) + aco::form_hard_clauses(program.get()); + if (program->collect_statistics) aco::collect_preasm_stats(program.get()); diff --git a/src/amd/compiler/aco_ir.h b/src/amd/compiler/aco_ir.h index 10c78b32af0..39db82c655a 100644 --- a/src/amd/compiler/aco_ir.h +++ b/src/amd/compiler/aco_ir.h @@ -1746,6 +1746,7 @@ void schedule_program(Program* program, live& live_vars); void spill(Program* program, live& live_vars); void insert_wait_states(Program* program); void insert_NOPs(Program* program); +void form_hard_clauses(Program *program); unsigned emit_program(Program* program, std::vector& code); bool print_asm(Program *program, std::vector& binary, unsigned exec_size, FILE *output); diff --git a/src/amd/compiler/meson.build b/src/amd/compiler/meson.build index b82b69a2aeb..c03c31498e5 100644 --- a/src/amd/compiler/meson.build +++ b/src/amd/compiler/meson.build @@ -64,6 +64,7 @@ libaco_files = files( 'aco_ir.cpp', 'aco_ir.h', 'aco_assembler.cpp', + 'aco_form_hard_clauses.cpp', 'aco_insert_exec_mask.cpp', 'aco_insert_NOPs.cpp', 'aco_insert_waitcnt.cpp',