diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp index 9a2ae8d14..5076e255c 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp @@ -5,18 +5,6 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { 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) { const auto bits_type = TypeU32Vector(state, 2); 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; } -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) { return EmitNative(state, arg0, ConstantU32(state, 0xffffu)); } diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h index dc9ed0aa5..528f22dd5 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h @@ -92,7 +92,6 @@ EMIT_NATIVE(BitReverse32, OpBitReverse, U32, uint32_t) EMIT_NATIVE(BitCount32, OpBitCount, U32, uint32_t) inline constexpr auto EmitFindILsb32 = EmitGlsl; inline constexpr auto EmitFindUMsb32 = EmitGlsl; -uint32_t EmitFindUMsb64(EmitterState& state, uint32_t arg0); inline constexpr auto EmitSMin32 = EmitGlsl; inline constexpr auto EmitSMax32 = EmitGlsl; inline constexpr auto EmitUMin32 = EmitGlsl; diff --git a/src/graphics/shader/recompiler/frontend/translate/Integer.cpp b/src/graphics/shader/recompiler/frontend/translate/Integer.cpp index 2a1532d14..ffa2a92e1 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Integer.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Integer.cpp @@ -221,19 +221,21 @@ void Translator::V_XOR3_B32(const Decoder::Instruction& inst) { 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); - if (find_zero) { - source[0] = ir.BitwiseNot(source[0]); - source[1] = ir.BitwiseNot(source[1]); + for (auto& word: source) { + word = find_zero ? ir.BitwiseNot(word) : word; } - const auto low_lsb = IR::U32(ir.Emit(IR::ValueOpcode::FindILsb32, {source[0]})); - const auto high_lsb = IR::U32(ir.Emit(IR::ValueOpcode::FindILsb32, {source[1]})); - const auto high_position = ir.IAdd(high_lsb, IR::U32(IR::Value(32u))); - const auto result = ir.Select(ir.INotEqual(source[0], IR::U32(IR::Value(0u))), low_lsb, - ir.Select(ir.INotEqual(source[1], IR::U32(IR::Value(0u))), - high_position, IR::U32(IR::Value(0xffffffffu)))); - WriteOperand(DestinationOperand(inst), result); + if (from_msb) { + // The leading bit index is the trailing bit index of the bit-reversed 64-bit value. + source = {IR::U32(ir.Emit(IR::ValueOpcode::BitReverse32, {source[1]})), + IR::U32(ir.Emit(IR::ValueOpcode::BitReverse32, {source[0]}))}; + } + // FindILsb returns ~0 for zero, so OR-ing 32 keeps a missing high bit at ~0 (-1). + 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) { @@ -248,17 +250,6 @@ void Translator::V_FFBH_32(const Decoder::Instruction& inst, bool sign) { 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) { const auto extract24 = [&](IR::U32 value) { return IR::U32( diff --git a/src/graphics/shader/recompiler/frontend/translate/Scalar.cpp b/src/graphics/shader/recompiler/frontend/translate/Scalar.cpp index abbca7f83..bb89d1c92 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Scalar.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Scalar.cpp @@ -238,10 +238,10 @@ void Translator::EmitScalar(const Decoder::Instruction& inst) { return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseOr32, false, true, true); case O::S_XNOR_B32: 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_FF1_I32_B64: return S_FF_I32_B64(inst, false); + 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, 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_BITSET1_B32: return S_BITSET_B32(inst, true); diff --git a/src/graphics/shader/recompiler/frontend/translate/Translator.h b/src/graphics/shader/recompiler/frontend/translate/Translator.h index b3e95a5c3..eb8c14770 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Translator.h +++ b/src/graphics/shader/recompiler/frontend/translate/Translator.h @@ -187,9 +187,8 @@ private: void V_AND_OR_B32(const Decoder::Instruction& inst); void V_OR3_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 S_FLBIT_I32_B64(const Decoder::Instruction& inst); void Integer24(const Decoder::Instruction& inst, bool sign, bool addend); void V_MAD_U64_U32(const Decoder::Instruction& inst); void V_SAD_U32(const Decoder::Instruction& inst); diff --git a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc index 6788ef3c7..c9a3408a0 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc +++ b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc @@ -118,7 +118,6 @@ VALUE_OPCODE(BitwiseNot32, U32, U32) VALUE_OPCODE(BitReverse32, U32, U32) VALUE_OPCODE(BitCount32, U32, U32) VALUE_OPCODE(FindUMsb32, U32, U32) -VALUE_OPCODE(FindUMsb64, U32, U64) VALUE_OPCODE(FindILsb32, U32, U32) VALUE_OPCODE(SMin32, U32, U32, U32) VALUE_OPCODE(UMin32, U32, U32, U32) diff --git a/src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp b/src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp index e1273e8bd..7e516cf7d 100644 --- a/src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp @@ -651,10 +651,15 @@ void FoldInstruction(Block& block, Block::iterator instruction, } return; } - case ValueOpcode::BitCount32: { + case ValueOpcode::BitCount32: + case ValueOpcode::FindILsb32: { const auto value = Arg(inst, 0); if (IsImmediate(value, Type::U32)) { - Replace(inst, Value(static_cast(std::popcount(value.U32())))); + const auto bits = value.U32(); + Replace(inst, Value(static_cast( + inst.GetOpcode() == ValueOpcode::BitCount32 ? std::popcount(bits) + : bits == 0u ? -1 + : std::countr_zero(bits)))); } return; } @@ -667,7 +672,9 @@ void FoldInstruction(Block& block, Block::iterator instruction, }); return; 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; case ValueOpcode::UMax32: FoldU32(inst, [](uint32_t a, uint32_t b) { return std::max(a, b); });