From cda15ce9eae1e60bb5b579a90f72d30a49bc6354 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Thu, 12 Jun 2025 15:36:14 -0400 Subject: [PATCH] RegisterAllocationPass: optimize long divsion Signed-off-by: Alyssa Rosenzweig --- FEXCore/Source/Interface/IR/IR.h | 5 +++++ .../IR/Passes/RegisterAllocationPass.cpp | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/FEXCore/Source/Interface/IR/IR.h b/FEXCore/Source/Interface/IR/IR.h index 5177a1bcc..b4a1cb5a5 100644 --- a/FEXCore/Source/Interface/IR/IR.h +++ b/FEXCore/Source/Interface/IR/IR.h @@ -165,6 +165,11 @@ struct FEX_PACKED NodeWrapperBase final { LOGMAN_THROW_A_FMT(IsPointer(), "Offsets are within 2GiB range"); } + void SetInvalid() { + NodeOffset = 0; + LOGMAN_THROW_A_FMT(IsInvalid(), "Zero state"); + } + void SetImmediate(uint32_t Immediate) { LOGMAN_THROW_A_FMT(Immediate < (1u << 31), "Bounded"); NodeOffset = Immediate | (1u << 31); diff --git a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index b64d9f17c..6d11c80be 100644 --- a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -382,6 +382,19 @@ inline bool KillMove(IROp_Header* LastOp, IROp_Header* IROp, Ref LastNode, Ref C return LastOp->Op == OP_STOREREGISTER; } +inline bool IsSignext(const IROp_Header* IROp, OrderedNodeWrapper Src, OpSize Size) { + if (IROp->Op == OP_SBFE) { + auto Sbfe = IROp->C(); + return Sbfe->Width == 1 && Sbfe->lsb == (IR::OpSizeAsBits(Size) - 1) && Sbfe->Src == Src; + } else { + return false; + } +} + +inline bool IsZero(const IROp_Header* IROp) { + return IROp->Op == OP_CONSTANT && IROp->C()->Constant == 0; +} + bool ConstrainedRAPass::TryPostRAMerge(Ref LastNode, Ref CodeNode, IROp_Header* IROp) { auto LastOp = IR->GetOp(LastNode); @@ -408,6 +421,15 @@ bool ConstrainedRAPass::TryPostRAMerge(Ref LastNode, Ref CodeNode, IROp_Header* IREmit->RemovePostRA(CodeNode); return true; } + } else if ((IROp->Op == OP_DIV || IROp->Op == OP_UDIV) && IROp->Size >= OpSize::i32Bit) { + // If Upper came from a sign/zero extension, we only need a 64-bit division. + auto Op = IROp->CW(); + if (!Op->Upper.IsInvalid() && PhysicalRegister(Op->Upper) == PhysicalRegister(LastNode)) { + if (IROp->Op == OP_DIV ? IsSignext(LastOp, Op->Lower, IROp->Size) : IsZero(LastOp)) { + Op->Upper.SetInvalid(); + return PhysicalRegister(LastNode) == PhysicalRegister(Op->OutRemainder); + } + } } // Merge moves that are immediately consumed.