diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp index cb73a18ce..63c16e257 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp @@ -163,6 +163,16 @@ DEF_OP(Adc) { adc(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID())); } +DEF_OP(SbbWithFlags) { + auto Op = IROp->C(); + const auto OpSize = IROp->Size; + + LOGMAN_THROW_AA_FMT(OpSize == IR::i32Bit || OpSize == IR::i64Bit, "Unsupported {} size: {}", __func__, OpSize); + const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; + + sbcs(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID())); +} + DEF_OP(SbbNZCV) { auto Op = IROp->C(); const auto OpSize = IROp->Size; @@ -173,6 +183,16 @@ DEF_OP(SbbNZCV) { sbcs(EmitSize, ARMEmitter::Reg::zr, GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID())); } +DEF_OP(Sbb) { + auto Op = IROp->C(); + const auto OpSize = IROp->Size; + + LOGMAN_THROW_AA_FMT(OpSize == IR::i32Bit || OpSize == IR::i64Bit, "Unsupported {} size: {}", __func__, OpSize); + const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; + + sbc(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID())); +} + DEF_OP(TestNZ) { auto Op = IROp->C(); const uint8_t OpSize = IROp->Size; diff --git a/FEXCore/Source/Interface/IR/IR.json b/FEXCore/Source/Interface/IR/IR.json index 39d870038..f22537db4 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -960,6 +960,15 @@ "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" ] }, + "GPR = Sbb OpSize:#Size, GPR:$Src1, GPR:$Src2": { + "Desc": [ "Integer Subtract with carry/borrow", + "Will truncate to 64 or 32bits" + ], + "DestSize": "Size", + "EmitValidation": [ + "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" + ] + }, "GPR = AddShift OpSize:#Size, GPR:$Src1, GPR:$Src2, ShiftType:$Shift{ShiftType::LSL}, u8:$ShiftAmount{0}": { "Desc": [ "Integer Add with shifted register", "Will truncate to 64 or 32bits" @@ -1011,6 +1020,14 @@ "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, + "DestSize": "Size", + "EmitValidation": [ + "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" + ] + }, "AdcNZCV OpSize:#Size, GPR:$Src1, GPR:$Src2": { "Desc": ["Set NZCV for the sum 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 601bc515c..bb8c12723 100644 --- a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -150,6 +150,14 @@ DeadFlagCalculationEliminination::Classify(IROp_Header *IROp) .Replacement = OP_ADC, }; + case OP_SBBWITHFLAGS: + return { + .Read = FLAG_C, + .Write = FLAG_NZCV, + .CanReplace = true, + .Replacement = OP_SBB, + }; + case OP_ADDNZCV: case OP_SUBNZCV: case OP_TESTNZ: @@ -179,6 +187,7 @@ DeadFlagCalculationEliminination::Classify(IROp_Header *IROp) return {.Read = FLAG_NZCV}; case OP_ADC: + case OP_SBB: return {.Read = FLAG_C}; case OP_ADCNZCV: