diff --git a/FEXCore/Scripts/json_ir_generator.py b/FEXCore/Scripts/json_ir_generator.py index 64a8f6809..6c93b974b 100755 --- a/FEXCore/Scripts/json_ir_generator.py +++ b/FEXCore/Scripts/json_ir_generator.py @@ -699,8 +699,12 @@ def print_ir_allocator_helpers(): # We gather the "has x87?" flag as we go. This saves the user from # having to keep track of whether they emitted any x87. + # Also changes the mmx state to X87. if op.LoweredX87: output_file.write("\t\tRecordX87Use();\n") + output_file.write( + "\t\tif(MMXState == MMXState_MMX) ChgStateMMX_X87();\n" + ) output_file.write("\t\tauto _Op = AllocateOp();\n".format(op.Name, op.Name.upper())) @@ -826,4 +830,3 @@ print_ir_dispatcher_defs() print_ir_dispatcher_dispatch() output_dispatch_file.close() - diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 076231bf0..31c36ee42 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -4407,9 +4407,13 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl LOGMAN_THROW_A_FMT(OpSize == 8, "full"); LOGMAN_THROW_A_FMT(Class == FPRClass, "MMX is floaty"); - // Partial store into bottom 64-bits, leave the upper bits unaffected. - // XXX: We actually should set the upper bits to all-1s? - StoreContextPartial(MM0Index + gpr - FEXCore::X86State::REG_MM_0, Src); + if (MMXState != MMXState_MMX) { + ChgStateX87_MMX(); + } + + uint8_t Index = MM0Index + gpr - FEXCore::X86State::REG_MM_0; + StoreContext(Index, Src); + RegCache.Partial |= (1ull << (uint64_t)Index); } else if (gpr >= FEXCore::X86State::REG_XMM_0) { const auto gprIndex = gpr - X86State::REG_XMM_0; const auto VectorSize = GetGuestVectorLength(); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index b321f4f3d..4c66d3eba 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -1243,6 +1243,10 @@ public: Bits &= ~NextBit; } else { _StoreContext(Size, Class, Value, Offset); + // If Partial and MMX register, then we need to store all 1s in bits 64-80 + if (Partial && Index >= MM0Index && Index <= MM7Index) { + _StoreContext(2, IR::GPRClass, _Constant(0xFFFF), Offset + 8); + } } } @@ -1964,12 +1968,6 @@ private: RegCache.Written |= Bit; } - void StoreContextPartial(uint8_t Index, Ref Value) { - StoreContext(Index, Value); - - RegCache.Partial |= (1ull << (uint64_t)Index); - } - void StoreRegister(uint8_t Reg, bool FPR, Ref Value) { StoreContext(Reg + (FPR ? FPR0Index : GPR0Index), Value); } @@ -2333,7 +2331,6 @@ private: } } - /** @} */ /** @} */ Ref GetX87Top(); @@ -2342,6 +2339,20 @@ private: Ref GetX87FTW_Helper(); void SetX87Top(Ref Value); + void ChgStateX87_MMX() override { + LOGMAN_THROW_A_FMT(MMXState == MMXState_X87, "Expected state to be x87"); + _StackForceSlow(); + SetX87Top(_Constant(0)); // top reset to zero + StoreContext(AbridgedFTWIndex, _Constant(0xFFFFUL)); // all valid + MMXState = MMXState_MMX; + } + + void ChgStateMMX_X87() override { + LOGMAN_THROW_A_FMT(MMXState == MMXState_MMX, "Expected state to be MMX"); + FlushRegisterCache(); + MMXState = MMXState_X87; + } + bool DestIsLockedMem(FEXCore::X86Tables::DecodedOp Op) const { return DestIsMem(Op) && (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK) != 0; } diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 4e1eff508..50d8aaf31 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -698,6 +698,10 @@ void OpDispatchBuilder::MOVQOp(OpcodeArgs, VectorOpType VectorType) { } void OpDispatchBuilder::MOVQMMXOp(OpcodeArgs) { + // Partial store into bottom 64-bits, leave the upper bits unaffected. + if (MMXState == MMXState_X87) { + ChgStateX87_MMX(); + } Ref Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); StoreResult(FPRClass, Op, Src, 1); } @@ -2298,6 +2302,11 @@ void OpDispatchBuilder::MMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs) { template void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int(OpcodeArgs) { + // This function causes a change in MMX state from X87 to MMX + if (MMXState == MMXState_X87) { + ChgStateX87_MMX(); + } + // If loading a vector, use the full size, so we don't // unnecessarily zero extend the vector. Otherwise, if // memory, then we want to load the element size exactly. diff --git a/FEXCore/Source/Interface/IR/IREmitter.h b/FEXCore/Source/Interface/IR/IREmitter.h index 98d6790b4..5b0720e61 100644 --- a/FEXCore/Source/Interface/IR/IREmitter.h +++ b/FEXCore/Source/Interface/IR/IREmitter.h @@ -343,8 +343,13 @@ protected: return Ptr; } + // MMX State can be either MMX (for 64bit) or x87 FPU (for 80bit) + enum { MMXState_MMX, MMXState_X87 } MMXState = MMXState_MMX; + // Overriden by dispatcher, stubbed for IR tests virtual void RecordX87Use() {} + virtual void ChgStateX87_MMX() {} + virtual void ChgStateMMX_X87() {} virtual void SaveNZCV(IROps Op) {} Ref CurrentWriteCursor = nullptr;