r600/sfn: Always start a new CF after a KILL instruction
Docu says:
Ensure that the KILL* instruction is the last instruction
in an ALU clause, because the remaining instructions executed
in the clause do not reflect the updated valid state after
the kill operation.
Fixes: 79ca456b48
r600/sfn: rewrite NIR backend
Signed-off-by: Gert Wollny <gert.wollny@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18983>
This commit is contained in:
@@ -35,6 +35,25 @@ AluGroup::AluGroup()
|
||||
std::fill(m_slots.begin(), m_slots.end(), nullptr);
|
||||
}
|
||||
|
||||
static bool is_kill(EAluOp op)
|
||||
{
|
||||
switch (op) {
|
||||
case op2_kille:
|
||||
case op2_kille_int:
|
||||
case op2_killne:
|
||||
case op2_killne_int:
|
||||
case op2_killge:
|
||||
case op2_killge_int:
|
||||
case op2_killge_uint:
|
||||
case op2_killgt:
|
||||
case op2_killgt_int:
|
||||
case op2_killgt_uint:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AluGroup::add_instruction(AluInstr *instr)
|
||||
{
|
||||
/* we can only schedule one op that accesses LDS or
|
||||
@@ -45,12 +64,17 @@ bool AluGroup::add_instruction(AluInstr *instr)
|
||||
if (instr->has_alu_flag(alu_is_trans)) {
|
||||
ASSERTED auto opinfo = alu_ops.find(instr->opcode());
|
||||
assert(opinfo->second.can_channel(AluOp::t, s_chip_class));
|
||||
if (add_trans_instructions(instr))
|
||||
if (add_trans_instructions(instr)) {
|
||||
if (is_kill(instr->opcode()))
|
||||
m_has_kill_op = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (add_vec_instructions(instr) && !instr->has_alu_flag(alu_is_trans)) {
|
||||
instr->set_parent_group(this);
|
||||
if (!instr->has_alu_flag(alu_is_lds) && is_kill(instr->opcode()))
|
||||
m_has_kill_op = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -61,6 +85,8 @@ bool AluGroup::add_instruction(AluInstr *instr)
|
||||
opinfo->second.can_channel(AluOp::t, s_chip_class) &&
|
||||
add_trans_instructions(instr)) {
|
||||
instr->set_parent_group(this);
|
||||
if (is_kill(instr->opcode()))
|
||||
m_has_kill_op = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -87,6 +87,7 @@ public:
|
||||
static bool has_t() { return s_max_slots == 5;}
|
||||
|
||||
bool addr_for_src() const { return m_addr_for_src;}
|
||||
bool has_kill_op() const {return m_has_kill_op;}
|
||||
|
||||
private:
|
||||
void forward_set_blockid(int id, int index) override;
|
||||
@@ -111,6 +112,7 @@ private:
|
||||
bool m_has_lds_op{false};
|
||||
bool m_addr_is_index{false};
|
||||
bool m_addr_for_src{false};
|
||||
bool m_has_kill_op{false};
|
||||
};
|
||||
|
||||
|
||||
|
@@ -294,7 +294,6 @@ void BlockSheduler::schedule_block(Block& in_block, Shader::ShaderBlocks& out_bl
|
||||
bool have_instr = collect_ready(cir);
|
||||
|
||||
m_current_block = new Block(in_block.nesting_depth(), in_block.id());
|
||||
|
||||
assert(m_current_block->id() >= 0);
|
||||
|
||||
while (have_instr) {
|
||||
@@ -569,6 +568,13 @@ bool BlockSheduler::schedule_alu(Shader::ShaderBlocks& out_blocks)
|
||||
if (group->has_lds_group_end())
|
||||
m_current_block->lds_group_end();
|
||||
|
||||
if (group->has_kill_op()) {
|
||||
assert(!group->has_lds_group_start());
|
||||
start_new_block(out_blocks, Block::alu);
|
||||
m_current_block->set_instr_flag(Instr::force_cf);
|
||||
}
|
||||
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@@ -178,6 +178,7 @@ bool FragmentShader::process_stage_intrinsic(nir_intrinsic_instr *intr)
|
||||
value_factory().zero(),
|
||||
value_factory().zero(),
|
||||
{AluInstr::last}));
|
||||
start_new_block(0);
|
||||
return true;
|
||||
case nir_intrinsic_load_sample_mask_in:
|
||||
if (m_apply_sample_mask) {
|
||||
|
Reference in New Issue
Block a user