diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp index 4b6d29a4d..69bcd9510 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp @@ -115,6 +115,21 @@ DEF_OP(AdcWithFlags) { adcs(ConvertSize48(IROp), GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID())); } +DEF_OP(AdcZeroWithFlags) { + auto Op = IROp->C(); + auto Size = ConvertSize48(IROp); + + cset(Size, TMP1, ARMEmitter::Condition::CC_CC); + adds(Size, GetReg(Node), GetReg(Op->Src1.ID()), TMP1); +} + +DEF_OP(AdcZero) { + auto Op = IROp->C(); + auto Size = ConvertSize48(IROp); + + cinc(Size, GetReg(Node), GetReg(Op->Src1.ID()), ARMEmitter::Condition::CC_CC); +} + DEF_OP(Adc) { auto Op = IROp->C(); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 55e76b967..9ac6a881f 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -302,7 +302,18 @@ void OpDispatchBuilder::ADCOp(OpcodeArgs) { Before = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); } - Ref Result = CalculateFlags_ADC(Size, Before, Src); + Ref Result; + if (!DestIsLockedMem(Op) && Op->Src[SrcIndex].IsLiteral() && Op->Src[SrcIndex].Literal() == 0 && Size >= 4) { + HandleNZCV_RMW(); + RectifyCarryInvert(true); + Result = _AdcZeroWithFlags(OpSize, Before); + SetRFLAG(Before); + CalculatePF(Result); + CFInverted = false; + } else { + Result = CalculateFlags_ADC(Size, Before, Src); + } + if (!DestIsLockedMem(Op)) { StoreResult(GPRClass, Op, Result, -1); } diff --git a/FEXCore/Source/Interface/IR/IR.json b/FEXCore/Source/Interface/IR/IR.json index 2d054b818..db2476d76 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -1171,6 +1171,21 @@ "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" ] }, + "GPR = AdcZero OpSize:#Size, GPR:$Src1": { + "Desc": ["Adds GPR with inverted carry-in"], + "DestSize": "Size", + "EmitValidation": [ + "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" + ] + }, + "GPR = AdcZeroWithFlags OpSize:#Size, GPR:$Src1": { + "Desc": ["Adds and set NZCV for the sum of GPR and inverted carry-in given as NZCV"], + "HasSideEffects": true, + "DestSize": "Size", + "EmitValidation": [ + "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" + ] + }, "GPR = SbbWithFlags OpSize:#Size, GPR:$Src1, GPR:$Src2": { "Desc": ["Subtracts and set NZCV for the difference of two GPRs and carry-in given as NZCV"], "HasSideEffects": true, diff --git a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index 3f2db4b29..55d2c3fba 100644 --- a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -144,6 +144,14 @@ FlagInfo DeadFlagCalculationEliminination::Classify(IROp_Header* IROp) { .ReplacementNoWrite = OP_ADCNZCV, }; + case OP_ADCZEROWITHFLAGS: + return { + .Read = FLAG_C, + .Write = FLAG_NZCV, + .CanReplace = true, + .Replacement = OP_ADCZERO, + }; + case OP_SBBWITHFLAGS: return { .Read = FLAG_C,