From 2030b70ff8425923ef9983e0bf2121d92e49c7c9 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 6 Aug 2025 15:09:00 -0400 Subject: [PATCH] OpcodeDispatcher: do Select 0/1 inline in dispatcher Signed-off-by: Alyssa Rosenzweig --- FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp | 14 +++++--------- .../Interface/Core/OpcodeDispatcher/AVX_128.cpp | 9 ++------- .../Interface/Core/OpcodeDispatcher/Flags.cpp | 8 ++------ .../Interface/Core/OpcodeDispatcher/Vector.cpp | 10 ++-------- .../Source/Interface/Core/OpcodeDispatcher/X87.cpp | 4 +--- FEXCore/Source/Interface/IR/IREmitter.h | 8 ++++++++ 6 files changed, 20 insertions(+), 33 deletions(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 6c8ea9299..7f5c2c7ac 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -1692,9 +1692,7 @@ void OpDispatchBuilder::BLSMSKBMIOp(OpcodeArgs) { InvalidatePF_AF(); // CF set according to the Src - auto Zero = Constant(0); - auto One = Constant(1); - auto CFInv = _Select(IR::COND_NEQ, Src, Zero, One, Zero); + auto CFInv = To01(OpSize::i64Bit, Src); // The output of BLSMSK is always nonzero, so TST will clear Z (along with C // and O) while setting S. @@ -1712,9 +1710,7 @@ void OpDispatchBuilder::BLSRBMIOp(OpcodeArgs) { StoreResult(GPRClass, Op, Result, OpSize::iInvalid); - auto Zero = Constant(0); - auto One = Constant(1); - auto CFInv = _Select(IR::COND_NEQ, Src, Zero, One, Zero); + auto CFInv = To01(OpSize::i64Bit, Src); SetNZ_ZeroCV(Size, Result); SetCFInverted(CFInv); @@ -2747,7 +2743,7 @@ void OpDispatchBuilder::PopcountOp(OpcodeArgs) { Ref OpDispatchBuilder::CalculateAFForDecimal(Ref A) { auto Nibble = _And(OpSize::i64Bit, A, Constant(0xF)); - auto Greater = _Select(FEXCore::IR::COND_UGT, Nibble, Constant(9), Constant(1), Constant(0)); + auto Greater = Select01(OpSize::i64Bit, CondClassType {COND_UGT}, Nibble, Constant(9)); return _Or(OpSize::i64Bit, LoadAF(), Greater); } @@ -2759,7 +2755,7 @@ void OpDispatchBuilder::DAAOp(OpcodeArgs) { auto AF = CalculateAFForDecimal(AL); // CF |= (AL > 0x99); - CFInv = _And(OpSize::i64Bit, CFInv, _Select(FEXCore::IR::COND_ULE, AL, Constant(0x99), Constant(1), Constant(0))); + CFInv = _And(OpSize::i64Bit, CFInv, Select01(OpSize::i64Bit, CondClassType {COND_ULE}, AL, Constant(0x99))); // AL = AF ? (AL + 0x6) : AL; AL = _Select(FEXCore::IR::COND_NEQ, AF, Constant(0), _Add(OpSize::i64Bit, AL, Constant(0x6)), AL); @@ -2782,7 +2778,7 @@ void OpDispatchBuilder::DASOp(OpcodeArgs) { auto AF = CalculateAFForDecimal(AL); // CF |= (AL > 0x99); - CF = _Or(OpSize::i64Bit, CF, _Select(FEXCore::IR::COND_UGT, AL, Constant(0x99), Constant(1), Constant(0))); + CF = _Or(OpSize::i64Bit, CF, Select01(OpSize::i64Bit, CondClassType {COND_UGT}, AL, Constant(0x99))); // NewCF = CF | (AF && (Borrow from AL - 6)) auto NewCF = _Or(OpSize::i32Bit, CF, _Select(FEXCore::IR::COND_ULT, AL, Constant(6), AF, CF)); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp index 25f0e07ca..841e3133f 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp @@ -2212,8 +2212,6 @@ void OpDispatchBuilder::AVX128_VTESTP(OpcodeArgs) { // For 256-bit, we need to split up the operation. This is nontrivial. // Let's go the simple route here. Ref ZF, CFInv; - Ref ZeroConst = Constant(0); - Ref OneConst = Constant(1); const auto ElementSizeInBits = IR::OpSizeAsBits(ElementSize); @@ -2255,7 +2253,7 @@ void OpDispatchBuilder::AVX128_VTESTP(OpcodeArgs) { // ExtGPR will either be [0, 8] or [0, 16] If 0 then set Flag. auto ExtGPR = _VExtractToGPR(OpSize::i128Bit, ElementSize, AddWide, 0); - CFInv = _Select(IR::COND_NEQ, ExtGPR, ZeroConst, OneConst, ZeroConst); + CFInv = To01(OpSize::i64Bit, ExtGPR); } // As in PTest, this sets Z appropriately while zeroing the rest of NZCV. @@ -2294,10 +2292,7 @@ void OpDispatchBuilder::AVX128_PTest(OpcodeArgs) { Test1 = _VExtractToGPR(OpSize::i128Bit, OpSize::i16Bit, Test1, 0); Test2 = _VExtractToGPR(OpSize::i128Bit, OpSize::i16Bit, Test2, 0); - auto ZeroConst = Constant(0); - auto OneConst = Constant(1); - - Test2 = _Select(FEXCore::IR::COND_NEQ, Test2, ZeroConst, OneConst, ZeroConst); + Test2 = To01(OpSize::i64Bit, Test2); // Careful, these flags are different between {V,}PTEST and VTESTP{S,D} // Set ZF according to Test1. SF will be zeroed since we do a 32-bit test on diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp index 2a681cc23..7f6a2e786 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp @@ -267,8 +267,6 @@ Ref OpDispatchBuilder::IncrementByCarry(OpSize OpSize, Ref Src) { } Ref OpDispatchBuilder::CalculateFlags_ADC(IR::OpSize SrcSize, Ref Src1, Ref Src2) { - auto Zero = _InlineConstant(0); - auto One = _InlineConstant(1); auto OpSize = SrcSize == OpSize::i64Bit ? OpSize::i64Bit : OpSize::i32Bit; Ref Res; @@ -292,7 +290,7 @@ Ref OpDispatchBuilder::CalculateFlags_ADC(IR::OpSize SrcSize, Ref Src1, Ref Src2 Res = _Bfe(OpSize, IR::OpSizeAsBits(SrcSize), 0, Res); // TODO: We can fold that second Bfe in (cmp uxth). - auto SelectCFInv = _Select(FEXCore::IR::COND_UGE, Res, Src2PlusCF, One, Zero); + auto SelectCFInv = Select01(OpSize, CondClassType {COND_UGE}, Res, Src2PlusCF); SetNZ_ZeroCV(SrcSize, Res); SetCFInverted(SelectCFInv); @@ -304,8 +302,6 @@ Ref OpDispatchBuilder::CalculateFlags_ADC(IR::OpSize SrcSize, Ref Src1, Ref Src2 } Ref OpDispatchBuilder::CalculateFlags_SBB(IR::OpSize SrcSize, Ref Src1, Ref Src2) { - auto Zero = _InlineConstant(0); - auto One = _InlineConstant(1); auto OpSize = SrcSize == OpSize::i64Bit ? OpSize::i64Bit : OpSize::i32Bit; CalculateAF(Src1, Src2); @@ -328,7 +324,7 @@ Ref OpDispatchBuilder::CalculateFlags_SBB(IR::OpSize SrcSize, Ref Src1, Ref Src2 Res = _Sub(OpSize, Src1, Src2PlusCF); Res = _Bfe(OpSize, IR::OpSizeAsBits(SrcSize), 0, Res); - auto SelectCFInv = _Select(FEXCore::IR::COND_UGE, Src1, Src2PlusCF, One, Zero); + auto SelectCFInv = Select01(OpSize, CondClassType {COND_UGE}, Src1, Src2PlusCF); SetNZ_ZeroCV(SrcSize, Res); SetCFInverted(SelectCFInv); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index ca2f71838..a19738c96 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -3950,10 +3950,7 @@ void OpDispatchBuilder::PTestOpImpl(OpSize Size, Ref Dest, Ref Src) { Test1 = _VExtractToGPR(Size, OpSize::i16Bit, Test1, 0); Test2 = _VExtractToGPR(Size, OpSize::i16Bit, Test2, 0); - auto ZeroConst = Constant(0); - auto OneConst = Constant(1); - - Test2 = _Select(FEXCore::IR::COND_NEQ, Test2, ZeroConst, OneConst, ZeroConst); + Test2 = To01(OpSize::i64Bit, Test2); // Careful, these flags are different between {V,}PTEST and VTESTP{S,D} // Set ZF according to Test1. SF will be zeroed since we do a 32-bit test on @@ -3990,10 +3987,7 @@ void OpDispatchBuilder::VTESTOpImpl(OpSize SrcSize, IR::OpSize ElementSize, Ref Ref AndGPR = _VExtractToGPR(SrcSize, OpSize::i16Bit, MaxAnd, 0); Ref AndNotGPR = _VExtractToGPR(SrcSize, OpSize::i16Bit, MaxAndNot, 0); - Ref ZeroConst = Constant(0); - Ref OneConst = Constant(1); - - Ref CFInv = _Select(IR::COND_NEQ, AndNotGPR, ZeroConst, OneConst, ZeroConst); + Ref CFInv = To01(OpSize::i64Bit, AndNotGPR); // As in PTest, this sets Z appropriately while zeroing the rest of NZCV. SetNZ_ZeroCV(OpSize::i32Bit, AndGPR); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp index 0402410a9..0c5e9d7ff 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp @@ -851,11 +851,9 @@ void OpDispatchBuilder::X87FXAM(OpcodeArgs) { // Claim this is a normal number // We don't support anything else auto TopValid = _StackValidTag(0); - auto ZeroConst = Constant(0); - auto OneConst = Constant(1); // In the case of top being invalid then C3:C2:C0 is 0b101 - auto C3 = _Select(FEXCore::IR::COND_NEQ, TopValid, OneConst, OneConst, ZeroConst); + auto C3 = Select01(OpSize::i32Bit, CondClassType {COND_NEQ}, TopValid, Constant(1)); auto C2 = TopValid; auto C0 = C3; // Mirror C3 until something other than zero is supported diff --git a/FEXCore/Source/Interface/IR/IREmitter.h b/FEXCore/Source/Interface/IR/IREmitter.h index df39b1de1..0883aa75b 100644 --- a/FEXCore/Source/Interface/IR/IREmitter.h +++ b/FEXCore/Source/Interface/IR/IREmitter.h @@ -82,6 +82,14 @@ public: return _StoreMem(Class, Size, Value, Addr, Invalid(), Align, MEM_OFFSET_SXTX, 1); } + IRPair Select01(FEXCore::IR::OpSize CompareSize, CondClassType Cond, OrderedNode* Cmp1, OrderedNode* Cmp2) { + return _Select(OpSize::i64Bit, CompareSize, Cond, Cmp1, Cmp2, _InlineConstant(1), _InlineConstant(0)); + } + + IRPair To01(FEXCore::IR::OpSize CompareSize, OrderedNode* Cmp1) { + return Select01(CompareSize, CondClassType {COND_NEQ}, Cmp1, Constant(0)); + } + int64_t Constants[32]; Ref ConstantRefs[32]; uint32_t NrConstants;