diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp index d18369ea..6ce7612b 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp @@ -276,14 +276,8 @@ uint32_t ByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Memo uint32_t DwordIndex(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem, uint32_t prefix = 0) { - auto address = ByteAddress(ctx, inst, mem, prefix); - if (mem.kind == IR::ResourceKind::Lds || mem.kind == IR::ResourceKind::Gds) { - // RDNA2 DS region addresses retain bits [15:2] after adding the byte offset. - address = Binary(ctx.state, spv::OpBitwiseAnd, TypeU32(ctx.state), address, - ConstantU32(ctx.state, 0xffffu)); - } return Binary(ctx.state, spv::OpShiftRightLogical, TypeU32(ctx.state), - address, ConstantU32(ctx.state, 2)); + ByteAddress(ctx, inst, mem, prefix), ConstantU32(ctx.state, 2)); } uint32_t LoadWordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& resource, @@ -632,7 +626,12 @@ template uint32_t EmitAtomicAccess(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem, Fn&& operation) { return EmitValueOrZeroIfCondition(ctx.state, ctx.Arg(inst, inst.NumArgs() - 1), [&]() { - const auto index = DwordIndex(ctx, inst, mem); + auto index = DwordIndex(ctx, inst, mem); + if (mem.kind == IR::ResourceKind::Lds || mem.kind == IR::ResourceKind::Gds) { + // Keep region-address truncation local to DS atomics. + index = Binary(ctx.state, spv::OpBitwiseAnd, TypeU32(ctx.state), index, + ConstantU32(ctx.state, 0x3fffu)); + } const auto resource = PrepareMemoryResourceAccess(ctx.state, mem); return EmitValueOrZeroIfCondition( ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() { diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 995ffcc4..3d85a320 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -32259,6 +32259,45 @@ TestCase DsReadWriteVariants() { O::BUFFER_STORE_DWORD, O::S_ENDPGM}}; } +TestCase DsReadWriteFullRegionAddress(u32 wave_size, bool gds) { + using O = ShaderOpcode; + TestCase test; + test.name = gds ? (wave_size == 32u ? "DsGdsFullAddress32" : "DsGdsFullAddress64") + : (wave_size == 32u ? "DsLdsFullAddress32" : "DsLdsFullAddress64"); + auto &code = test.code; + code.push_back(EncodeVop2(0x1a, 1, InlineU32(2), 0)); + code.push_back(EncodeVop2(0x25, 2, InlineU32(1), 0)); + code.insert(code.end(), {EncodeDs0(0x0d, 4, gds), EncodeDs1(0, 2, 1)}); + AppendVMovLiteral(&code, 3, 0x10000u); + code.push_back(EncodeVop2(0x25, 3, Vgpr(1), 3)); + AppendVMovLiteral(&code, 4, 0xdeadbeefu); + // A high region address must not alias the valid word in the same lane. + code.insert(code.end(), {EncodeDs0(0x0d, 4, gds), EncodeDs1(0, 4, 3), + EncodeDs0(0x36, 4, gds), EncodeDs1(5, 0, 1), + EncodeDs0(0x36, 4, gds), EncodeDs1(6, 0, 3)}); + AppendStoreVgprAtLaneDwordOffset(&code, 5, 0, 0); + AppendStoreVgprAtLaneDwordOffset(&code, 6, 0, wave_size); + AppendEnd(&code); + test.initial.assign(wave_size * 2u, 0xdeadbeefu); + test.expected.resize(wave_size * 2u); + std::iota(test.expected.begin(), test.expected.begin() + wave_size, 1u); + test.compute_info.threads_num[0] = wave_size; + test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1u; + test.compute_info.thread_ids_num = 1; + test.compute_info.wave_size = wave_size; + test.compute_info.lds_size_dwords = wave_size + 1u; + test.has_compute_info = true; + if (gds) { + test.gds_initial.resize(wave_size + 1u); + test.expected_gds.resize(wave_size + 1u); + std::iota(test.expected_gds.begin(), test.expected_gds.end(), 0u); + } + test.opcodes = {O::V_LSHLREV_B32, O::V_ADD_NC_U32, O::V_MOV_B32, O::DS_WRITE_B32, + O::DS_READ_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM}; + test.forbidden_spirv = {"%uint_65535"}; + return test; +} + TestCase DsReadU16D16CapturedPreservesHighHalf() { using O = ShaderOpcode; @@ -38119,6 +38158,9 @@ std::vector MakeCases() { } } AddCase(DsReadWriteVariants); + for (u32 wave_size : {32u, 64u}) + for (bool gds : {false, true}) + cases.push_back(DsReadWriteFullRegionAddress(wave_size, gds)); AddCase(DsWriteB16D16HiCapturedUsesHighHalf); AddCase(DsWriteB8D16HiWritesByteTwo); AddCase(DsReadU16D16CapturedPreservesHighHalf); @@ -43566,6 +43608,9 @@ int main(int argc, char **argv) { if (argc == 2 && std::strcmp(argv[1], "--lds-limit-only") == 0) { VulkanHarness vulkan; CheckComputeLdsLimit(vulkan); + for (u32 wave_size : {32u, 64u}) + for (bool gds : {false, true}) + RunCase(&vulkan, DsReadWriteFullRegionAddress(wave_size, gds)); RunCase(&vulkan, DsWideLdsPartialBounds()); RunCase(&vulkan, DsAtomic64Bounds(false)); RunCase(&vulkan, DsAtomic64Bounds(true));