mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 03:46:53 +02:00
shader: share one find-first-bit lowering for S_FF0/FF1/FLBIT_I32_B64 and remove FindUMsb64
This commit is contained in:
@@ -5,18 +5,6 @@
|
|||||||
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct Pair {
|
|
||||||
uint32_t low = 0;
|
|
||||||
uint32_t high = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Pair ExtractPair(EmitterState& state, uint32_t value) {
|
|
||||||
Pair result {state.builder.AllocateId(), state.builder.AllocateId()};
|
|
||||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), result.low, value, 0);
|
|
||||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), result.high, value, 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t EmitMinMaxF64(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) {
|
uint32_t EmitMinMaxF64(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) {
|
||||||
const auto bits_type = TypeU32Vector(state, 2);
|
const auto bits_type = TypeU32Vector(state, 2);
|
||||||
const auto lhs_bits = Unary(state, spv::OpBitcast, bits_type, lhs);
|
const auto lhs_bits = Unary(state, spv::OpBitcast, bits_type, lhs);
|
||||||
@@ -160,18 +148,6 @@ uint32_t EmitFPMad32(EmitterState& state, uint32_t a, uint32_t b, uint32_t c) {
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t EmitFindUMsb64(EmitterState& state, uint32_t value) {
|
|
||||||
// GLSL FindUMsb is restricted to 32-bit components.
|
|
||||||
const auto unpacked = Unary(state, spv::OpBitcast, TypeU32Vector(state, 2), value);
|
|
||||||
const auto pair =
|
|
||||||
ExtractPair(state, EmitExt(state, TypeU32Vector(state, 2), GLSLstd450FindUMsb, {unpacked}));
|
|
||||||
const auto high_found =
|
|
||||||
Binary(state, spv::OpINotEqual, TypeBool(state), pair.high, ConstantU32(state, UINT32_MAX));
|
|
||||||
return Select(state, TypeU32(state), high_found,
|
|
||||||
Binary(state, spv::OpIAdd, TypeU32(state), pair.high, ConstantU32(state, 32)),
|
|
||||||
pair.low);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t EmitConvertU16U32(EmitterState& state, uint32_t arg0) {
|
uint32_t EmitConvertU16U32(EmitterState& state, uint32_t arg0) {
|
||||||
return EmitNative<spv::OpBitwiseAnd, IR::Type::U16>(state, arg0, ConstantU32(state, 0xffffu));
|
return EmitNative<spv::OpBitwiseAnd, IR::Type::U16>(state, arg0, ConstantU32(state, 0xffffu));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ EMIT_NATIVE(BitReverse32, OpBitReverse, U32, uint32_t)
|
|||||||
EMIT_NATIVE(BitCount32, OpBitCount, U32, uint32_t)
|
EMIT_NATIVE(BitCount32, OpBitCount, U32, uint32_t)
|
||||||
inline constexpr auto EmitFindILsb32 = EmitGlsl<GLSLstd450FindILsb, IR::Type::U32, uint32_t>;
|
inline constexpr auto EmitFindILsb32 = EmitGlsl<GLSLstd450FindILsb, IR::Type::U32, uint32_t>;
|
||||||
inline constexpr auto EmitFindUMsb32 = EmitGlsl<GLSLstd450FindUMsb, IR::Type::U32, uint32_t>;
|
inline constexpr auto EmitFindUMsb32 = EmitGlsl<GLSLstd450FindUMsb, IR::Type::U32, uint32_t>;
|
||||||
uint32_t EmitFindUMsb64(EmitterState& state, uint32_t arg0);
|
|
||||||
inline constexpr auto EmitSMin32 = EmitGlsl<GLSLstd450SMin, IR::Type::U32, uint32_t, uint32_t>;
|
inline constexpr auto EmitSMin32 = EmitGlsl<GLSLstd450SMin, IR::Type::U32, uint32_t, uint32_t>;
|
||||||
inline constexpr auto EmitSMax32 = EmitGlsl<GLSLstd450SMax, IR::Type::U32, uint32_t, uint32_t>;
|
inline constexpr auto EmitSMax32 = EmitGlsl<GLSLstd450SMax, IR::Type::U32, uint32_t, uint32_t>;
|
||||||
inline constexpr auto EmitUMin32 = EmitGlsl<GLSLstd450UMin, IR::Type::U32, uint32_t, uint32_t>;
|
inline constexpr auto EmitUMin32 = EmitGlsl<GLSLstd450UMin, IR::Type::U32, uint32_t, uint32_t>;
|
||||||
|
|||||||
@@ -221,19 +221,21 @@ void Translator::V_XOR3_B32(const Decoder::Instruction& inst) {
|
|||||||
WriteOperand(DestinationOperand(inst), result);
|
WriteOperand(DestinationOperand(inst), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero) {
|
void Translator::S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero, bool from_msb) {
|
||||||
auto source = ReadU32Pair(inst.src0);
|
auto source = ReadU32Pair(inst.src0);
|
||||||
if (find_zero) {
|
for (auto& word: source) {
|
||||||
source[0] = ir.BitwiseNot(source[0]);
|
word = find_zero ? ir.BitwiseNot(word) : word;
|
||||||
source[1] = ir.BitwiseNot(source[1]);
|
|
||||||
}
|
}
|
||||||
const auto low_lsb = IR::U32(ir.Emit(IR::ValueOpcode::FindILsb32, {source[0]}));
|
if (from_msb) {
|
||||||
const auto high_lsb = IR::U32(ir.Emit(IR::ValueOpcode::FindILsb32, {source[1]}));
|
// The leading bit index is the trailing bit index of the bit-reversed 64-bit value.
|
||||||
const auto high_position = ir.IAdd(high_lsb, IR::U32(IR::Value(32u)));
|
source = {IR::U32(ir.Emit(IR::ValueOpcode::BitReverse32, {source[1]})),
|
||||||
const auto result = ir.Select(ir.INotEqual(source[0], IR::U32(IR::Value(0u))), low_lsb,
|
IR::U32(ir.Emit(IR::ValueOpcode::BitReverse32, {source[0]}))};
|
||||||
ir.Select(ir.INotEqual(source[1], IR::U32(IR::Value(0u))),
|
}
|
||||||
high_position, IR::U32(IR::Value(0xffffffffu))));
|
// FindILsb returns ~0 for zero, so OR-ing 32 keeps a missing high bit at ~0 (-1).
|
||||||
WriteOperand(DestinationOperand(inst), result);
|
const auto low = ir.Emit(IR::ValueOpcode::FindILsb32, {source[0]});
|
||||||
|
const auto high = ir.BitwiseOr(IR::U32(ir.Emit(IR::ValueOpcode::FindILsb32, {source[1]})),
|
||||||
|
IR::U32(IR::Value(32u)));
|
||||||
|
WriteOperand(DestinationOperand(inst), ir.Emit(IR::ValueOpcode::UMin32, {low, high}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::V_FFBH_32(const Decoder::Instruction& inst, bool sign) {
|
void Translator::V_FFBH_32(const Decoder::Instruction& inst, bool sign) {
|
||||||
@@ -248,17 +250,6 @@ void Translator::V_FFBH_32(const Decoder::Instruction& inst, bool sign) {
|
|||||||
WriteOperand(DestinationOperand(inst), result);
|
WriteOperand(DestinationOperand(inst), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::S_FLBIT_I32_B64(const Decoder::Instruction& inst) {
|
|
||||||
const auto source = ReadU64(inst.src0);
|
|
||||||
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb64, {source}));
|
|
||||||
const auto position = ir.ISub(IR::U32(IR::Value(63u)), msb);
|
|
||||||
const auto nonzero =
|
|
||||||
IR::U1(ir.Emit(IR::ValueOpcode::INotEqual64,
|
|
||||||
{source, ir.ConstructU64(IR::U32(IR::Value(0u)), IR::U32(IR::Value(0u)))}));
|
|
||||||
const auto result = ir.Select(nonzero, position, IR::U32(IR::Value(0xffffffffu)));
|
|
||||||
WriteOperand(DestinationOperand(inst), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Translator::Integer24(const Decoder::Instruction& inst, bool sign, bool addend) {
|
void Translator::Integer24(const Decoder::Instruction& inst, bool sign, bool addend) {
|
||||||
const auto extract24 = [&](IR::U32 value) {
|
const auto extract24 = [&](IR::U32 value) {
|
||||||
return IR::U32(
|
return IR::U32(
|
||||||
|
|||||||
@@ -238,10 +238,10 @@ void Translator::EmitScalar(const Decoder::Instruction& inst) {
|
|||||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseOr32, false, true, true);
|
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseOr32, false, true, true);
|
||||||
case O::S_XNOR_B32:
|
case O::S_XNOR_B32:
|
||||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseXor32, false, true, true);
|
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseXor32, false, true, true);
|
||||||
case O::S_FF0_I32_B64: return S_FF_I32_B64(inst, true);
|
case O::S_FF0_I32_B64: return S_FF_I32_B64(inst, true, false);
|
||||||
case O::S_FF1_I32_B64: return S_FF_I32_B64(inst, false);
|
case O::S_FF1_I32_B64: return S_FF_I32_B64(inst, false, false);
|
||||||
case O::S_FLBIT_I32_B32: return V_FFBH_32(inst, false);
|
case O::S_FLBIT_I32_B32: return V_FFBH_32(inst, false);
|
||||||
case O::S_FLBIT_I32_B64: return S_FLBIT_I32_B64(inst);
|
case O::S_FLBIT_I32_B64: return S_FF_I32_B64(inst, false, true);
|
||||||
|
|
||||||
case O::S_BITSET0_B32: return S_BITSET_B32(inst, false);
|
case O::S_BITSET0_B32: return S_BITSET_B32(inst, false);
|
||||||
case O::S_BITSET1_B32: return S_BITSET_B32(inst, true);
|
case O::S_BITSET1_B32: return S_BITSET_B32(inst, true);
|
||||||
|
|||||||
@@ -187,9 +187,8 @@ private:
|
|||||||
void V_AND_OR_B32(const Decoder::Instruction& inst);
|
void V_AND_OR_B32(const Decoder::Instruction& inst);
|
||||||
void V_OR3_B32(const Decoder::Instruction& inst);
|
void V_OR3_B32(const Decoder::Instruction& inst);
|
||||||
void V_XOR3_B32(const Decoder::Instruction& inst);
|
void V_XOR3_B32(const Decoder::Instruction& inst);
|
||||||
void S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero);
|
void S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero, bool from_msb);
|
||||||
void V_FFBH_32(const Decoder::Instruction& inst, bool sign);
|
void V_FFBH_32(const Decoder::Instruction& inst, bool sign);
|
||||||
void S_FLBIT_I32_B64(const Decoder::Instruction& inst);
|
|
||||||
void Integer24(const Decoder::Instruction& inst, bool sign, bool addend);
|
void Integer24(const Decoder::Instruction& inst, bool sign, bool addend);
|
||||||
void V_MAD_U64_U32(const Decoder::Instruction& inst);
|
void V_MAD_U64_U32(const Decoder::Instruction& inst);
|
||||||
void V_SAD_U32(const Decoder::Instruction& inst);
|
void V_SAD_U32(const Decoder::Instruction& inst);
|
||||||
|
|||||||
@@ -118,7 +118,6 @@ VALUE_OPCODE(BitwiseNot32, U32, U32)
|
|||||||
VALUE_OPCODE(BitReverse32, U32, U32)
|
VALUE_OPCODE(BitReverse32, U32, U32)
|
||||||
VALUE_OPCODE(BitCount32, U32, U32)
|
VALUE_OPCODE(BitCount32, U32, U32)
|
||||||
VALUE_OPCODE(FindUMsb32, U32, U32)
|
VALUE_OPCODE(FindUMsb32, U32, U32)
|
||||||
VALUE_OPCODE(FindUMsb64, U32, U64)
|
|
||||||
VALUE_OPCODE(FindILsb32, U32, U32)
|
VALUE_OPCODE(FindILsb32, U32, U32)
|
||||||
VALUE_OPCODE(SMin32, U32, U32, U32)
|
VALUE_OPCODE(SMin32, U32, U32, U32)
|
||||||
VALUE_OPCODE(UMin32, U32, U32, U32)
|
VALUE_OPCODE(UMin32, U32, U32, U32)
|
||||||
|
|||||||
@@ -651,10 +651,15 @@ void FoldInstruction(Block& block, Block::iterator instruction,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case ValueOpcode::BitCount32: {
|
case ValueOpcode::BitCount32:
|
||||||
|
case ValueOpcode::FindILsb32: {
|
||||||
const auto value = Arg(inst, 0);
|
const auto value = Arg(inst, 0);
|
||||||
if (IsImmediate(value, Type::U32)) {
|
if (IsImmediate(value, Type::U32)) {
|
||||||
Replace(inst, Value(static_cast<uint32_t>(std::popcount(value.U32()))));
|
const auto bits = value.U32();
|
||||||
|
Replace(inst, Value(static_cast<uint32_t>(
|
||||||
|
inst.GetOpcode() == ValueOpcode::BitCount32 ? std::popcount(bits)
|
||||||
|
: bits == 0u ? -1
|
||||||
|
: std::countr_zero(bits))));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -667,7 +672,9 @@ void FoldInstruction(Block& block, Block::iterator instruction,
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
case ValueOpcode::UMin32:
|
case ValueOpcode::UMin32:
|
||||||
FoldU32(inst, [](uint32_t a, uint32_t b) { return std::min(a, b); });
|
if (!FoldU32(inst, [](uint32_t a, uint32_t b) { return std::min(a, b); })) {
|
||||||
|
ReplaceBinaryIdentity(inst, Type::U32, ~0u);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case ValueOpcode::UMax32:
|
case ValueOpcode::UMax32:
|
||||||
FoldU32(inst, [](uint32_t a, uint32_t b) { return std::max(a, b); });
|
FoldU32(inst, [](uint32_t a, uint32_t b) { return std::max(a, b); });
|
||||||
|
|||||||
Reference in New Issue
Block a user