From 57978accc146f7ff6ddfe67fa51d2ab348637148 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Fri, 10 Nov 2023 21:12:32 -0400 Subject: [PATCH] OpcodeDispatcher: Add heuristic to prefer rmif for InsertNZCV Decent instcountci win. Signed-off-by: Alyssa Rosenzweig --- .../Source/Interface/Core/OpcodeDispatcher.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 2c89b817a..2a0e92c76 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -1319,7 +1319,23 @@ private: void InsertNZCV(unsigned BitOffset, OrderedNode *Value, signed FlagOffset, bool MustMask) { signed Bit = IndexNZCV(BitOffset); - if (CTX->HostFeatures.SupportsFlagM && !NZCVDirty) { + // If NZCV is not dirty, we always want to use rmif, it's 1 instruction to + // implement this. But if NZCV is dirty, it might still be cheaper to copy + // the GPR flags to NZCV and rmif. This is a heuristic for cases where we + // expect that 2 instruction sequence to be a win (versus something like + // bfe+mov+bfi+mov which can happen with our RA..). It's not totally + // conservative but it's pretty good in practice. + bool PreferRmif = !NZCVDirty || FlagOffset || MustMask || + (PossiblySetNZCVBits & (1u << Bit)); + + if (CTX->HostFeatures.SupportsFlagM && PreferRmif) { + // Update NZCV + if (NZCVDirty && CachedNZCV) + _StoreNZCV(CachedNZCV); + + CachedNZCV = nullptr; + NZCVDirty = false; + // Insert as NZCV. signed RmifBit = Bit - 28; _RmifNZCV(Value, (64 + FlagOffset - RmifBit) % 64, 1u << RmifBit);