diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h index 51cefcf86..dc9ed0aa5 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h @@ -62,7 +62,6 @@ EMIT_NATIVE(IMul32, OpIMul, U32, uint32_t, uint32_t) EMIT_NATIVE(UDiv32, OpUDiv, U32, uint32_t, uint32_t) EMIT_NATIVE(IAdd64, OpIAdd, U64, uint32_t, uint32_t) EMIT_NATIVE(ISub64, OpISub, U64, uint32_t, uint32_t) -EMIT_NATIVE(IAddCarry32, OpIAddCarry, U32x2, uint32_t, uint32_t) uint32_t EmitSMulHi(EmitterState& state, uint32_t arg0, uint32_t arg1); uint32_t EmitUMulHi(EmitterState& state, uint32_t arg0, uint32_t arg1); inline constexpr auto EmitIAbs32 = EmitGlsl; diff --git a/src/graphics/shader/recompiler/frontend/translate/Control.cpp b/src/graphics/shader/recompiler/frontend/translate/Control.cpp index e805ae6ff..36137bd10 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Control.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Control.cpp @@ -82,19 +82,17 @@ void Translator::S_SAVEEXEC(const Decoder::Instruction& inst, IR::ValueOpcode op } void Translator::ADD_U32(const Decoder::Instruction& inst, bool vector, bool use_carry_in) { - const auto zero = IR::U32(IR::Value(0u)); - const auto lhs = ReadU32(inst.src0); - const auto rhs = ReadU32(inst.src1); - const auto carry_in = !use_carry_in ? zero - : vector ? ConditionBit(inst.src2) - : ConditionBit(ConditionOperand(Decoder::OperandKind::Scc)); - const auto add0 = ir.Emit(IR::ValueOpcode::IAddCarry32, {lhs, rhs}); - const auto partial = ir.CompositeExtract(add0, 0); - const auto carry0 = ir.CompositeExtract(add0, 1); - const auto add1 = ir.Emit(IR::ValueOpcode::IAddCarry32, {partial, carry_in}); - const auto result = ir.CompositeExtract(add1, 0); - const auto carry1 = ir.CompositeExtract(add1, 1); - const auto carry = ir.INotEqual(ir.BitwiseOr(carry0, carry1), zero); + const auto lhs = ReadU32(inst.src0); + const auto rhs = ReadU32(inst.src1); + const auto partial = ir.IAdd(lhs, rhs); + auto result = partial; + auto carry = ir.ULessThan(partial, lhs); + if (use_carry_in) { + // The carry-in is 0 or 1, so the second add carries out only when it wraps to zero. + result = ir.IAdd(partial, vector ? ConditionBit(inst.src2) + : ConditionBit(ConditionOperand(Decoder::OperandKind::Scc))); + carry = ir.LogicalOr(carry, ir.ULessThan(result, partial)); + } WriteOperand(DestinationOperand(inst), result); if (vector) { WriteMask(inst.dst2, ir.LogicalAnd(ir.GetExec(), carry)); diff --git a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc index ff6a44c7e..6788ef3c7 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc +++ b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc @@ -97,7 +97,6 @@ VALUE_OPCODE(SelectU1, U1, U1, U1, U1) VALUE_OPCODE(SelectF32, F32, U1, F32, F32) VALUE_OPCODE(IAdd32, U32, U32, U32) VALUE_OPCODE(IAdd64, U64, U64, U64) -VALUE_OPCODE(IAddCarry32, U32x2, U32, U32) VALUE_OPCODE(ISub32, U32, U32, U32) VALUE_OPCODE(ISub64, U64, U64, U64) VALUE_OPCODE(IMul32, U32, U32, U32) diff --git a/src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp b/src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp index 44dba865e..e1273e8bd 100644 --- a/src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp @@ -244,17 +244,6 @@ bool FoldCompositeExtract(Inst& inst, ValueOpcode construct, size_t components) Replace(inst, producer->Arg(component)); return true; } - if (component < 2u && producer != nullptr && - producer->GetOpcode() == ValueOpcode::IAddCarry32) { - const auto lhs = producer->Arg(0).Resolve(); - const auto rhs = producer->Arg(1).Resolve(); - if (IsImmediate(lhs, Type::U32) && IsImmediate(rhs, Type::U32)) { - const auto sum = static_cast(lhs.U32()) + rhs.U32(); - Replace(inst, Value(component == 0u ? static_cast(sum) - : static_cast(sum >> 32u))); - return true; - } - } return false; } diff --git a/src/graphics/shader/recompiler/ir/passes/SrtWalker.cpp b/src/graphics/shader/recompiler/ir/passes/SrtWalker.cpp index e2f940f11..d4c712db4 100644 --- a/src/graphics/shader/recompiler/ir/passes/SrtWalker.cpp +++ b/src/graphics/shader/recompiler/ir/passes/SrtWalker.cpp @@ -134,7 +134,6 @@ bool IsRuntimeUniformOp(ValueOpcode op) { case ValueOpcode::BitFieldSExtract: case ValueOpcode::IAdd32: case ValueOpcode::IAdd64: - case ValueOpcode::IAddCarry32: case ValueOpcode::ISub32: case ValueOpcode::ISub64: case ValueOpcode::IMul32: @@ -338,9 +337,7 @@ private: const auto* source = inst->NumArgs() == 2 ? inst->Arg(0).ResolveInstruction() : nullptr; const auto index = inst->NumArgs() == 2 ? inst->Arg(1).Resolve() : Value {}; if (source == nullptr || !index.IsImmediate() || index.GetType() != Type::U32 || - index.U32() >= 2u || - (source->GetOpcode() != ValueOpcode::CompositeConstructU32x2 && - source->GetOpcode() != ValueOpcode::IAddCarry32)) { + index.U32() >= 2u || source->GetOpcode() != ValueOpcode::CompositeConstructU32x2) { return finish(false); } } @@ -653,18 +650,6 @@ bool SrtWalker::EvaluateExtract(const Inst& inst, uint64_t& result) { if (source->GetOpcode() == ValueOpcode::CompositeConstructU32x2) { return EvaluateWide(source->Arg(component), result); } - if (source->GetOpcode() == ValueOpcode::IAddCarry32) { - uint64_t lhs = 0; - uint64_t rhs = 0; - if (!Arg(*source, 0, lhs) || !Arg(*source, 1, rhs)) { - return false; - } - const auto sum = - static_cast(static_cast(lhs)) + static_cast(rhs); - result = - component == 0u ? static_cast(sum) : static_cast(sum >> 32u); - return true; - } return false; } diff --git a/tests/ScalarProvenanceTests.cpp b/tests/ScalarProvenanceTests.cpp index ac8540e81..3069829e6 100644 --- a/tests/ScalarProvenanceTests.cpp +++ b/tests/ScalarProvenanceTests.cpp @@ -237,12 +237,9 @@ void TestShaderBaseAndUserData() { void TestCarryAndBitFields() { Fixture fixture; - const auto carry = - fixture.Emit(ValueOpcode::IAddCarry32, {Value(0xffffffffu), Value(2u)}); - const auto low = - fixture.Emit(ValueOpcode::CompositeExtractU32x2, {carry, Value(0u)}); - const auto high = - fixture.Emit(ValueOpcode::CompositeExtractU32x2, {carry, Value(1u)}); + const auto low = fixture.Emit(ValueOpcode::IAdd32, {Value(0xffffffffu), Value(2u)}); + const auto carry = fixture.Emit(ValueOpcode::ULessThan32, {low, Value(0xffffffffu)}); + const auto high = fixture.Emit(ValueOpcode::SelectU32, {carry, Value(1u), Value(0u)}); const auto inserted = fixture.Emit(ValueOpcode::BitFieldInsert, {Value(0u), Value(0x89abcdefu), Value(0u), Value(32u)}); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 55d1351fb..87445e15a 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -25806,7 +25806,7 @@ TestCase VectorAddcWritesPerLaneCarryOut() { O::S_ENDPGM}; test.decoded_counts = { {"V_ADDC_U32 v2, vcc_lo, 0, v26.sdwa(sel=4,sext=1), vcc_lo", 1}}; - test.ir_counts = {{" = BitFieldSExtract ", 1}, {" = IAddCarry32 ", 2}}; + test.ir_counts = {{" = BitFieldSExtract ", 1}, {" = ULessThan32 ", 3}}; test.required_spirv = {"OpBitFieldSExtract"}; test.compute_info.threads_num[0] = 4; test.compute_info.threads_num[1] = 1; diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index e546262e6..965f182ea 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -15144,7 +15144,7 @@ void TestTypedDescriptorRealCarryAndScalarLoads() { ValueDependsOn(carry_source->dwords[1], ShaderRecompiler::IR::ValueOpcode::GetShaderBase) && ValueDependsOn(carry_source->dwords[1], - ShaderRecompiler::IR::ValueOpcode::IAddCarry32), + ShaderRecompiler::IR::ValueOpcode::ULessThan32), "real s_add_u32/s_addc_u32 translation lost SCC carry provenance"); std::array carry_user_data{}; const uint64_t shader_base = 0x00000012fffffffbull;