diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 3eb6ea40b..9134a104d 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -2527,7 +2527,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs, uint32_t SrcIndex, BTAction Action) { if (DestIsLockedMem(Op)) { HandledLock = true; - Value = _AtomicFetchCLR(OpSize::i8Bit, BitMask, LoadEffectiveAddress(Address)); + Value = _AtomicFetchCLR(OpSize::i8Bit, BitMask, LoadEffectiveAddress(Address, true)); } else { Value = _LoadMemAutoTSO(GPRClass, 1, Address, 1); @@ -2542,7 +2542,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs, uint32_t SrcIndex, BTAction Action) { if (DestIsLockedMem(Op)) { HandledLock = true; - Value = _AtomicFetchOr(OpSize::i8Bit, BitMask, LoadEffectiveAddress(Address)); + Value = _AtomicFetchOr(OpSize::i8Bit, BitMask, LoadEffectiveAddress(Address, true)); } else { Value = _LoadMemAutoTSO(GPRClass, 1, Address, 1); @@ -2557,7 +2557,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs, uint32_t SrcIndex, BTAction Action) { if (DestIsLockedMem(Op)) { HandledLock = true; - Value = _AtomicFetchXor(OpSize::i8Bit, BitMask, LoadEffectiveAddress(Address)); + Value = _AtomicFetchXor(OpSize::i8Bit, BitMask, LoadEffectiveAddress(Address, true)); } else { Value = _LoadMemAutoTSO(GPRClass, 1, Address, 1); @@ -4225,22 +4225,7 @@ void OpDispatchBuilder::UpdatePrefixFromSegment(Ref Segment, uint32_t SegmentReg } } -AddressMode OpDispatchBuilder::AddSegmentToAddress(AddressMode A, uint32_t Flags) { - auto Segment = GetSegment(Flags); - if (Segment) { - if (!A.Base) { - A.Base = Segment; - } else if (!A.Index) { - A.Index = Segment; - } else { - A.Base = _Add(IR::SizeToOpSize(CTX->GetGPRSize()), A.Base, Segment); - } - } - - return A; -} - -Ref OpDispatchBuilder::LoadEffectiveAddress(AddressMode A, bool AllowUpperGarbage) { +Ref OpDispatchBuilder::LoadEffectiveAddress(AddressMode A, bool AddSegmentBase, bool AllowUpperGarbage) { const uint8_t GPRSize = CTX->GetGPRSize(); Ref Tmp = A.Base; @@ -4272,10 +4257,16 @@ Ref OpDispatchBuilder::LoadEffectiveAddress(AddressMode A, bool AllowUpperGarbag Tmp = _Bfe(IR::SizeToOpSize(GPRSize), A.AddrSize * 8, 0, Tmp); } + if (A.Segment && AddSegmentBase) { + Tmp = Tmp ? _Add(IR::SizeToOpSize(GPRSize), Tmp, A.Segment) : A.Segment; + } + return Tmp ?: _Constant(0); } AddressMode OpDispatchBuilder::SelectAddressMode(AddressMode A, bool AtomicTSO, bool Vector, unsigned AccessSize) { + const uint8_t GPRSize = CTX->GetGPRSize(); + // In the future this also needs to account for LRCPC3. bool SupportsRegIndex = Vector || !AtomicTSO; @@ -4284,27 +4275,41 @@ AddressMode OpDispatchBuilder::SelectAddressMode(AddressMode A, bool AtomicTSO, // addresses are reserved and therefore wrap around is invalid. // // TODO: Also handle GPR TSO if we can guarantee the constant inlines. - if (A.Base && A.Offset && !A.Index && SupportsRegIndex) { - const bool Const_16K = A.Offset > -16384 && A.Offset < 16384 && CTX->GetGPRSize() == 4; + if (SupportsRegIndex) { + if ((A.Base || A.Segment) && A.Offset && !A.Index) { + const bool Const_16K = A.Offset > -16384 && A.Offset < 16384 && A.AddrSize == 4 && GPRSize == 4; - if ((A.AddrSize == 8) || Const_16K) { - return { - .Base = A.Base, - .Index = _Constant(A.Offset), - .IndexType = (Const_16K && A.Offset < 0) ? MEM_OFFSET_SXTW : MEM_OFFSET_SXTX, - .IndexScale = 1, - }; + if ((A.AddrSize == 8) || Const_16K) { + if (A.Base && A.Segment) { + A.Base = _Add(IR::SizeToOpSize(GPRSize), A.Base, A.Segment); + } else if (A.Segment) { + A.Base = A.Segment; + } + + return { + .Base = A.Base, + .Index = _Constant(A.Offset), + .IndexType = (Const_16K && A.Offset < 0) ? MEM_OFFSET_SXTW : MEM_OFFSET_SXTX, + .IndexScale = 1, + }; + } } - } - // Try a (possibly scaled) register index. - if (A.AddrSize == 8 && A.Base && A.Index && !A.Offset && (A.IndexScale == 1 || A.IndexScale == AccessSize) && SupportsRegIndex) { - return A; + // Try a (possibly scaled) register index. + if (A.AddrSize == 8 && A.Base && (A.Index || A.Segment) && !A.Offset && (A.IndexScale == 1 || A.IndexScale == AccessSize)) { + if (A.Index && A.Segment) { + A.Base = _Add(IR::SizeToOpSize(GPRSize), A.Base, A.Segment); + } else if (A.Segment) { + A.Index = A.Segment; + A.IndexScale = 1; + } + return A; + } } // Fallback on software address calculation return { - .Base = LoadEffectiveAddress(A), + .Base = LoadEffectiveAddress(A, true), .Index = InvalidNode, }; } @@ -4314,6 +4319,7 @@ AddressMode OpDispatchBuilder::DecodeAddress(const X86Tables::DecodedOp& Op, con const uint8_t GPRSize = CTX->GetGPRSize(); AddressMode A {}; + A.Segment = GetSegment(Op->Flags); A.AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize; A.NonTSO = AccessType == MemoryAccessType::NONTSO || AccessType == MemoryAccessType::STREAM; @@ -4404,11 +4410,9 @@ Ref OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, const X86T } if ((IsOperandMem(Operand, true) && LoadData) || ForceLoad) { - A = AddSegmentToAddress(A, Flags); - return _LoadMemAutoTSO(Class, OpSize, A, Align == -1 ? OpSize : Align); } else { - return LoadEffectiveAddress(A, AllowUpperGarbage); + return LoadEffectiveAddress(A, false, AllowUpperGarbage); } } @@ -4523,10 +4527,9 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl } AddressMode A = DecodeAddress(Op, Operand, AccessType, false /* IsLoad */); - A = AddSegmentToAddress(A, Op->Flags); if (OpSize == 10) { - Ref MemStoreDst = LoadEffectiveAddress(A); + Ref MemStoreDst = LoadEffectiveAddress(A, true); // For X87 extended doubles, split before storing _StoreMem(FPRClass, 8, MemStoreDst, Src, Align); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 8e2fa0d60..ef127fb2a 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -72,6 +72,7 @@ struct LoadSourceOptions { }; struct AddressMode { + Ref Segment {nullptr}; Ref Base {nullptr}; Ref Index {nullptr}; MemOffsetType IndexType = MEM_OFFSET_SXTX; @@ -1504,8 +1505,7 @@ private: Ref GetRelocatedPC(const FEXCore::X86Tables::DecodedOp& Op, int64_t Offset = 0); - AddressMode AddSegmentToAddress(AddressMode A, uint32_t Flags); - Ref LoadEffectiveAddress(AddressMode A, bool AllowUpperGarbage = false); + Ref LoadEffectiveAddress(AddressMode A, bool AddSegmentBase, bool AllowUpperGarbage = false); AddressMode SelectAddressMode(AddressMode A, bool AtomicTSO, bool Vector, unsigned AccessSize); bool IsOperandMem(const X86Tables::DecodedOperand& Operand, bool Load) { diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp index 8390ee968..8eb423e9d 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp @@ -499,7 +499,6 @@ OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_LoadSource_WithOpSize( LOGMAN_THROW_A_FMT(IsOperandMem(Operand, true), "only memory sources"); AddressMode A = DecodeAddress(Op, Operand, AccessType, true /* IsLoad */); - A = AddSegmentToAddress(A, Flags); AddressMode HighA = A; HighA.Offset += 16; @@ -557,7 +556,6 @@ void OpDispatchBuilder::AVX128_StoreResult_WithOpSize(FEXCore::X86Tables::Decode } } else { AddressMode A = DecodeAddress(Op, Operand, AccessType, false /* IsLoad */); - A = AddSegmentToAddress(A, Op->Flags); _StoreMemAutoTSO(FPRClass, 16, A, Src.Low, 1);