mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-14 15:00:53 +02:00
OpcodeDispatcher: refactor address modes
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
1 parent
112c49a348
commit
7bd036d1ae
2 files changed
+154
-145
No files matched your search
@@ -4240,6 +4240,64 @@ void OpDispatchBuilder::UpdatePrefixFromSegment(OrderedNode* Segment, uint32_t S
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
OrderedNode* OpDispatchBuilder::LoadEffectiveAddress(AddressMode A, bool AllowUpperGarbage) {
|
||||
const uint8_t GPRSize = CTX->GetGPRSize();
|
||||
OrderedNode* Tmp = A.Base;
|
||||
|
||||
if (A.Offset) {
|
||||
OrderedNode* Offset = _Constant(A.Offset);
|
||||
Tmp = Tmp ? _Add(IR::SizeToOpSize(GPRSize), Tmp, Offset) : Offset;
|
||||
}
|
||||
|
||||
if (A.Index) {
|
||||
if (A.IndexScale != 1) {
|
||||
LOGMAN_THROW_AA_FMT((A.IndexScale & (A.IndexScale - 1)) == 0, "power of two");
|
||||
uint32_t Log2 = FEXCore::ilog2(A.IndexScale);
|
||||
|
||||
if (Tmp) {
|
||||
Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Tmp, A.Index, ShiftType::LSL, Log2);
|
||||
} else {
|
||||
Tmp = _Lshl(IR::SizeToOpSize(GPRSize), A.Index, _Constant(Log2));
|
||||
}
|
||||
} else {
|
||||
Tmp = Tmp ? _Add(IR::SizeToOpSize(GPRSize), Tmp, A.Index) : A.Index;
|
||||
}
|
||||
}
|
||||
|
||||
// For 64-bit AddrSize can be 32-bit or 64-bit
|
||||
// For 32-bit AddrSize can be 32-bit or 16-bit
|
||||
//
|
||||
// If the AddrSize is not the GPRSize then we need to clear the upper bits.
|
||||
if ((A.AddrSize < GPRSize) && !AllowUpperGarbage && Tmp) {
|
||||
Tmp = _Bfe(IR::SizeToOpSize(GPRSize), A.AddrSize * 8, 0, Tmp);
|
||||
}
|
||||
|
||||
return Tmp ?: _Constant(0);
|
||||
}
|
||||
|
||||
AddressMode OpDispatchBuilder::SelectAddressMode(AddressMode A, bool AtomicTSO, bool Vector, unsigned AccessSize) {
|
||||
// Fallback on software address calculation
|
||||
return {
|
||||
.Base = LoadEffectiveAddress(A),
|
||||
.Index = InvalidNode,
|
||||
};
|
||||
}
|
||||
|
||||
OrderedNode* OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, const X86Tables::DecodedOp& Op,
|
||||
const X86Tables::DecodedOperand& Operand, uint8_t OpSize, uint32_t Flags,
|
||||
const LoadSourceOptions& Options) {
|
||||
@@ -4249,54 +4307,51 @@ OrderedNode* OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, c
|
||||
|
||||
auto [Align, LoadData, ForceLoad, AccessType, AllowUpperGarbage] = Options;
|
||||
|
||||
OrderedNode* Src {nullptr};
|
||||
bool LoadableType = false;
|
||||
const uint8_t GPRSize = CTX->GetGPRSize();
|
||||
const uint32_t AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize;
|
||||
bool LoadableType = false;
|
||||
|
||||
AddressMode A {};
|
||||
A.AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize;
|
||||
|
||||
if (Operand.IsLiteral()) {
|
||||
uint64_t constant = Operand.Data.Literal.Value;
|
||||
A.Offset = Operand.Data.Literal.Value;
|
||||
uint64_t width = Operand.Data.Literal.Size * 8;
|
||||
|
||||
if (Operand.Data.Literal.Size != 8) {
|
||||
// zero extend
|
||||
constant = constant & ((1ULL << width) - 1);
|
||||
A.Offset &= ((1ULL << width) - 1);
|
||||
}
|
||||
Src = _Constant(width, constant);
|
||||
} else if (Operand.IsGPR()) {
|
||||
const auto gpr = Operand.Data.GPR.GPR;
|
||||
const auto highIndex = Operand.Data.GPR.HighBits ? 1 : 0;
|
||||
|
||||
if (gpr >= FEXCore::X86State::REG_MM_0) {
|
||||
Src = _LoadContext(OpSize, FPRClass, offsetof(FEXCore::Core::CPUState, mm[gpr - FEXCore::X86State::REG_MM_0]));
|
||||
A.Base = _LoadContext(OpSize, FPRClass, offsetof(FEXCore::Core::CPUState, mm[gpr - FEXCore::X86State::REG_MM_0]));
|
||||
} else if (gpr >= FEXCore::X86State::REG_XMM_0) {
|
||||
const auto gprIndex = gpr - X86State::REG_XMM_0;
|
||||
|
||||
// Load the full register size if it is a XMM register source.
|
||||
Src = LoadXMMRegister(gprIndex);
|
||||
A.Base = LoadXMMRegister(gprIndex);
|
||||
|
||||
// Now extract the subregister if it was a partial load /smaller/ than SSE size
|
||||
// TODO: Instead of doing the VMov implicitly on load, hunt down all use cases that require partial loads and do it after load.
|
||||
// We don't have information here to know if the operation needs zero upper bits or can contain data.
|
||||
if (!AllowUpperGarbage && OpSize < Core::CPUState::XMM_SSE_REG_SIZE) {
|
||||
Src = _VMov(OpSize, Src);
|
||||
A.Base = _VMov(OpSize, A.Base);
|
||||
}
|
||||
} else {
|
||||
Src = LoadGPRRegister(gpr, OpSize, highIndex ? 8 : 0, AllowUpperGarbage);
|
||||
A.Base = LoadGPRRegister(gpr, OpSize, highIndex ? 8 : 0, AllowUpperGarbage);
|
||||
}
|
||||
} else if (Operand.IsGPRDirect()) {
|
||||
Src = LoadGPRRegister(Operand.Data.GPR.GPR, GPRSize);
|
||||
A.Base = LoadGPRRegister(Operand.Data.GPR.GPR, GPRSize);
|
||||
|
||||
LoadableType = true;
|
||||
if (Operand.Data.GPR.GPR == FEXCore::X86State::REG_RSP && AccessType == MemoryAccessType::DEFAULT) {
|
||||
AccessType = MemoryAccessType::NONTSO;
|
||||
}
|
||||
} else if (Operand.IsGPRIndirect()) {
|
||||
auto GPR = LoadGPRRegister(Operand.Data.GPRIndirect.GPR, GPRSize);
|
||||
|
||||
auto Constant = _Constant(GPRSize * 8, Operand.Data.GPRIndirect.Displacement);
|
||||
|
||||
Src = _Add(IR::SizeToOpSize(GPRSize), GPR, Constant);
|
||||
A.Base = LoadGPRRegister(Operand.Data.GPRIndirect.GPR, GPRSize);
|
||||
A.Offset = Operand.Data.GPRIndirect.Displacement;
|
||||
|
||||
LoadableType = true;
|
||||
if (Operand.Data.GPRIndirect.GPR == FEXCore::X86State::REG_RSP && AccessType == MemoryAccessType::DEFAULT) {
|
||||
@@ -4304,69 +4359,36 @@ OrderedNode* OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, c
|
||||
}
|
||||
} else if (Operand.IsRIPRelative()) {
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
Src = GetRelocatedPC(Op, Operand.Data.RIPLiteral.Value.s);
|
||||
A.Base = GetRelocatedPC(Op, Operand.Data.RIPLiteral.Value.s);
|
||||
} else {
|
||||
// 32bit this isn't RIP relative but instead absolute
|
||||
Src = _Constant(GPRSize * 8, Operand.Data.RIPLiteral.Value.u);
|
||||
A.Offset = Operand.Data.RIPLiteral.Value.u;
|
||||
}
|
||||
|
||||
LoadableType = true;
|
||||
} else if (Operand.IsSIB()) {
|
||||
const bool IsVSIB = (Op->Flags & X86Tables::DecodeFlags::FLAG_VSIB_BYTE) != 0;
|
||||
OrderedNode* Tmp {};
|
||||
|
||||
if (!IsVSIB && Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID && Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) {
|
||||
auto Base = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize);
|
||||
auto Index = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize);
|
||||
if (Operand.Data.SIB.Scale == 1) {
|
||||
Tmp = _Add(IR::SizeToOpSize(GPRSize), Base, Index);
|
||||
} else {
|
||||
Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Base, Index, ShiftType::LSL, FEXCore::ilog2(Operand.Data.SIB.Scale));
|
||||
}
|
||||
} else {
|
||||
// NOTE: VSIB cannot have the index * scale portion calculated ahead of time,
|
||||
// since the index in this case is a vector. So, we can't just apply the scale
|
||||
// to it, since this needs to be applied to each element in the index register
|
||||
// after said element has been sign extended. So, we pass this through for the
|
||||
// instruction implementation to handle.
|
||||
//
|
||||
// What we do handle though, is the applying the displacement value to
|
||||
// the base register (if a base register is provided), since this is a
|
||||
// part of the address calculation that can be done ahead of time.
|
||||
if (Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID && !IsVSIB) {
|
||||
Tmp = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize);
|
||||
|
||||
if (Operand.Data.SIB.Scale != 1) {
|
||||
auto Constant = _Constant(GPRSize * 8, Operand.Data.SIB.Scale);
|
||||
Tmp = _Mul(IR::SizeToOpSize(GPRSize), Tmp, Constant);
|
||||
}
|
||||
}
|
||||
|
||||
if (Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) {
|
||||
auto GPR = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize);
|
||||
|
||||
if (Tmp != nullptr) {
|
||||
Tmp = _Add(IR::SizeToOpSize(GPRSize), Tmp, GPR);
|
||||
} else {
|
||||
Tmp = GPR;
|
||||
}
|
||||
}
|
||||
if (Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) {
|
||||
A.Base = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize);
|
||||
}
|
||||
|
||||
if (Operand.Data.SIB.Offset) {
|
||||
if (Tmp != nullptr) {
|
||||
Src = _Add(IR::SizeToOpSize(GPRSize), Tmp, _Constant(GPRSize * 8, Operand.Data.SIB.Offset));
|
||||
} else {
|
||||
Src = _Constant(GPRSize * 8, Operand.Data.SIB.Offset);
|
||||
}
|
||||
} else {
|
||||
if (Tmp != nullptr) {
|
||||
Src = Tmp;
|
||||
} else {
|
||||
Src = _Constant(GPRSize * 8, 0);
|
||||
}
|
||||
// NOTE: VSIB cannot have the index * scale portion calculated ahead of time,
|
||||
// since the index in this case is a vector. So, we can't just apply the scale
|
||||
// to it, since this needs to be applied to each element in the index register
|
||||
// after said element has been sign extended. So, we pass this through for the
|
||||
// instruction implementation to handle.
|
||||
//
|
||||
// What we do handle though, is the applying the displacement value to
|
||||
// the base register (if a base register is provided), since this is a
|
||||
// part of the address calculation that can be done ahead of time.
|
||||
if (!IsVSIB && Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID) {
|
||||
A.Index = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize);
|
||||
A.IndexScale = Operand.Data.SIB.Scale;
|
||||
}
|
||||
|
||||
A.Offset = Operand.Data.SIB.Offset;
|
||||
|
||||
if ((Operand.Data.SIB.Base == FEXCore::X86State::REG_RSP || Operand.Data.SIB.Index == FEXCore::X86State::REG_RSP) &&
|
||||
AccessType == MemoryAccessType::DEFAULT) {
|
||||
AccessType = MemoryAccessType::NONTSO;
|
||||
@@ -4377,24 +4399,15 @@ OrderedNode* OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, c
|
||||
LOGMAN_MSG_A_FMT("Unknown Src Type: {}\n", Operand.Type);
|
||||
}
|
||||
|
||||
if (LoadableType && AddrSize < GPRSize && (LoadData || !AllowUpperGarbage)) {
|
||||
// For 64-bit AddrSize can be 32-bit or 64-bit
|
||||
// For 32-bit AddrSize can be 32-bit or 16-bit
|
||||
//
|
||||
// If the AddrSize is not the GPRSize then we need to clear the upper bits.
|
||||
Src = _Bfe(IR::SizeToOpSize(GPRSize), AddrSize * 8, 0, Src);
|
||||
}
|
||||
|
||||
if ((LoadableType && LoadData) || ForceLoad) {
|
||||
Src = AppendSegmentOffset(Src, Flags);
|
||||
|
||||
if (AccessType == MemoryAccessType::NONTSO || AccessType == MemoryAccessType::STREAM) {
|
||||
Src = _LoadMem(Class, OpSize, Src, Align == -1 ? OpSize : Align);
|
||||
} else {
|
||||
Src = _LoadMemAutoTSO(Class, OpSize, Src, Align == -1 ? OpSize : Align);
|
||||
}
|
||||
A = AddSegmentToAddress(A, Flags);
|
||||
|
||||
bool ForceNonTSO = AccessType == MemoryAccessType::NONTSO || AccessType == MemoryAccessType::STREAM;
|
||||
return _LoadMemAutoTSO(Class, OpSize, A, Align == -1 ? OpSize : Align, ForceNonTSO);
|
||||
} else {
|
||||
return LoadEffectiveAddress(A, AllowUpperGarbage);
|
||||
}
|
||||
return Src;
|
||||
}
|
||||
|
||||
OrderedNode* OpDispatchBuilder::GetRelocatedPC(const FEXCore::X86Tables::DecodedOp& Op, int64_t Offset) {
|
||||
@@ -4462,13 +4475,14 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
|
||||
|
||||
// 8Bit and 16bit destination types store their result without effecting the upper bits
|
||||
// 32bit ops ZEXT the result to 64bit
|
||||
OrderedNode* MemStoreDst {nullptr};
|
||||
bool MemStore = false;
|
||||
const uint8_t GPRSize = CTX->GetGPRSize();
|
||||
const uint32_t AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize;
|
||||
|
||||
AddressMode A {};
|
||||
A.AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize;
|
||||
|
||||
if (Operand.IsLiteral()) {
|
||||
MemStoreDst = _Constant(Operand.Data.Literal.Size * 8, Operand.Data.Literal.Value);
|
||||
A.Offset = Operand.Data.Literal.Value;
|
||||
MemStore = true; // Literals are ONLY hardcoded memory destinations
|
||||
} else if (Operand.IsGPR()) {
|
||||
const auto gpr = Operand.Data.GPR.GPR;
|
||||
@@ -4517,80 +4531,39 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
|
||||
}
|
||||
}
|
||||
} else if (Operand.IsGPRDirect()) {
|
||||
MemStoreDst = LoadGPRRegister(Operand.Data.GPR.GPR, GPRSize);
|
||||
A.Base = LoadGPRRegister(Operand.Data.GPR.GPR, GPRSize);
|
||||
|
||||
MemStore = true;
|
||||
if (Operand.Data.GPR.GPR == FEXCore::X86State::REG_RSP && AccessType == MemoryAccessType::DEFAULT) {
|
||||
AccessType = MemoryAccessType::NONTSO;
|
||||
}
|
||||
} else if (Operand.IsGPRIndirect()) {
|
||||
auto GPR = LoadGPRRegister(Operand.Data.GPRIndirect.GPR, GPRSize);
|
||||
auto Constant = _Constant(GPRSize * 8, Operand.Data.GPRIndirect.Displacement);
|
||||
A.Base = LoadGPRRegister(Operand.Data.GPRIndirect.GPR, GPRSize);
|
||||
A.Offset = Operand.Data.GPRIndirect.Displacement;
|
||||
|
||||
MemStoreDst = _Add(IR::SizeToOpSize(GPRSize), GPR, Constant);
|
||||
MemStore = true;
|
||||
if (Operand.Data.GPRIndirect.GPR == FEXCore::X86State::REG_RSP && AccessType == MemoryAccessType::DEFAULT) {
|
||||
AccessType = MemoryAccessType::NONTSO;
|
||||
}
|
||||
} else if (Operand.IsRIPRelative()) {
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
MemStoreDst = GetRelocatedPC(Op, Operand.Data.RIPLiteral.Value.s);
|
||||
A.Base = GetRelocatedPC(Op, Operand.Data.RIPLiteral.Value.s);
|
||||
} else {
|
||||
// 32bit this isn't RIP relative but instead absolute
|
||||
MemStoreDst = _Constant(GPRSize * 8, Operand.Data.RIPLiteral.Value.u);
|
||||
A.Offset = Operand.Data.RIPLiteral.Value.u;
|
||||
}
|
||||
MemStore = true;
|
||||
} else if (Operand.IsSIB()) {
|
||||
OrderedNode* Tmp {};
|
||||
|
||||
if (Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID && Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) {
|
||||
auto Base = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize);
|
||||
auto Index = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize);
|
||||
if (Operand.Data.SIB.Scale == 1) {
|
||||
Tmp = _Add(IR::SizeToOpSize(GPRSize), Base, Index);
|
||||
} else {
|
||||
Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Base, Index, ShiftType::LSL, FEXCore::ilog2(Operand.Data.SIB.Scale));
|
||||
}
|
||||
} else {
|
||||
if (Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID) {
|
||||
Tmp = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize);
|
||||
|
||||
if (Operand.Data.SIB.Scale != 1) {
|
||||
auto Constant = _Constant(GPRSize * 8, Operand.Data.SIB.Scale);
|
||||
Tmp = _Mul(IR::SizeToOpSize(GPRSize), Tmp, Constant);
|
||||
}
|
||||
}
|
||||
|
||||
if (Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) {
|
||||
auto GPR = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize);
|
||||
|
||||
if (Tmp != nullptr) {
|
||||
Tmp = _Add(IR::SizeToOpSize(GPRSize), Tmp, GPR);
|
||||
} else {
|
||||
Tmp = GPR;
|
||||
}
|
||||
}
|
||||
if (Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) {
|
||||
A.Base = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize);
|
||||
}
|
||||
|
||||
if (Operand.Data.SIB.Offset) {
|
||||
if (Tmp != nullptr) {
|
||||
MemStoreDst = _Add(IR::SizeToOpSize(GPRSize), Tmp, _Constant(GPRSize * 8, Operand.Data.SIB.Offset));
|
||||
} else {
|
||||
MemStoreDst = _Constant(GPRSize * 8, Operand.Data.SIB.Offset);
|
||||
}
|
||||
} else {
|
||||
if (Tmp != nullptr) {
|
||||
MemStoreDst = Tmp;
|
||||
} else {
|
||||
MemStoreDst = _Constant(GPRSize * 8, 0);
|
||||
}
|
||||
if (Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID) {
|
||||
A.Index = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize);
|
||||
}
|
||||
|
||||
if (AddrSize < GPRSize) {
|
||||
// If AddrSize == 16 then we need to clear the upper bits
|
||||
// GPRSize will be 32 in this case
|
||||
MemStoreDst = _Bfe(IR::SizeToOpSize(std::max<uint8_t>(4u, AddrSize)), AddrSize * 8, 0, MemStoreDst);
|
||||
}
|
||||
A.IndexScale = Operand.Data.SIB.Scale;
|
||||
A.Offset = Operand.Data.SIB.Offset;
|
||||
|
||||
if ((Operand.Data.SIB.Base == FEXCore::X86State::REG_RSP || Operand.Data.SIB.Index == FEXCore::X86State::REG_RSP) &&
|
||||
AccessType == MemoryAccessType::DEFAULT) {
|
||||
@@ -4601,20 +4574,18 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
|
||||
}
|
||||
|
||||
if (MemStore) {
|
||||
MemStoreDst = AppendSegmentOffset(MemStoreDst, Op->Flags);
|
||||
A = AddSegmentToAddress(A, Op->Flags);
|
||||
|
||||
if (OpSize == 10) {
|
||||
OrderedNode* MemStoreDst = LoadEffectiveAddress(A);
|
||||
|
||||
// For X87 extended doubles, split before storing
|
||||
_StoreMem(FPRClass, 8, MemStoreDst, Src, Align);
|
||||
auto Upper = _VExtractToGPR(16, 8, Src, 1);
|
||||
auto DestAddr = _Add(OpSize::i64Bit, MemStoreDst, _Constant(8));
|
||||
_StoreMem(GPRClass, 2, DestAddr, Upper, std::min<uint8_t>(Align, 8));
|
||||
_StoreMem(GPRClass, 2, Upper, MemStoreDst, _Constant(8), std::min<uint8_t>(Align, 8), MEM_OFFSET_SXTX, 1);
|
||||
} else {
|
||||
if (AccessType == MemoryAccessType::NONTSO || AccessType == MemoryAccessType::STREAM) {
|
||||
_StoreMem(Class, OpSize, MemStoreDst, Src, Align == -1 ? OpSize : Align);
|
||||
} else {
|
||||
_StoreMemAutoTSO(Class, OpSize, MemStoreDst, Src, Align == -1 ? OpSize : Align);
|
||||
}
|
||||
bool ForceNonTSO = AccessType == MemoryAccessType::NONTSO || AccessType == MemoryAccessType::STREAM;
|
||||
_StoreMemAutoTSO(Class, OpSize, A, Src, Align == -1 ? OpSize : Align, ForceNonTSO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user