From 521b848ea80d8b5823aa69dec260ee48a82e70ea Mon Sep 17 00:00:00 2001 From: Patrick Lerda Date: Fri, 18 Jul 2025 13:02:18 +0200 Subject: [PATCH] r600: fix evergreen gds atomic_counter_comp_swap This change fixes the gds implementation of atomic_counter_comp_swap which requires three arguments. This update is based on 4e3b43f18046 "r600/atomic: fix ATOMCAS instruction." which was the tgsi implementation. Note: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36554 is required for this change to work properly on cayman. This change was tested on palm, cypress and barts. Here is the test fixed: khr-gl4[5-6]/shader_atomic_counter_ops_tests/shaderatomiccounteropsexchangetestcase: fail pass Cc: mesa-stable Signed-off-by: Patrick Lerda Reviewed-by: Gert Wollny Part-of: --- .../drivers/r600/sfn/sfn_instr_mem.cpp | 60 ++++++++++++++++++- src/gallium/drivers/r600/sfn/sfn_instr_mem.h | 1 + 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/gallium/drivers/r600/sfn/sfn_instr_mem.cpp b/src/gallium/drivers/r600/sfn/sfn_instr_mem.cpp index 6249a051c8e..f76923c913b 100644 --- a/src/gallium/drivers/r600/sfn/sfn_instr_mem.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_instr_mem.cpp @@ -87,8 +87,9 @@ GDSInstr::emit_atomic_counter(nir_intrinsic_instr *intr, Shader& shader) case nir_intrinsic_atomic_counter_min: case nir_intrinsic_atomic_counter_or: case nir_intrinsic_atomic_counter_xor: - case nir_intrinsic_atomic_counter_comp_swap: return emit_atomic_op2(intr, shader); + case nir_intrinsic_atomic_counter_comp_swap: + return emit_atomic_counter_comp_swap(intr, shader); case nir_intrinsic_atomic_counter_read: case nir_intrinsic_atomic_counter_post_dec: return emit_atomic_read(intr, shader); @@ -353,6 +354,63 @@ GDSInstr::emit_atomic_pre_dec(nir_intrinsic_instr *instr, Shader& shader) return true; } +bool +GDSInstr::emit_atomic_counter_comp_swap(nir_intrinsic_instr *instr, Shader& shader) +{ + auto& vf = shader.value_factory(); + bool read_result = !list_is_empty(&instr->def.uses); + + ESDOp op = + read_result ? get_opcode(instr->intrinsic) : get_opcode_wo(instr->intrinsic); + + if (DS_OP_INVALID == op) + return false; + + auto [offset, uav_id] = shader.evaluate_resource_offset(instr, 0); + + offset += nir_intrinsic_base(instr); + + auto dest = read_result ? vf.dest(instr->def, 0, pin_free) : nullptr; + + if (uav_id != nullptr) + shader.set_flag(Shader::sh_indirect_atomic); + + GDSInstr *ir = nullptr; + + if (shader.chip_class() < ISA_CC_CAYMAN) { + auto tmp = vf.temp_vec4(pin_group, {4, 1, 2, 7}); + + shader.emit_instruction( + new AluInstr(op1_mov, tmp[1], vf.src(instr->src[1], 0), AluInstr::write)); + shader.emit_instruction( + new AluInstr(op1_mov, tmp[2], vf.src(instr->src[2], 0), AluInstr::write)); + + ir = new GDSInstr(op, dest, tmp, offset, uav_id); + } else { + auto tmp = vf.temp_vec4(pin_group, {0, 1, 2, 7}); + + if (uav_id) + shader.emit_instruction(new AluInstr(op3_muladd_uint24, + tmp[0], + uav_id, + vf.literal(4), + vf.literal(4 * offset), + AluInstr::write)); + else + shader.emit_instruction( + new AluInstr(op1_mov, tmp[0], vf.literal(4 * offset), AluInstr::write)); + + shader.emit_instruction( + new AluInstr(op1_mov, tmp[1], vf.src(instr->src[1], 0), AluInstr::write)); + shader.emit_instruction( + new AluInstr(op1_mov, tmp[2], vf.src(instr->src[2], 0), AluInstr::write)); + + ir = new GDSInstr(op, dest, tmp, 0, nullptr); + } + shader.emit_instruction(ir); + return true; +} + void GDSInstr::update_indirect_addr(PRegister old_reg, PRegister addr) { (void)old_reg; diff --git a/src/gallium/drivers/r600/sfn/sfn_instr_mem.h b/src/gallium/drivers/r600/sfn/sfn_instr_mem.h index 89d59d2feaf..81f2df71a99 100644 --- a/src/gallium/drivers/r600/sfn/sfn_instr_mem.h +++ b/src/gallium/drivers/r600/sfn/sfn_instr_mem.h @@ -46,6 +46,7 @@ private: static bool emit_atomic_op2(nir_intrinsic_instr *intr, Shader& shader); static bool emit_atomic_inc(nir_intrinsic_instr *intr, Shader& shader); static bool emit_atomic_pre_dec(nir_intrinsic_instr *intr, Shader& shader); + static bool emit_atomic_counter_comp_swap(nir_intrinsic_instr *intr, Shader& shader); void do_print(std::ostream& os) const override;