graphics: implement RDNA2 buffer atomic swap x2

This commit is contained in:
nmzik
2026-09-03 06:01:27 +02:00
parent c78a5a9fdf
commit b3c8f91a84
9 changed files with 83 additions and 61 deletions
@@ -189,7 +189,8 @@ void AnalyzeProgramRequirements(IR::Program& program) {
const auto MarkBallot = [&] { requirements.subgroup_ballot = true; };
for (const auto* block: program.blocks) {
for (const auto& inst: *block) {
if (inst.GetOpcode() == IR::ValueOpcode::BufferAtomicOr64) {
if (IR::BufferAccessOf(inst.GetOpcode()) == IR::BufferAccess::Atomic &&
inst.GetType() == IR::Type::U64) {
requirements.buffer_int64_atomics = true;
}
const auto address_access = IR::AddressOpcodeInfoOf(inst.GetOpcode()).access;
@@ -617,6 +617,7 @@ void FormattedStore(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Memor
uint32_t AtomicOpcode(IR::ValueOpcode opcode) {
switch (opcode) {
case IR::ValueOpcode::BufferAtomicSwap32:
case IR::ValueOpcode::BufferAtomicSwap64:
case IR::ValueOpcode::SharedAtomicSwap32: return OpAtomicExchange;
case IR::ValueOpcode::BufferAtomicIAdd32:
case IR::ValueOpcode::SharedAtomicIAdd32: return OpAtomicIAdd;
@@ -633,6 +634,7 @@ uint32_t AtomicOpcode(IR::ValueOpcode opcode) {
case IR::ValueOpcode::BufferAtomicAnd32:
case IR::ValueOpcode::SharedAtomicAnd32: return OpAtomicAnd;
case IR::ValueOpcode::BufferAtomicOr32:
case IR::ValueOpcode::BufferAtomicOr64:
case IR::ValueOpcode::SharedAtomicOr32: return OpAtomicOr;
case IR::ValueOpcode::BufferAtomicXor32:
case IR::ValueOpcode::SharedAtomicXor32: return OpAtomicXor;
@@ -672,8 +674,8 @@ uint32_t EmitAtomic(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Memor
return return_value ? result : ConstantU32(ctx.state, 0);
}
uint32_t EmitBufferAtomicOr64(ValueEmitContext& ctx, const IR::Inst& inst,
const IR::MemoryInfo& mem) {
uint32_t EmitBufferAtomic64(ValueEmitContext& ctx, const IR::Inst& inst,
const IR::MemoryInfo& mem) {
auto& state = ctx.state;
return EmitValueOrDefaultIfCondition(
state, ctx.Arg(inst, inst.NumArgs() - 1), TypeU64(state), ConstantU64(state, 0), [&]() {
@@ -690,7 +692,7 @@ uint32_t EmitBufferAtomicOr64(ValueEmitContext& ctx, const IR::Inst& inst,
ctx.Arg(inst, inst.NumArgs() - 2));
const auto old = state.builder.AllocateId();
state.builder.AddFunction(
{OpAtomicOr, TypeScalarU64(state), old,
{AtomicOpcode(inst.GetOpcode()), TypeScalarU64(state), old,
EmitStorageBufferElementPointer(
state, resource, index, TypeStorageBufferU64ElementPointer(state)),
ConstantU32(state, ScopeDevice),
@@ -1209,12 +1211,12 @@ bool EmitValueMemory(ValueEmitContext& ctx, const IR::Inst& inst) {
return true;
}
const auto atomic_opcode = AtomicOpcode(op);
if (atomic_opcode != 0) {
ctx.Define(inst, EmitAtomic(ctx, inst, ctx.Memory(inst), true));
if (atomic_opcode != 0 && inst.GetType() == IR::Type::U64) {
ctx.Define(inst, EmitBufferAtomic64(ctx, inst, ctx.Memory(inst)));
return true;
}
if (op == IR::ValueOpcode::BufferAtomicOr64) {
ctx.Define(inst, EmitBufferAtomicOr64(ctx, inst, ctx.Memory(inst)));
if (atomic_opcode != 0) {
ctx.Define(inst, EmitAtomic(ctx, inst, ctx.Memory(inst), true));
return true;
}
if (op == IR::ValueOpcode::BufferAtomicFMin32 || op == IR::ValueOpcode::BufferAtomicFMax32) {
@@ -58,6 +58,7 @@ constexpr MemoryOpcodeInfo MUBUF_OPCODE_LIST[] = {
{0x3bu, Opcode::BUFFER_ATOMIC_XOR, 1, 32},
{0x3fu, Opcode::BUFFER_ATOMIC_FMIN, 1, 32},
{0x40u, Opcode::BUFFER_ATOMIC_FMAX, 1, 32},
{0x50u, Opcode::BUFFER_ATOMIC_SWAP_X2, 2, 32},
{0x5au, Opcode::BUFFER_ATOMIC_OR_X2, 2, 32},
};
@@ -592,6 +592,7 @@ std::string InstructionToString(const Instruction& inst) {
case Opcode::TBUFFER_STORE_FORMAT_XYZ:
case Opcode::TBUFFER_STORE_FORMAT_XYZW:
case Opcode::BUFFER_ATOMIC_SWAP:
case Opcode::BUFFER_ATOMIC_SWAP_X2:
case Opcode::BUFFER_ATOMIC_ADD:
case Opcode::BUFFER_ATOMIC_SUB:
case Opcode::BUFFER_ATOMIC_SMIN:
@@ -455,6 +455,7 @@ enum class Opcode {
TBUFFER_STORE_FORMAT_XYZ,
TBUFFER_STORE_FORMAT_XYZW,
BUFFER_ATOMIC_SWAP,
BUFFER_ATOMIC_SWAP_X2,
BUFFER_ATOMIC_ADD,
BUFFER_ATOMIC_SUB,
BUFFER_ATOMIC_SMIN,
@@ -922,6 +922,8 @@ bool Translator::EmitMemory(const Decoder::Instruction& inst) {
case Decoder::Opcode::BUFFER_ATOMIC_SWAP:
return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicSwap32);
case Decoder::Opcode::BUFFER_ATOMIC_SWAP_X2:
return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicSwap64);
case Decoder::Opcode::BUFFER_ATOMIC_ADD:
return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicIAdd32);
case Decoder::Opcode::BUFFER_ATOMIC_SUB:
@@ -111,6 +111,7 @@ BufferAccess BufferAccessOf(ValueOpcode opcode) {
case ValueOpcode::StoreBufferU32x3:
case ValueOpcode::StoreBufferU32x4: return BufferAccess::Write;
case ValueOpcode::BufferAtomicSwap32:
case ValueOpcode::BufferAtomicSwap64:
case ValueOpcode::BufferAtomicIAdd32:
case ValueOpcode::BufferAtomicISub32:
case ValueOpcode::BufferAtomicSMin32:
@@ -129,6 +130,7 @@ BufferAccess BufferAccessOf(ValueOpcode opcode) {
uint32_t BufferComponentCount(ValueOpcode opcode) {
switch (opcode) {
case ValueOpcode::BufferAtomicSwap64:
case ValueOpcode::BufferAtomicOr64:
case ValueOpcode::LoadBufferU32x2:
case ValueOpcode::StoreBufferU32x2: return 2u;
@@ -222,6 +222,7 @@ VALUE_OPCODE(StoreBufferU32x2, Void, BufferResource, U32, U32, U32, U32x2, U1)
VALUE_OPCODE(StoreBufferU32x3, Void, BufferResource, U32, U32, U32, U32x3, U1)
VALUE_OPCODE(StoreBufferU32x4, Void, BufferResource, U32, U32, U32, U32x4, U1)
VALUE_OPCODE(BufferAtomicSwap32, U32, BufferResource, 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(BufferAtomicISub32, U32, BufferResource, U32, U32, U32, U32, U1)
VALUE_OPCODE(BufferAtomicSMin32, U32, BufferResource, U32, U32, U32, U32, U1)