mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
shader: support returning 64-bit LDS max and compare-exchange
This commit is contained in:
@@ -322,6 +322,8 @@ inline constexpr auto EmitSharedAtomicDec32 = EmitSharedIncDec;
|
||||
inline constexpr auto EmitSharedAtomicSMin32 = EmitAtomic32;
|
||||
inline constexpr auto EmitSharedAtomicUMin32 = EmitAtomic32;
|
||||
inline constexpr auto EmitSharedAtomicSMax32 = EmitAtomic32;
|
||||
inline constexpr auto EmitSharedAtomicUMax64 = EmitSharedAtomic64;
|
||||
inline constexpr auto EmitSharedAtomicCmpSwap64 = EmitSharedAtomic64;
|
||||
inline constexpr auto EmitSharedAtomicUMax32 = EmitAtomic32;
|
||||
inline constexpr auto EmitSharedAtomicAnd32 = EmitAtomic32;
|
||||
inline constexpr auto EmitSharedAtomicOr32 = EmitAtomic32;
|
||||
|
||||
@@ -1240,32 +1240,48 @@ void EmitSharedAtomic64(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
auto& state = ctx.state;
|
||||
const auto& mem = ctx.Memory(inst);
|
||||
EnsureLdsStorage(state);
|
||||
EmitIfCondition(state, ctx.Arg(inst, 2), [&]() {
|
||||
const auto address = Binary(state, spv::OpBitwiseAnd, TypeU32(state),
|
||||
ByteAddress(ctx, inst, mem), ConstantU32(state, 0xfff8u));
|
||||
const auto index = Binary(state, spv::OpShiftRightLogical, TypeU32(state), address,
|
||||
ConstantU32(state, 3u));
|
||||
const auto in_bounds = Binary(state, spv::OpULessThan, TypeBool(state), index,
|
||||
ConstantU32(state, LdsDwordCount(state) / 2u));
|
||||
EmitIfCondition(state, in_bounds, [&]() {
|
||||
auto native_index = index;
|
||||
auto semantics = spv::MemorySemanticsWorkgroupMemoryMask;
|
||||
if (state.lds_storage_class == spv::StorageClassStorageBuffer) {
|
||||
native_index = EmitAddU32(state, index, EmitBinaryU32(
|
||||
state, spv::OpShiftRightLogical, state.lds_base_dwords, ConstantU32(state, 1)));
|
||||
semantics = spv::MemorySemanticsUniformMemoryMask;
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto address = Binary(state, spv::OpBitwiseAnd, TypeU32(state),
|
||||
ByteAddress(ctx, inst, mem), ConstantU32(state, 0xfff8u));
|
||||
const auto index = Binary(state, spv::OpShiftRightLogical, TypeU32(state), address,
|
||||
ConstantU32(state, 3u));
|
||||
const auto in_bounds = Binary(state, spv::OpULessThan, TypeBool(state), index,
|
||||
ConstantU32(state, LdsDwordCount(state) / 2u));
|
||||
const auto active = EmitLogicalAndBool(state, ctx.Arg(inst, inst.NumArgs() - 1), in_bounds);
|
||||
const auto emit = [&]() {
|
||||
auto native_index = index;
|
||||
auto semantics = spv::MemorySemanticsWorkgroupMemoryMask;
|
||||
if (state.lds_storage_class == spv::StorageClassStorageBuffer) {
|
||||
native_index = EmitAddU32(state, index, EmitBinaryU32(
|
||||
state, spv::OpShiftRightLogical, state.lds_base_dwords, ConstantU32(state, 1)));
|
||||
semantics = spv::MemorySemanticsUniformMemoryMask;
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
spv::OpAccessChain, TypePointer(state, state.lds_storage_class, TypeU64(state)),
|
||||
pointer, state.lds_u64_variable, ConstantU32(state, 0), native_index);
|
||||
const auto old = state.builder.AllocateId();
|
||||
const auto opcode = SpirvAtomicOpcode(inst.GetOpcode());
|
||||
const auto scope = ConstantU32(state, spv::ScopeWorkgroup);
|
||||
const auto acquire_release =
|
||||
ConstantU32(state, spv::MemorySemanticsAcquireReleaseMask | semantics);
|
||||
if (opcode == spv::OpAtomicCompareExchange) {
|
||||
// RDNA2 DS compares DATA and stores DATA2, opposite to BUFFER atomics.
|
||||
state.builder.AddFunction(
|
||||
spv::OpAccessChain, TypePointer(state, state.lds_storage_class, TypeU64(state)),
|
||||
pointer, state.lds_u64_variable, ConstantU32(state, 0), native_index);
|
||||
const auto value = ctx.Arg(inst, 1);
|
||||
state.builder.AddFunction(
|
||||
SpirvAtomicOpcode(inst.GetOpcode()), TypeU64(state), state.builder.AllocateId(),
|
||||
pointer, ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::MemorySemanticsAcquireReleaseMask | semantics), value);
|
||||
});
|
||||
});
|
||||
opcode, TypeU64(state), old, pointer, scope, acquire_release,
|
||||
ConstantU32(state, spv::MemorySemanticsAcquireMask | semantics),
|
||||
ctx.Arg(inst, 2), ctx.Arg(inst, 1));
|
||||
} else {
|
||||
state.builder.AddFunction(opcode, TypeU64(state), old, pointer, scope,
|
||||
acquire_release, ctx.Arg(inst, 1));
|
||||
}
|
||||
return old;
|
||||
};
|
||||
if (inst.HasUses()) {
|
||||
ctx.Define(inst, EmitValueOrDefaultIfCondition(
|
||||
state, active, TypeU64(state), ConstantU64(state, 0), emit));
|
||||
} else {
|
||||
EmitIfCondition(state, active, emit);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t EmitBufferFloatAtomic(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
|
||||
@@ -464,6 +464,7 @@ uint32_t EncodeFormattedStoreComponent(EmitterState& state, const Format::Buffer
|
||||
|
||||
spv::Op SpirvAtomicOpcode(IR::ValueOpcode opcode) {
|
||||
switch (opcode) {
|
||||
case IR::ValueOpcode::SharedAtomicCmpSwap64:
|
||||
case IR::ValueOpcode::ImageAtomicCompareSwap32:
|
||||
case IR::ValueOpcode::BufferAtomicCmpSwap32: return spv::OpAtomicCompareExchange;
|
||||
case IR::ValueOpcode::ImageAtomicSwap32:
|
||||
@@ -491,7 +492,8 @@ spv::Op SpirvAtomicOpcode(IR::ValueOpcode opcode) {
|
||||
case IR::ValueOpcode::ImageAtomicUMax32:
|
||||
case IR::ValueOpcode::ImageAtomicUMax64:
|
||||
case IR::ValueOpcode::BufferAtomicUMax32:
|
||||
case IR::ValueOpcode::SharedAtomicUMax32: return spv::OpAtomicUMax;
|
||||
case IR::ValueOpcode::SharedAtomicUMax32:
|
||||
case IR::ValueOpcode::SharedAtomicUMax64: return spv::OpAtomicUMax;
|
||||
case IR::ValueOpcode::ImageAtomicAnd32:
|
||||
case IR::ValueOpcode::ImageAtomicAnd64:
|
||||
case IR::ValueOpcode::BufferAtomicAnd32:
|
||||
|
||||
@@ -116,7 +116,8 @@ constexpr MemoryOpcodeInfo DS_OPCODE_LIST[] = {
|
||||
{0x3fu, Opcode::DS_ORDERED_COUNT, 1, 32},
|
||||
{0x40u, Opcode::DS_ADD_U64, 2, 32}, {0x4au, Opcode::DS_OR_B64, 2, 32},
|
||||
{0x4du, Opcode::DS_WRITE_B64, 2, 32}, {0x4eu, Opcode::DS_WRITE2_B64, 4, 32},
|
||||
{0x4fu, Opcode::DS_WRITE2ST64_B64, 4, 32}, {0x76u, Opcode::DS_READ_B64, 2, 32},
|
||||
{0x4fu, Opcode::DS_WRITE2ST64_B64, 4, 32}, {0x68u, Opcode::DS_MAX_RTN_U64, 2, 32},
|
||||
{0x70u, Opcode::DS_CMPST_RTN_B64, 2, 32}, {0x76u, Opcode::DS_READ_B64, 2, 32},
|
||||
{0x77u, Opcode::DS_READ2_B64, 4, 32}, {0x78u, Opcode::DS_READ2ST64_B64, 4, 32},
|
||||
{0xa0u, Opcode::DS_WRITE_B8_D16_HI, 1, 8},
|
||||
{0xa1u, Opcode::DS_WRITE_B16_D16_HI, 1, 16},
|
||||
@@ -192,6 +193,8 @@ bool IsDsAtomicOpcode(Opcode opcode) {
|
||||
case Opcode::DS_MIN_RTN_U32:
|
||||
case Opcode::DS_MAX_U32:
|
||||
case Opcode::DS_MAX_RTN_U32:
|
||||
case Opcode::DS_MAX_RTN_U64:
|
||||
case Opcode::DS_CMPST_RTN_B64:
|
||||
case Opcode::DS_AND_B32:
|
||||
case Opcode::DS_AND_RTN_B32:
|
||||
case Opcode::DS_OR_B32:
|
||||
@@ -211,6 +214,7 @@ uint32_t DsSourceCount(Opcode opcode) {
|
||||
case Opcode::DS_WRITE2ST64_B32:
|
||||
case Opcode::DS_WRITE2_B64:
|
||||
case Opcode::DS_WRITE2ST64_B64:
|
||||
case Opcode::DS_CMPST_RTN_B64:
|
||||
case Opcode::DS_MSKOR_B32: return 3u;
|
||||
case Opcode::DS_MIN_F32:
|
||||
case Opcode::DS_MAX_F32:
|
||||
|
||||
@@ -708,6 +708,8 @@ std::string InstructionToString(const Instruction& inst) {
|
||||
case Opcode::DS_MIN_RTN_U32:
|
||||
case Opcode::DS_MAX_U32:
|
||||
case Opcode::DS_MAX_RTN_U32:
|
||||
case Opcode::DS_MAX_RTN_U64:
|
||||
case Opcode::DS_CMPST_RTN_B64:
|
||||
case Opcode::DS_AND_B32:
|
||||
case Opcode::DS_AND_RTN_B32:
|
||||
case Opcode::DS_OR_B32:
|
||||
|
||||
@@ -624,6 +624,8 @@ enum class Opcode {
|
||||
DS_MIN_RTN_U32,
|
||||
DS_MAX_U32,
|
||||
DS_MAX_RTN_U32,
|
||||
DS_MAX_RTN_U64,
|
||||
DS_CMPST_RTN_B64,
|
||||
DS_AND_B32,
|
||||
DS_AND_RTN_B32,
|
||||
DS_OR_B32,
|
||||
|
||||
@@ -578,11 +578,13 @@ void Translator::DS_ATOMIC(const Decoder::Instruction& inst, IR::ValueOpcode opc
|
||||
bool returns_value) {
|
||||
const auto memory = MemoryInfoFromDecoded(inst);
|
||||
const auto address = ReadU32(inst.src0);
|
||||
const IR::Value value =
|
||||
memory.data_dwords == 2u ? IR::Value(ReadU64(inst.src1)) : IR::Value(ReadU32(inst.src1));
|
||||
const auto read = [&](const Decoder::Operand& operand) -> IR::Value {
|
||||
return memory.data_dwords == 2u ? IR::Value(ReadU64(operand)) : IR::Value(ReadU32(operand));
|
||||
};
|
||||
const auto value = read(inst.src1);
|
||||
const auto flags = AddMemoryInfo(memory, inst.pc);
|
||||
const auto result = inst.src_count == 3u
|
||||
? ir.Emit(opcode, {address, value, ReadU32(inst.src2), ir.GetExec()}, flags)
|
||||
? ir.Emit(opcode, {address, value, read(inst.src2), ir.GetExec()}, flags)
|
||||
: ir.Emit(opcode, {address, value, ir.GetExec()}, flags);
|
||||
if (returns_value) {
|
||||
WriteOperand(inst.dst, result);
|
||||
@@ -1073,6 +1075,10 @@ void Translator::EmitMemory(const Decoder::Instruction& inst) {
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicUMax32, false);
|
||||
case Decoder::Opcode::DS_MAX_RTN_U32:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicUMax32, true);
|
||||
case Decoder::Opcode::DS_MAX_RTN_U64:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicUMax64, true);
|
||||
case Decoder::Opcode::DS_CMPST_RTN_B64:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicCmpSwap64, true);
|
||||
case Decoder::Opcode::DS_AND_B32:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicAnd32, false);
|
||||
case Decoder::Opcode::DS_AND_RTN_B32:
|
||||
|
||||
@@ -948,9 +948,14 @@ void IncludeInstructionVectorRegisters(const Decoder::Instruction& inst, uint32_
|
||||
switch (inst.opcode) {
|
||||
case Decoder::Opcode::DS_ADD_U64:
|
||||
case Decoder::Opcode::DS_OR_B64:
|
||||
case Decoder::Opcode::DS_MAX_RTN_U64:
|
||||
case Decoder::Opcode::DS_WRITE_B64:
|
||||
case Decoder::Opcode::DS_WRITE_B96:
|
||||
case Decoder::Opcode::DS_WRITE_B128: include_vector(inst.src1, inst.data_dwords); break;
|
||||
case Decoder::Opcode::DS_CMPST_RTN_B64:
|
||||
include_vector(inst.src1, 2u);
|
||||
include_vector(inst.src2, 2u);
|
||||
break;
|
||||
case Decoder::Opcode::DS_WRITE2_B32:
|
||||
case Decoder::Opcode::DS_WRITE2ST64_B32:
|
||||
case Decoder::Opcode::DS_WRITE2_B64:
|
||||
|
||||
@@ -175,6 +175,8 @@ SharedAccess SharedAccessOf(ValueOpcode opcode) {
|
||||
case ValueOpcode::SharedAtomicUMin32:
|
||||
case ValueOpcode::SharedAtomicSMax32:
|
||||
case ValueOpcode::SharedAtomicUMax32:
|
||||
case ValueOpcode::SharedAtomicUMax64:
|
||||
case ValueOpcode::SharedAtomicCmpSwap64:
|
||||
case ValueOpcode::SharedAtomicAnd32:
|
||||
case ValueOpcode::SharedAtomicOr32:
|
||||
case ValueOpcode::SharedAtomicOr64:
|
||||
@@ -190,6 +192,8 @@ uint32_t SharedComponentCount(ValueOpcode opcode) {
|
||||
switch (opcode) {
|
||||
case ValueOpcode::SharedAtomicIAdd64:
|
||||
case ValueOpcode::SharedAtomicOr64:
|
||||
case ValueOpcode::SharedAtomicUMax64:
|
||||
case ValueOpcode::SharedAtomicCmpSwap64:
|
||||
case ValueOpcode::LoadSharedU32x2:
|
||||
case ValueOpcode::WriteSharedU32x2: return 2u;
|
||||
case ValueOpcode::LoadSharedU32x3:
|
||||
|
||||
@@ -303,6 +303,8 @@ VALUE_OPCODE(SharedAtomicSMin32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicUMin32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicSMax32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicUMax32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicUMax64, U64, U32, U64, U1)
|
||||
VALUE_OPCODE(SharedAtomicCmpSwap64, U64, U32, U64, U64, U1)
|
||||
VALUE_OPCODE(SharedAtomicAnd32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicOr32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicOr64, Void, U32, U64, U1)
|
||||
|
||||
Reference in New Issue
Block a user