Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,12 @@ constexpr std::uint64_t Sign = 0x8000000000000000ull;

bool Nan(std::uint64_t bits) { return (bits & ~Sign) > 0x7ff0000000000000ull; }
std::uint64_t OrderKey(std::uint64_t bits) { return (bits & Sign) != 0u ? ~bits : bits | Sign; }
constexpr std::uint64_t Quiet = 0x0008000000000000ull;

bool Signaling(std::uint64_t bits) { return Nan(bits) && (bits & Quiet) == 0u; }
std::uint64_t MinMax(std::uint64_t old, std::uint64_t data, bool max) {
if (Signaling(data)) return data | Quiet;
if (Signaling(old)) return old | Quiet;
if (Nan(old)) return data;
if (Nan(data)) return old;
return (max ? OrderKey(data) > OrderKey(old) : OrderKey(data) < OrderKey(old)) ? data : old;
Expand All @@ -114,7 +119,7 @@ void Fill(std::uint32_t tid, std::uint32_t* words) {
std::array<std::uint64_t, 3> values{};
if (kind == 0u) values = {seed, seed * 0xbf58476d1ce4e5b9ull, seed ^ 0x94d049bb133111ebull};
if (kind == 1u) values = {tid % 7u, (tid * 3u) % 7u, tid % 5u};
if (kind == 2u) values = {floats[tid % 12u], floats[(tid / 2u + 3u) % 12u], floats[(tid + 5u) % 12u]};
if (kind == 2u) values = {floats[tid % 12u], floats[(tid / 4u + 9u) % 12u], floats[(tid + 5u) % 12u]};
if (kind == 3u) values = {seed, (tid & 4u) != 0u ? seed : seed + 0x100000000ull, seed * 3u};
for (std::uint32_t i = 0; i < values.size(); ++i) {
words[i * 2u] = static_cast<std::uint32_t>(values[i]);
Expand Down
480 changes: 480 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/execution/LdsFloatAtomicModes.cpp

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct MemoryInfo {
bool planningOnly = false;
bool coherent = false;
bool gpuDescriptor = false;
bool flushDenormals = false;

bool operator==(const MemoryInfo& other) const = default;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,11 +611,15 @@ struct AtomicFloatBits {
std::uint64_t sign() const { return wide ? 0x8000000000000000ull : 0x80000000ull; }
std::uint64_t quiet() const { return wide ? 0x0008000000000000ull : 0x00400000ull; }
std::uint64_t infinity() const { return wide ? 0x7ff0000000000000ull : 0x7f800000ull; }
std::uint64_t minNormal() const { return wide ? 0x0010000000000000ull : 0x00800000ull; }
std::uint32_t op(spv::Op opcode, std::uint32_t lhs, std::uint32_t rhs) const { return Binary(state, opcode, type(), lhs, rhs); }
std::uint32_t test(spv::Op opcode, std::uint32_t lhs, std::uint32_t rhs) const { return Binary(state, opcode, TypeBool(state), lhs, rhs); }
std::uint32_t select(std::uint32_t condition, std::uint32_t lhs, std::uint32_t rhs) const { return Select(state, type(), condition, lhs, rhs); }
std::uint32_t magnitude(std::uint32_t value) const { return op(spv::OpBitwiseAnd, value, constant(sign() - 1u)); }
std::uint32_t nan(std::uint32_t value) const { return test(spv::OpUGreaterThan, magnitude(value), constant(infinity())); }
std::uint32_t flush(std::uint32_t value, bool enabled) const {
return enabled ? select(test(spv::OpULessThan, magnitude(value), constant(minNormal())), op(spv::OpBitwiseAnd, value, constant(sign())), value) : value;
}
std::uint32_t signalingNan(std::uint32_t value) const {
return Binary(state, spv::OpLogicalAnd, TypeBool(state), nan(value), test(spv::OpIEqual, op(spv::OpBitwiseAnd, value, constant(quiet())), constant(0u)));
}
Expand Down Expand Up @@ -683,19 +687,10 @@ std::uint32_t SharedAtomicUpdate(SpirvValueEmitContext& ctx, const IrValue& inst

std::uint32_t SharedFloatMinMax(SpirvValueEmitContext& ctx, const IrValue& inst, bool maxValue) {
const auto data = ctx.Arg(inst, 1);
const bool flush = SharedMemory(ctx, inst).flushDenormals;
return SharedAtomicUpdate(ctx, inst, [&](SpirvEmitterState& state, std::uint32_t old) {
const auto oldFloat = Unary(state, spv::OpBitcast, TypeF32(state), old);
const auto dataFloat = Unary(state, spv::OpBitcast, TypeF32(state), data);
const auto oldNan = Unary(state, spv::OpIsNan, TypeBool(state), oldFloat);
const auto dataNan = Unary(state, spv::OpIsNan, TypeBool(state), dataFloat);
const auto better = Binary(state, maxValue ? spv::OpFOrdGreaterThan : spv::OpFOrdLessThan, TypeBool(state), dataFloat, oldFloat);
const auto magnitudes = Binary(state, spv::OpBitwiseAnd, TypeU32(state), Binary(state, spv::OpBitwiseOr, TypeU32(state), old, data), ConstantU32(state, 0x7fffffffu));
const auto zeros = Binary(state, spv::OpIEqual, TypeBool(state), magnitudes, ConstantU32(state, 0u));
const auto zero = Binary(state, maxValue ? spv::OpBitwiseAnd : spv::OpBitwiseOr, TypeU32(state), old, data);
auto result = Select(state, TypeU32(state), better, data, old);
result = Select(state, TypeU32(state), zeros, zero, result);
result = Select(state, TypeU32(state), dataNan, old, result);
return Select(state, TypeU32(state), oldNan, data, result);
const AtomicFloatBits bits{state, false};
return bits.minMax(bits.flush(old, flush), bits.flush(data, flush), maxValue);
});
}

Expand Down Expand Up @@ -972,11 +967,10 @@ std::uint32_t SharedAtomic64Select(SpirvValueEmitContext& ctx, const IrValue& in
}

std::uint32_t SharedFloatMinMax64(SpirvValueEmitContext& ctx, const IrValue& inst, bool maxValue) {
const bool flush = SharedMemory(ctx, inst).flushDenormals;
return SharedAtomic64Binary(ctx, inst, [&](SpirvEmitterState& state, std::uint32_t old, std::uint32_t data) {
const AtomicFloatBits bits{state, true};
auto result = bits.select(bits.test(maxValue ? spv::OpUGreaterThan : spv::OpULessThan, bits.orderKey(data), bits.orderKey(old)), data, old);
result = bits.select(bits.nan(data), old, result);
return bits.select(bits.nan(old), data, result);
return bits.minMax(bits.flush(old, flush), bits.flush(data, flush), maxValue);
});
}

Expand Down Expand Up @@ -1373,9 +1367,10 @@ std::uint32_t EmitSharedAtomicCmpst32(SpirvValueEmitContext& ctx, const IrValue&
std::uint32_t EmitSharedAtomicCmpstF32(SpirvValueEmitContext& ctx, const IrValue& inst) {
const auto compare = ctx.Arg(inst, 1);
const auto source = ctx.Arg(inst, 2);
const bool flush = SharedMemory(ctx, inst).flushDenormals;
return SharedAtomicUpdate(ctx, inst, [&](SpirvEmitterState& state, std::uint32_t old) {
const auto equal = Binary(state, spv::OpFOrdEqual, TypeBool(state), Unary(state, spv::OpBitcast, TypeF32(state), old), Unary(state, spv::OpBitcast, TypeF32(state), compare));
return Select(state, TypeU32(state), equal, source, old);
const AtomicFloatBits bits{state, false};
return bits.select(bits.equal(bits.flush(old, flush), bits.flush(compare, flush)), source, old);
});
}

Expand Down Expand Up @@ -1475,9 +1470,10 @@ std::uint32_t EmitSharedAtomicCmpst64(SpirvValueEmitContext& ctx, const IrValue&
std::uint32_t EmitSharedAtomicCmpstF64(SpirvValueEmitContext& ctx, const IrValue& inst) {
const auto compare = ScalarU64Argument(ctx, inst, 3u);
const auto source = ScalarU64Argument(ctx, inst, 2u);
const bool flush = SharedMemory(ctx, inst).flushDenormals;
return SharedAtomic64(ctx, inst, [&](SpirvEmitterState& state, std::uint32_t old) {
const AtomicFloatBits bits{state, true};
return bits.select(bits.equal(old, compare), source, old);
return bits.select(bits.equal(bits.flush(old, flush), bits.flush(compare, flush)), source, old);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class TranslationContext {
bool dsWrite2(const RdnaInstruction& inst);
bool dsSrc2(const RdnaInstruction& inst, IrOpcode opcode);
bool dsAtomic2(const RdnaInstruction& inst, IrOpcode opcode, bool returnsValue);
bool sharedFloatFlush(IrOpcode opcode) const;
bool dsAtomic64(const RdnaInstruction& inst, IrOpcode opcode, bool returnsValue);
bool dsCondxchg32(const RdnaInstruction& inst);
bool dsAppendConsume(const RdnaInstruction& inst, IrOpcode opcode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ MemoryInfo sharedMemoryInfoFromInstruction(const RdnaInstruction& inst) {
}

bool TranslationContext::dsAtomic(const RdnaInstruction& inst, IrOpcode opcode, bool returnsValue) {
const MemoryInfo memory = sharedMemoryInfoFromInstruction(inst);
MemoryInfo memory = sharedMemoryInfoFromInstruction(inst);
memory.flushDenormals = sharedFloatFlush(opcode);
const IrU32 address = readU32(inst.source0);
const IrU32 value = readU32(inst.source1);
IrValue& active = ir.GetExec();
Expand Down Expand Up @@ -211,8 +212,24 @@ bool TranslationContext::dsSrc2(const RdnaInstruction& inst, IrOpcode opcode) {
return true;
}

bool TranslationContext::sharedFloatFlush(IrOpcode opcode) const {
switch (opcode) {
case IrOpcode::SharedAtomicFMin32:
case IrOpcode::SharedAtomicFMax32:
case IrOpcode::SharedAtomicCmpstF32:
return !floatMode.has_value() || ((floatMode->floatMode >> 4u) & 1u) == 0u;
case IrOpcode::SharedAtomicFMin64:
case IrOpcode::SharedAtomicFMax64:
case IrOpcode::SharedAtomicCmpstF64:
return floatMode.has_value() && ((floatMode->floatMode >> 6u) & 1u) == 0u;
default:
return false;
}
}

bool TranslationContext::dsAtomic2(const RdnaInstruction& inst, IrOpcode opcode, bool returnsValue) {
const MemoryInfo memory = sharedMemoryInfoFromInstruction(inst);
MemoryInfo memory = sharedMemoryInfoFromInstruction(inst);
memory.flushDenormals = sharedFloatFlush(opcode);
const IrU32 address = readU32(inst.source0);
const IrU32 data0 = readU32(inst.source1);
const IrU32 data1 = readU32(inst.source2);
Expand All @@ -226,7 +243,8 @@ bool TranslationContext::dsAtomic64(const RdnaInstruction& inst, IrOpcode opcode
if (inst.gds) {
throw std::runtime_error("64-bit GDS atomics are not supported");
}
const MemoryInfo memory = sharedMemoryInfoFromInstruction(inst);
MemoryInfo memory = sharedMemoryInfoFromInstruction(inst);
memory.flushDenormals = sharedFloatFlush(opcode);
const IrU32 address = readU32(inst.source0);
const IrU64 data0 = readU64(inst.source1);
IrValue& active = ir.GetExec();
Expand Down
Loading
Loading