mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
shader: implement DS_INC_RTN_U32 and DS_DEC_RTN_U32
This commit is contained in:
@@ -589,31 +589,58 @@ uint32_t EmitAtomicOperation(ValueEmitContext& ctx, const IR::Inst& inst, uint32
|
||||
return old;
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
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 access = PrepareMemoryElement(ctx, mem, DwordIndex(ctx, inst, mem));
|
||||
return EmitValueOrZeroIfCondition(
|
||||
ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() {
|
||||
return operation(EmitMemoryElementPointer(ctx.state, access.resource, access.index));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t EmitAtomic(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem) {
|
||||
const auto result =
|
||||
EmitValueOrZeroIfCondition(ctx.state, ctx.Arg(inst, inst.NumArgs() - 1), [&]() {
|
||||
const auto access = PrepareMemoryElement(ctx, mem, DwordIndex(ctx, inst, mem));
|
||||
return EmitValueOrZeroIfCondition(
|
||||
ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index),
|
||||
[&]() {
|
||||
const auto scope =
|
||||
mem.kind == IR::ResourceKind::Lds ? ScopeWorkgroup : ScopeDevice;
|
||||
const auto pointer =
|
||||
EmitMemoryElementPointer(ctx.state, access.resource, access.index);
|
||||
const auto old = EmitAtomicOperation(ctx, inst, pointer, scope);
|
||||
if (mem.kind == IR::ResourceKind::Lds) {
|
||||
const auto semantics =
|
||||
MemorySemanticsAcquireRelease | MemorySemanticsWorkgroupMemory;
|
||||
ctx.state.builder.AddFunction({OpMemoryBarrier,
|
||||
ConstantU32(ctx.state, ScopeWorkgroup),
|
||||
ConstantU32(ctx.state, semantics)});
|
||||
} else {
|
||||
EmitDeviceAtomicMemoryBarrier(ctx.state);
|
||||
}
|
||||
return old;
|
||||
});
|
||||
});
|
||||
return result;
|
||||
return EmitAtomicAccess(ctx, inst, mem, [&](uint32_t pointer) {
|
||||
const auto scope = mem.kind == IR::ResourceKind::Lds ? ScopeWorkgroup : ScopeDevice;
|
||||
const auto old = EmitAtomicOperation(ctx, inst, pointer, scope);
|
||||
if (mem.kind == IR::ResourceKind::Lds) {
|
||||
const auto semantics = MemorySemanticsAcquireRelease | MemorySemanticsWorkgroupMemory;
|
||||
ctx.state.builder.AddFunction({OpMemoryBarrier, ConstantU32(ctx.state, scope),
|
||||
ConstantU32(ctx.state, semantics)});
|
||||
} else {
|
||||
EmitDeviceAtomicMemoryBarrier(ctx.state);
|
||||
}
|
||||
return old;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
uint32_t EmitAtomicUpdate(ValueEmitContext& ctx, const IR::Inst& inst,
|
||||
const IR::MemoryInfo& mem, Fn&& replacement) {
|
||||
const auto value = ctx.Arg(inst, inst.NumArgs() - 2);
|
||||
return EmitAtomicAccess(ctx, inst, mem, [&](uint32_t pointer) {
|
||||
return AtomicUpdate(ctx.state, pointer, mem.kind, [&](uint32_t old) {
|
||||
return replacement(ctx.state, old, value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t AtomicIncrement(EmitterState& state, uint32_t old, uint32_t limit) {
|
||||
// old >= limit ? 0 : old + 1 (unsigned).
|
||||
const auto wrap = Binary(state, OpUGreaterThanEqual, TypeBool(state), old, limit);
|
||||
const auto next = Binary(state, OpIAdd, TypeU32(state), old, ConstantU32(state, 1));
|
||||
return Select(state, TypeU32(state), wrap, ConstantU32(state, 0), next);
|
||||
}
|
||||
|
||||
uint32_t AtomicDecrement(EmitterState& state, uint32_t old, uint32_t limit) {
|
||||
// old == 0 || old > limit ? limit : old - 1 (unsigned).
|
||||
const auto zero = Binary(state, OpIEqual, TypeBool(state), old, ConstantU32(state, 0));
|
||||
const auto above = Binary(state, OpUGreaterThan, TypeBool(state), old, limit);
|
||||
const auto wrap = Binary(state, OpLogicalOr, TypeBool(state), zero, above);
|
||||
const auto next = Binary(state, OpISub, TypeU32(state), old, ConstantU32(state, 1));
|
||||
return Select(state, TypeU32(state), wrap, limit, next);
|
||||
}
|
||||
|
||||
uint32_t EmitBufferAtomic64(ValueEmitContext& ctx, const IR::Inst& inst,
|
||||
@@ -647,17 +674,9 @@ uint32_t EmitBufferAtomic64(ValueEmitContext& ctx, const IR::Inst& inst,
|
||||
|
||||
uint32_t FloatAtomic(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem,
|
||||
bool max_value) {
|
||||
return EmitValueOrZeroIfCondition(ctx.state, ctx.Arg(inst, inst.NumArgs() - 1), [&]() {
|
||||
const auto access = PrepareMemoryElement(ctx, mem, DwordIndex(ctx, inst, mem));
|
||||
return EmitValueOrZeroIfCondition(
|
||||
ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() {
|
||||
const auto pointer =
|
||||
EmitMemoryElementPointer(ctx.state, access.resource, access.index);
|
||||
const auto source = ctx.Arg(inst, inst.NumArgs() - 2);
|
||||
return AtomicUpdate(ctx.state, pointer, mem.kind, [&](uint32_t old) {
|
||||
return EmitFloatAtomicReplacement(ctx.state, old, source, max_value);
|
||||
});
|
||||
});
|
||||
return EmitAtomicUpdate(ctx, inst, mem, [max_value](EmitterState& state, uint32_t old,
|
||||
uint32_t value) {
|
||||
return EmitFloatAtomicReplacement(state, old, value, max_value);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1138,6 +1157,12 @@ bool EmitValueMemory(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
op == IR::ValueOpcode::BufferAtomicFMax32));
|
||||
return true;
|
||||
}
|
||||
if (op == IR::ValueOpcode::SharedAtomicInc32 || op == IR::ValueOpcode::SharedAtomicDec32) {
|
||||
const auto replacement = op == IR::ValueOpcode::SharedAtomicInc32
|
||||
? AtomicIncrement : AtomicDecrement;
|
||||
ctx.Define(inst, EmitAtomicUpdate(ctx, inst, ctx.Memory(inst), replacement));
|
||||
return true;
|
||||
}
|
||||
if (op == IR::ValueOpcode::SharedAtomicFMin32 || op == IR::ValueOpcode::SharedAtomicFMax32) {
|
||||
SharedFloatAtomic(ctx, inst, ctx.Memory(inst), op == IR::ValueOpcode::SharedAtomicFMax32);
|
||||
return true;
|
||||
|
||||
@@ -94,6 +94,7 @@ constexpr MemoryOpcodeInfo DS_OPCODE_LIST[] = {
|
||||
{0x12u, Opcode::DS_MIN_F32, 1, 32}, {0x13u, Opcode::DS_MAX_F32, 1, 32},
|
||||
{0x1eu, Opcode::DS_WRITE_B8, 1, 8}, {0x1fu, Opcode::DS_WRITE_B16, 1, 16},
|
||||
{0x20u, Opcode::DS_ADD_RTN_U32, 1, 32}, {0x21u, Opcode::DS_SUB_RTN_U32, 1, 32},
|
||||
{0x23u, Opcode::DS_INC_RTN_U32, 1, 32}, {0x24u, Opcode::DS_DEC_RTN_U32, 1, 32},
|
||||
{0x25u, Opcode::DS_MIN_RTN_I32, 1, 32}, {0x26u, Opcode::DS_MAX_RTN_I32, 1, 32},
|
||||
{0x27u, Opcode::DS_MIN_RTN_U32, 1, 32}, {0x28u, Opcode::DS_MAX_RTN_U32, 1, 32},
|
||||
{0x29u, Opcode::DS_AND_RTN_B32, 1, 32}, {0x2au, Opcode::DS_OR_RTN_B32, 1, 32},
|
||||
@@ -165,6 +166,8 @@ bool IsDsAtomicOpcode(Opcode opcode) {
|
||||
case Opcode::DS_ADD_RTN_U32:
|
||||
case Opcode::DS_SUB_U32:
|
||||
case Opcode::DS_SUB_RTN_U32:
|
||||
case Opcode::DS_INC_RTN_U32:
|
||||
case Opcode::DS_DEC_RTN_U32:
|
||||
case Opcode::DS_MIN_I32:
|
||||
case Opcode::DS_MIN_RTN_I32:
|
||||
case Opcode::DS_MAX_I32:
|
||||
|
||||
@@ -626,6 +626,8 @@ std::string InstructionToString(const Instruction& inst) {
|
||||
case Opcode::DS_ADD_RTN_U32:
|
||||
case Opcode::DS_SUB_U32:
|
||||
case Opcode::DS_SUB_RTN_U32:
|
||||
case Opcode::DS_INC_RTN_U32:
|
||||
case Opcode::DS_DEC_RTN_U32:
|
||||
case Opcode::DS_MIN_I32:
|
||||
case Opcode::DS_MIN_RTN_I32:
|
||||
case Opcode::DS_MAX_I32:
|
||||
|
||||
@@ -488,6 +488,8 @@ enum class Opcode {
|
||||
DS_ADD_RTN_U32,
|
||||
DS_SUB_U32,
|
||||
DS_SUB_RTN_U32,
|
||||
DS_INC_RTN_U32,
|
||||
DS_DEC_RTN_U32,
|
||||
DS_MIN_I32,
|
||||
DS_MIN_RTN_I32,
|
||||
DS_MAX_I32,
|
||||
|
||||
@@ -968,6 +968,10 @@ bool Translator::EmitMemory(const Decoder::Instruction& inst) {
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicISub32, false);
|
||||
case Decoder::Opcode::DS_SUB_RTN_U32:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicISub32, true);
|
||||
case Decoder::Opcode::DS_INC_RTN_U32:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicInc32, true);
|
||||
case Decoder::Opcode::DS_DEC_RTN_U32:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicDec32, true);
|
||||
case Decoder::Opcode::DS_MIN_I32:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicSMin32, false);
|
||||
case Decoder::Opcode::DS_MIN_RTN_I32:
|
||||
|
||||
@@ -163,6 +163,8 @@ SharedAccess SharedAccessOf(ValueOpcode opcode) {
|
||||
case ValueOpcode::SharedAtomicSwap32:
|
||||
case ValueOpcode::SharedAtomicIAdd32:
|
||||
case ValueOpcode::SharedAtomicISub32:
|
||||
case ValueOpcode::SharedAtomicInc32:
|
||||
case ValueOpcode::SharedAtomicDec32:
|
||||
case ValueOpcode::SharedAtomicSMin32:
|
||||
case ValueOpcode::SharedAtomicUMin32:
|
||||
case ValueOpcode::SharedAtomicSMax32:
|
||||
|
||||
@@ -255,6 +255,8 @@ VALUE_OPCODE(SharedAtomicFMax32, Void, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicSwap32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicIAdd32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicISub32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicInc32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicDec32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicSMin32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicUMin32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(SharedAtomicSMax32, U32, U32, U32, U1)
|
||||
|
||||
Reference in New Issue
Block a user