diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 0725933d7..90526f5ac 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -5334,11 +5334,25 @@ void OpDispatchBuilder::ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCor else { Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1); - auto ALUOp = _Add(Dest, Src); - // Overwrite our IR's op type - ALUOp.first->Header.Op = ALUIROp; + /* 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. + */ + if (ALUIROp == FEXCore::IR::IROps::OP_XOR && + Op->Dest.IsGPR() && Op->Src[0].IsGPR() && + Op->Dest.Data.GPR == Op->Src[0].Data.GPR) { + + Result = _Constant(0); + } else { + auto ALUOp = _Add(Dest, Src); + // Overwrite our IR's op type + ALUOp.first->Header.Op = ALUIROp; + + Result = ALUOp; + } - Result = ALUOp; StoreResult(GPRClass, Op, Result, -1); }