aco/tests: Add post-RA DPP test cases with control flow.

These are intended to make sure that the post-RA optimizer works
correctly across control flow. The new tests emit a divergent
if-else branch (with full logical+linear CFG).

- dpp_across_cf:
  Simple case of DPP optimizable across control flow. Should pass.
- dpp_across_cf_overwritten:
  Similar case but the DPP source register is overwritten in CF.
  This shows a bug so the test fails now (will be fixed).

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/18488>
This commit is contained in:
Timur Kristóf
2022-09-20 16:28:01 +02:00
committed by Marge Bot
parent d7cd49d54b
commit d4b3f81d94
3 changed files with 218 additions and 0 deletions
+65
View File
@@ -350,6 +350,71 @@ Temp ext_ubyte(Temp src, unsigned idx, Builder b)
Operand::c32(8u), Operand::c32(false));
}
void emit_divergent_if_else(Program* prog, aco::Builder& b, Operand cond, std::function<void()> then,
std::function<void()> els)
{
prog->blocks.reserve(prog->blocks.size() + 6);
Block* if_block = &prog->blocks.back();
Block* then_logical = prog->create_and_insert_block();
Block* then_linear = prog->create_and_insert_block();
Block* invert = prog->create_and_insert_block();
Block* else_logical = prog->create_and_insert_block();
Block* else_linear = prog->create_and_insert_block();
Block* endif_block = prog->create_and_insert_block();
if_block->kind |= block_kind_branch;
invert->kind |= block_kind_invert;
endif_block->kind |= block_kind_merge;
/* Set up logical CF */
then_logical->logical_preds.push_back(if_block->index);
else_logical->logical_preds.push_back(if_block->index);
endif_block->logical_preds.push_back(then_logical->index);
endif_block->logical_preds.push_back(else_logical->index);
/* Set up linear CF */
then_logical->linear_preds.push_back(if_block->index);
then_linear->linear_preds.push_back(if_block->index);
invert->linear_preds.push_back(then_logical->index);
invert->linear_preds.push_back(then_linear->index);
else_logical->linear_preds.push_back(invert->index);
else_linear->linear_preds.push_back(invert->index);
endif_block->linear_preds.push_back(else_logical->index);
endif_block->linear_preds.push_back(else_linear->index);
PhysReg saved_exec_reg(84);
b.reset(if_block);
Temp saved_exec = b.sop1(Builder::s_and_saveexec, b.def(b.lm, saved_exec_reg), Definition(scc, s1), Definition(exec, b.lm), cond, Operand(exec, b.lm));
b.branch(aco_opcode::p_cbranch_nz, Definition(vcc, bld.lm), then_logical->index, then_linear->index);
b.reset(then_logical);
b.pseudo(aco_opcode::p_logical_start);
then();
b.pseudo(aco_opcode::p_logical_end);
b.branch(aco_opcode::p_branch, Definition(vcc, bld.lm), invert->index);
b.reset(then_linear);
b.branch(aco_opcode::p_branch, Definition(vcc, bld.lm), invert->index);
b.reset(invert);
b.sop2(Builder::s_andn2, Definition(exec, bld.lm), Definition(scc, s1), Operand(saved_exec, saved_exec_reg), Operand(exec, bld.lm));
b.branch(aco_opcode::p_cbranch_nz, Definition(vcc, bld.lm), else_logical->index, else_linear->index);
b.reset(else_logical);
b.pseudo(aco_opcode::p_logical_start);
els();
b.pseudo(aco_opcode::p_logical_end);
b.branch(aco_opcode::p_branch, Definition(vcc, bld.lm), endif_block->index);
b.reset(else_linear);
b.branch(aco_opcode::p_branch, Definition(vcc, bld.lm), endif_block->index);
b.reset(endif_block);
b.pseudo(aco_opcode::p_parallelcopy, Definition(exec, bld.lm), Operand(saved_exec, saved_exec_reg));
}
VkDevice get_vk_device(enum amd_gfx_level gfx_level)
{
enum radeon_family family;
+3
View File
@@ -26,6 +26,7 @@
#include "framework.h"
#include "vulkan/vulkan.h"
#include <functional>
enum QoShaderDeclType {
QoShaderDeclType_ubo,
@@ -102,6 +103,8 @@ aco::Temp fma(aco::Temp src0, aco::Temp src1, aco::Temp src2, aco::Builder b=bld
aco::Temp fsat(aco::Temp src, aco::Builder b=bld);
aco::Temp ext_ushort(aco::Temp src, unsigned idx, aco::Builder b=bld);
aco::Temp ext_ubyte(aco::Temp src, unsigned idx, aco::Builder b=bld);
void emit_divergent_if_else(aco::Program* prog, aco::Builder& b, aco::Operand cond, std::function<void()> then,
std::function<void()> els);
/* vulkan helpers */
VkDevice get_vk_device(enum amd_gfx_level gfx_level);
@@ -430,3 +430,153 @@ BEGIN_TEST(optimizer_postRA.dpp)
finish_optimizer_postRA_test();
END_TEST
BEGIN_TEST(optimizer_postRA.dpp_across_cf)
//>> v1: %a:v[0], v1: %b:v[1], v1: %c:v[2], v1: %d:v[3], s2: %e:s[0-1] = p_startpgm
if (!setup_cs("v1 v1 v1 v1 s2", GFX10_3))
return;
aco_ptr<Instruction>& startpgm = bld.instructions->at(0);
startpgm->definitions[0].setFixed(PhysReg(256));
startpgm->definitions[1].setFixed(PhysReg(257));
startpgm->definitions[2].setFixed(PhysReg(258));
startpgm->definitions[3].setFixed(PhysReg(259));
startpgm->definitions[4].setFixed(PhysReg(0));
Operand a(inputs[0], PhysReg(256)); /* source for DPP */
Operand b(inputs[1], PhysReg(257)); /* source for fadd */
Operand c(inputs[2], PhysReg(258)); /* buffer store address */
Operand d(inputs[3], PhysReg(259)); /* buffer store value */
Operand e(inputs[4], PhysReg(0)); /* condition */
PhysReg reg_v12(268); /* temporary register */
Temp dpp_tmp = bld.vop1_dpp(aco_opcode::v_mov_b32, bld.def(v1, reg_v12), a, dpp_row_mirror);
//! s2: %saved_exec:s[84-85], s1: %0:scc, s2: %0:exec = s_and_saveexec_b64 %e:s[0-1], %0:exec
//! s2: %0:vcc = p_cbranch_nz BB1, BB2
emit_divergent_if_else(program.get(), bld, e, [&]() -> void {
/* --- logical then --- */
//! BB1
//! /* logical preds: BB0, / linear preds: BB0, / kind: */
//! p_logical_start
//! buffer_store_dword %c:v[2], 0, %d:v[3], 0 offen storage: semantics: scope:invocation
bld.mubuf(aco_opcode::buffer_store_dword, c, Operand::zero(), d, Operand::zero(), 0, true);
//! p_logical_end
//! s2: %0:vcc = p_branch BB3
/* --- linear then --- */
//! BB2
//! /* logical preds: / linear preds: BB0, / kind: */
//! s2: %0:vcc = p_branch BB3
/* --- invert --- */
//! BB3
//! /* logical preds: / linear preds: BB1, BB2, / kind: invert, */
//! s2: %0:exec, s1: %0:scc = s_andn2_b64 %saved_exec:s[84-85], %0:exec
//! s2: %0:vcc = p_cbranch_nz BB4, BB5
}, [&]() -> void {
/* --- logical else --- */
//! BB4
//! /* logical preds: BB0, / linear preds: BB3, / kind: */
//! p_logical_start
//! p_logical_end
//! s2: %0:vcc = p_branch BB6
/* --- linear else --- */
//! BB5
//! /* logical preds: / linear preds: BB3, / kind: */
//! s2: %0:vcc = p_branch BB6
});
/* --- merge block --- */
//! BB6
//! /* logical preds: BB1, BB4, / linear preds: BB4, BB5, / kind: uniform, merge, */
//! s2: %0:exec = p_parallelcopy %saved_exec:s[84-85]
//! v1: %res10:v[12] = v_add_f32 %a:v[0], %b:v[1] row_mirror bound_ctrl:1
//! p_unit_test 10, %res10:v[12]
Temp result = bld.vop2(aco_opcode::v_add_f32, bld.def(v1, reg_v12), Operand(dpp_tmp, reg_v12), b);
writeout(10, Operand(result, reg_v12));
finish_optimizer_postRA_test();
END_TEST
BEGIN_TEST(optimizer_postRA.dpp_across_cf_overwritten)
//>> v1: %a:v[0], v1: %b:v[1], v1: %c:v[2], v1: %d:v[3], s2: %e:s[0-1], s1: %f:s[2] = p_startpgm
if (!setup_cs("v1 v1 v1 v1 s2 s1", GFX10_3))
return;
aco_ptr<Instruction>& startpgm = bld.instructions->at(0);
startpgm->definitions[0].setFixed(PhysReg(256));
startpgm->definitions[1].setFixed(PhysReg(257));
startpgm->definitions[2].setFixed(PhysReg(258));
startpgm->definitions[3].setFixed(PhysReg(259));
startpgm->definitions[4].setFixed(PhysReg(0));
startpgm->definitions[5].setFixed(PhysReg(2));
Operand a(inputs[0], PhysReg(256)); /* source for DPP */
Operand b(inputs[1], PhysReg(257)); /* source for fadd */
Operand d(inputs[3], PhysReg(259)); /* buffer store value */
Operand e(inputs[4], PhysReg(0)); /* condition */
Operand f(inputs[5], PhysReg(2)); /* buffer store address (scalar) */
PhysReg reg_v12(268); /* temporary register */
//! v1: %dpp_tmp:v[12] = v_mov_b32 %a:v[0] row_mirror bound_ctrl:1
Temp dpp_tmp = bld.vop1_dpp(aco_opcode::v_mov_b32, bld.def(v1, reg_v12), a, dpp_row_mirror);
//! s2: %saved_exec:s[84-85], s1: %0:scc, s2: %0:exec = s_and_saveexec_b64 %e:s[0-1], %0:exec
//! s2: %0:vcc = p_cbranch_nz BB1, BB2
emit_divergent_if_else(program.get(), bld, e, [&]() -> void {
/* --- logical then --- */
//! BB1
//! /* logical preds: BB0, / linear preds: BB0, / kind: */
//! p_logical_start
//! v1: %addr:v[0] = p_parallelcopy %f:s[2]
Temp addr = bld.pseudo(aco_opcode::p_parallelcopy, bld.def(v1, a.physReg()), f);
//! buffer_store_dword %addr:v[0], 0, %d:v[3], 0 offen storage: semantics: scope:invocation
bld.mubuf(aco_opcode::buffer_store_dword, Operand(addr, a.physReg()), Operand::zero(), d, Operand::zero(), 0, true);
//! p_logical_end
//! s2: %0:vcc = p_branch BB3
/* --- linear then --- */
//! BB2
//! /* logical preds: / linear preds: BB0, / kind: */
//! s2: %0:vcc = p_branch BB3
/* --- invert --- */
//! BB3
//! /* logical preds: / linear preds: BB1, BB2, / kind: invert, */
//! s2: %0:exec, s1: %0:scc = s_andn2_b64 %saved_exec:s[84-85], %0:exec
//! s2: %0:vcc = p_cbranch_nz BB4, BB5
}, [&]() -> void {
/* --- logical else --- */
//! BB4
//! /* logical preds: BB0, / linear preds: BB3, / kind: */
//! p_logical_start
//! p_logical_end
//! s2: %0:vcc = p_branch BB6
/* --- linear else --- */
//! BB5
//! /* logical preds: / linear preds: BB3, / kind: */
//! s2: %0:vcc = p_branch BB6
});
/* --- merge block --- */
//! BB6
//! /* logical preds: BB1, BB4, / linear preds: BB4, BB5, / kind: uniform, merge, */
//! s2: %0:exec = p_parallelcopy %saved_exec:s[84-85]
//! v1: %result:v[12] = v_add_f32 %dpp_mov_tmp:v[12], %b:v[1]
Temp result = bld.vop2(aco_opcode::v_add_f32, bld.def(v1, reg_v12), Operand(dpp_tmp, reg_v12), b);
//! p_unit_test 10, %result:v[12]
writeout(10, Operand(result, reg_v12));
finish_optimizer_postRA_test();
END_TEST