shader: 64-bit buffer atomic add (BUFFER_ATOMIC_ADD_X2)

This commit is contained in:
Çağatay Güçlü
2026-10-16 02:58:37 +03:00
committed by nmzik
parent 4f1f3b1bb3
commit 02ead0e2e1
10 changed files with 49 additions and 0 deletions
@@ -296,6 +296,7 @@ inline constexpr auto EmitBufferAtomicSMax32 = EmitAtomic32;
inline constexpr auto EmitBufferAtomicUMax32 = EmitAtomic32;
inline constexpr auto EmitBufferAtomicAnd32 = EmitAtomic32;
inline constexpr auto EmitBufferAtomicAnd64 = EmitBufferAtomic64;
inline constexpr auto EmitBufferAtomicIAdd64 = EmitBufferAtomic64;
inline constexpr auto EmitBufferAtomicOr32 = EmitAtomic32;
inline constexpr auto EmitBufferAtomicOr64 = EmitBufferAtomic64;
inline constexpr auto EmitBufferAtomicXor32 = EmitAtomic32;
@@ -516,6 +516,7 @@ spv::Op SpirvAtomicOpcode(IR::ValueOpcode opcode) {
case IR::ValueOpcode::ImageAtomicIAdd64:
case IR::ValueOpcode::BufferAtomicIAdd32:
case IR::ValueOpcode::SharedAtomicIAdd64:
case IR::ValueOpcode::BufferAtomicIAdd64:
case IR::ValueOpcode::SharedAtomicIAdd32: return spv::OpAtomicIAdd;
case IR::ValueOpcode::BufferAtomicISub32:
case IR::ValueOpcode::SharedAtomicISub32: return spv::OpAtomicISub;
@@ -67,6 +67,7 @@ constexpr MemoryOpcodeInfo MUBUF_OPCODE_LIST[] = {
{0x3fu, Opcode::BUFFER_ATOMIC_FMIN, 1, 32},
{0x40u, Opcode::BUFFER_ATOMIC_FMAX, 1, 32},
{0x50u, Opcode::BUFFER_ATOMIC_SWAP_X2, 2, 32},
{0x52u, Opcode::BUFFER_ATOMIC_ADD_X2, 2, 32},
{0x59u, Opcode::BUFFER_ATOMIC_AND_X2, 2, 32},
{0x5au, Opcode::BUFFER_ATOMIC_OR_X2, 2, 32},
{0x80u, Opcode::BUFFER_LOAD_FORMAT_D16_X, 1, 16, false, false, true},
@@ -670,6 +670,7 @@ std::string InstructionToString(const Instruction& inst) {
case Opcode::BUFFER_ATOMIC_CMPSWAP:
case Opcode::BUFFER_ATOMIC_SWAP_X2:
case Opcode::BUFFER_ATOMIC_ADD:
case Opcode::BUFFER_ATOMIC_ADD_X2:
case Opcode::BUFFER_ATOMIC_SUB:
case Opcode::BUFFER_ATOMIC_SMIN:
case Opcode::BUFFER_ATOMIC_UMIN:
@@ -586,6 +586,7 @@ enum class Opcode {
BUFFER_ATOMIC_CMPSWAP,
BUFFER_ATOMIC_SWAP_X2,
BUFFER_ATOMIC_ADD,
BUFFER_ATOMIC_ADD_X2,
BUFFER_ATOMIC_SUB,
BUFFER_ATOMIC_SMIN,
BUFFER_ATOMIC_UMIN,
@@ -1046,6 +1046,8 @@ void Translator::EmitMemory(const Decoder::Instruction& inst) {
return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicFMin32);
case Decoder::Opcode::BUFFER_ATOMIC_FMAX:
return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicFMax32);
case Decoder::Opcode::BUFFER_ATOMIC_ADD_X2:
return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicIAdd64);
case Decoder::Opcode::DS_ADD_U32:
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicIAdd32, false);
@@ -118,6 +118,7 @@ BufferAccess BufferAccessOf(ValueOpcode opcode) {
case ValueOpcode::BufferAtomicCmpSwap32:
case ValueOpcode::BufferAtomicSwap64:
case ValueOpcode::BufferAtomicIAdd32:
case ValueOpcode::BufferAtomicIAdd64:
case ValueOpcode::BufferAtomicISub32:
case ValueOpcode::BufferAtomicSMin32:
case ValueOpcode::BufferAtomicUMin32:
@@ -137,6 +138,7 @@ BufferAccess BufferAccessOf(ValueOpcode opcode) {
uint32_t BufferComponentCount(ValueOpcode opcode) {
switch (opcode) {
case ValueOpcode::BufferAtomicSwap64:
case ValueOpcode::BufferAtomicIAdd64:
case ValueOpcode::BufferAtomicAnd64:
case ValueOpcode::BufferAtomicOr64:
case ValueOpcode::LoadBufferU32x2:
@@ -268,6 +268,7 @@ VALUE_OPCODE(BufferAtomicSwap32, U32, BufferResource, U32, U32, U32, U32, U1)
VALUE_OPCODE(BufferAtomicCmpSwap32, U32, BufferResource, U32, U32, U32, U32, U32, U1)
VALUE_OPCODE(BufferAtomicSwap64, U64, BufferResource, U32, U32, U32, U64, U1)
VALUE_OPCODE(BufferAtomicIAdd32, U32, BufferResource, U32, U32, U32, U32, U1)
VALUE_OPCODE(BufferAtomicIAdd64, U64, BufferResource, U32, U32, U32, U64, U1)
VALUE_OPCODE(BufferAtomicISub32, U32, BufferResource, U32, U32, U32, U32, U1)
VALUE_OPCODE(BufferAtomicSMin32, U32, BufferResource, U32, U32, U32, U32, U1)
VALUE_OPCODE(BufferAtomicUMin32, U32, BufferResource, U32, U32, U32, U32, U1)
+37
View File
@@ -20991,6 +20991,7 @@ CoverageClass ClassifyOpcode(ShaderOpcode opcode,
case Opcode::BUFFER_ATOMIC_SMAX:
case Opcode::BUFFER_ATOMIC_UMAX:
case Opcode::BUFFER_ATOMIC_AND:
case Opcode::BUFFER_ATOMIC_ADD_X2:
case Opcode::BUFFER_ATOMIC_AND_X2:
case Opcode::BUFFER_ATOMIC_OR:
case Opcode::BUFFER_ATOMIC_XOR:
@@ -35712,6 +35713,40 @@ TestCase BufferAtomicAndX2GlcAndExec() {
return test;
}
TestCase BufferAtomicAddX2GlcAndExec() {
using O = ShaderOpcode;
TestCase test;
test.name = "BufferAtomicAddX2GlcAndExec";
auto &code = test.code;
code.push_back(EncodeSop1(0x04, 12, 126));
AppendVMovU32(&code, 20, 0);
const u32 values[][2] = {{0x0ff00ff0u, 0xf00ff00fu},
{0xff00ff00u, 0x00ff00ffu},
{0x76543210u, 0xfedcba98u}};
for (u32 i = 0; i < std::size(values); ++i) {
AppendVMovLiteral(&code, 2, values[i][0]);
AppendVMovLiteral(&code, 3, values[i][1]);
if (i == 2) {
code.push_back(EncodeSop1(0x04, 126, InlineU32(0)));
}
AppendBufferStoreOpcode(&code, 0x52, 2, 20, i != 1);
code.push_back(EncodeSop1(0x04, 126, 12));
AppendStoreVgpr(&code, 2, 2 + i * 2);
AppendStoreVgpr(&code, 3, 3 + i * 2);
}
AppendEnd(&code);
test.initial = {0x12345678u, 0x87654321u, 0, 0, 0, 0, 0, 0};
// The first add wraps at 64 bits; the second carries from the low dword.
// GLC returns the first old value, preserves the second operand, and EXEC = 0
// suppresses the third add and its writeback despite its nonzero operand.
test.expected = {0x21256568u, 0x78743430u, 0x12345678u, 0x87654321u,
0xff00ff00u, 0x00ff00ffu, 0x76543210u, 0xfedcba98u};
test.opcodes = {O::V_MOV_B32, O::S_MOV_B64, O::BUFFER_ATOMIC_ADD_X2,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.required_spirv = {"OpAtomicIAdd %ulong", "Int64Atomics"};
return test;
}
TestCase BufferAtomicCmpSwapExactRaw() {
using O = ShaderOpcode;
@@ -42248,6 +42283,7 @@ std::vector<TestCase> MakeCases() {
}
}
AddCase(BufferAtomicAndX2GlcAndExec);
AddCase(BufferAtomicAddX2GlcAndExec);
AddCase(ImageAtomicSignedMinMax<false>);
AddCase(ImageAtomicSignedMinMax<true>);
AddCase(ImageAtomicSignedMinMax<false, true>);
@@ -47786,6 +47822,7 @@ int main(int argc, char **argv) {
}
RunCase(&vulkan, DsAtomicReturn64());
RunCase(&vulkan, BufferAtomicAndX2GlcAndExec());
RunCase(&vulkan, BufferAtomicAddX2GlcAndExec());
RunCase(&vulkan, ImageAtomicSignedMinMax<false>());
RunCase(&vulkan, ImageAtomicSignedMinMax<true>());
return 0;
+2
View File
@@ -10539,6 +10539,8 @@ void TestCapturedBufferAtomicsX2() {
ValueOpcode ir_opcode;
};
const Case cases[] = {
{{0xe1480018u, 0x80000000u}, 0u, 234u, "BUFFER_ATOMIC_ADD_X2",
"BufferAtomicIAdd64", "OpAtomicIAdd", ValueOpcode::BufferAtomicIAdd64},
{{0xe1680018u, 0x80000000u}, 0u, 241u, "BUFFER_ATOMIC_OR_X2",
"BufferAtomicOr64", "OpAtomicOr", ValueOpcode::BufferAtomicOr64},
{{0xe1402000u, 0x80000913u}, 9u, 229u, "BUFFER_ATOMIC_SWAP_X2",