From 0fbe69ebcfd9095c90a252fe678167fd62898604 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 28 May 2025 13:41:30 -0400 Subject: [PATCH] OpcodeDispatcher: optimize xor-with-self flags Signed-off-by: Alyssa Rosenzweig --- .../Interface/Core/OpcodeDispatcher.cpp | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 3467fbb0f..78685fe93 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -4416,18 +4416,22 @@ void OpDispatchBuilder::MOVGPRNTOp(OpcodeArgs) { } void OpDispatchBuilder::ALUOp(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp, unsigned SrcIdx) { - /* On x86, the canonical way to zero a register is XOR with itself... because - * modern x86 detects this pattern in hardware. arm64 does not detect this - * pattern, we should do it like the x86 hardware would. On arm64, "mov x0, - * #0" is faster than "eor x0, x0, x0". Additionally this lets more constant - * folding kick in for flags. - */ + // On x86, the canonical way to zero a register is XOR with itself. Detect and + // emit optimal arm64 assembly. if (!DestIsLockedMem(Op) && ALUIROp == FEXCore::IR::IROps::OP_XOR && Op->Dest.IsGPR() && Op->Src[SrcIdx].IsGPR() && Op->Dest.Data.GPR == Op->Src[SrcIdx].Data.GPR) { - auto Result = _Constant(0); - StoreResult(GPRClass, Op, Result, OpSize::iInvalid); - CalculateFlags_Logical(OpSizeFromSrc(Op), Result); + // Move 0 into the register + StoreResult(GPRClass, Op, _Constant(0), OpSize::iInvalid); + + // Set flags for zero result with inverted carry. We subtract an arbitrary + // register from itself to get the zero, since `subs wzr, #0` is not + // encodable. This is optimal and works regardless of the opsize. + auto Zero = LoadGPR(Op->Dest.Data.GPR.GPR); + HandleNZ00Write(); + InvalidateAF(); + CalculatePF(_SubWithFlags(OpSize::i32Bit, Zero, Zero)); + CFInverted = true; return; }