From 22ab7f2b3effc47ec2fcbf8ba95ab1be3e02aa42 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 21 Feb 2024 13:00:12 -0400 Subject: [PATCH] IR: add SubWithFlags op (arm64 subs) with 8/16-bit handling to keep everything uniform. Signed-off-by: Alyssa Rosenzweig --- .../Source/Interface/Core/JIT/Arm64/ALUOps.cpp | 15 +++++++++++++++ FEXCore/Source/Interface/IR/IR.json | 8 ++++++++ FEXCore/Source/Interface/IR/Passes/ConstProp.cpp | 3 ++- .../RedundantFlagCalculationElimination.cpp | 7 +++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp index 2cd99aca6..322c8925b 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp @@ -200,6 +200,21 @@ DEF_OP(SubShift) { sub(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()), ConvertIRShiftType(Op->Shift), Op->ShiftAmount); } +DEF_OP(SubWithFlags) { + auto Op = IROp->C(); + const uint8_t OpSize = IROp->Size; + + LOGMAN_THROW_AA_FMT(OpSize == 4 || OpSize == 8, "Unsupported {} size: {}", __func__, OpSize); + const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; + + uint64_t Const; + if (IsInlineConstant(Op->Src2, &Const)) { + subs(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), Const); + } else { + subs(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID())); + } +} + DEF_OP(SubNZCV) { 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 5a09eb942..bcc9fc4d9 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -1021,6 +1021,14 @@ "_Shift != ShiftType::ROR" ] }, + "GPR = SubWithFlags OpSize:#Size, GPR:$Src1, GPR:$Src2": { + "Desc": [ "Integer Sub. Truncates and sets NZCV per SubNZCV"], + "DestSize": "Size", + "HasSideEffects": true, + "EmitValidation": [ + "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" + ] + }, "SubNZCV OpSize:#Size, GPR:$Src1, GPR:$Src2": { "Desc": ["Set NZCV for the difference of two GPRs. ", "Carry flag uses arm64 definition, inverted x86.", diff --git a/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp b/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp index 5e78c360a..013f6e7cf 100644 --- a/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp +++ b/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp @@ -965,6 +965,7 @@ bool ConstProp::ConstantInlining(IREmitter *IREmit, const IRListView& CurrentIR) case OP_SUB: case OP_ADDNZCV: case OP_SUBNZCV: + case OP_SUBWITHFLAGS: { auto Op = IROp->C(); @@ -979,7 +980,7 @@ bool ConstProp::ConstantInlining(IREmitter *IREmit, const IRListView& CurrentIR) Changed = true; } - } else if (IROp->Op == OP_SUBNZCV) { + } else if (IROp->Op == OP_SUBNZCV || IROp->Op == OP_SUBWITHFLAGS) { // If the first source is zero, we can use a NEGS instruction. uint64_t Constant1{}; if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) { diff --git a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index 1e222351c..dd29abfdd 100644 --- a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -128,6 +128,13 @@ DeadFlagCalculationEliminination::Classify(IROp_Header *IROp) .Replacement = OP_AND, }; + case OP_SUBWITHFLAGS: + return { + .Write = FLAG_NZCV, + .CanReplace = true, + .Replacement = OP_SUB, + }; + case OP_ADDNZCV: case OP_SUBNZCV: case OP_TESTNZ: