aco: Introduce a new, post-RA optimizer.
authorTimur Kristóf <timur.kristof@gmail.com>
Tue, 24 Nov 2020 10:39:28 +0000 (11:39 +0100)
committerMarge Bot <eric+marge@anholt.net>
Fri, 28 May 2021 12:14:53 +0000 (12:14 +0000)
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>

src/amd/compiler/aco_interface.cpp
src/amd/compiler/aco_ir.h
src/amd/compiler/aco_optimizer_postRA.cpp [new file with mode: 0644]
src/amd/compiler/meson.build
src/amd/compiler/tests/helpers.cpp
src/amd/compiler/tests/helpers.h
src/amd/compiler/tests/meson.build
src/amd/compiler/tests/test_optimizer_postRA.cpp [new file with mode: 0644]

index 20cb04c..54a2973 100644 (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());
    }
 
index 3b6280c..c05b658 100644 (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,
diff --git a/src/amd/compiler/aco_optimizer_postRA.cpp b/src/amd/compiler/aco_optimizer_postRA.cpp
new file mode 100644 (file)
index 0000000..45b6194
--- /dev/null
@@ -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 */
\ No newline at end of file
index e780d65..ae545ec 100644 (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',
index 1a579ad..52f93e0 100644 (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);
 }
 
index 90964c8..f9b966b 100644 (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();
index 0537f01..af2c462 100644 (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',
 )
diff --git a/src/amd/compiler/tests/test_optimizer_postRA.cpp b/src/amd/compiler/tests/test_optimizer_postRA.cpp
new file mode 100644 (file)
index 0000000..a8a5acd
--- /dev/null
@@ -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;