OpcodeDispatcher: Don't apply the address-size flag to segment addresses

The address-size flag only applies to the offset from the segment base,
rather than the segment address itself.
This commit is contained in:
Billy Laws committed 2024-07-31 18:14:32 +00:00
1 parent 069e2ce62a
commit be4777110c
3 files changed
+43 -42

No files matched your search

@@ -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);