aboutsummaryrefslogtreecommitdiff
path: root/src/dynarmic
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-11-01 15:13:31 -0500
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-11-01 15:13:31 -0500
commitf21d6c0a49a90fd6ec919de438a07da11ead12d9 (patch)
treedaa3d3123b3e6274ed0f1dd4b4400ff9be10f503 /src/dynarmic
parent1337d7f4650045d7aa2a50db93a0fbdcadefd55d (diff)
parent34f81e052c37973a69aeec39e2f996b89c80e4ad (diff)
Merge remote-tracking branch 'origin/fix/dynarmic-compact-block-tables' into test/linux-all-prs-plus
Diffstat (limited to 'src/dynarmic')
-rw-r--r--src/dynarmic/src/dynarmic/backend/block_range_information.cpp27
-rw-r--r--src/dynarmic/src/dynarmic/backend/block_range_information.h18
-rw-r--r--src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp6
-rw-r--r--src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h14
-rw-r--r--src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp6
-rw-r--r--src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h14
-rw-r--r--src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp70
-rw-r--r--src/dynarmic/src/dynarmic/backend/x64/emit_x64.h12
-rw-r--r--src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc81
9 files changed, 151 insertions, 97 deletions
diff --git a/src/dynarmic/src/dynarmic/backend/block_range_information.cpp b/src/dynarmic/src/dynarmic/backend/block_range_information.cpp
index 1a56b7adb6..068e86c2bc 100644
--- a/src/dynarmic/src/dynarmic/backend/block_range_information.cpp
+++ b/src/dynarmic/src/dynarmic/backend/block_range_information.cpp
@@ -8,7 +8,8 @@
#include "dynarmic/backend/block_range_information.h"
-#include <boost/icl/interval_map.hpp>
+#include <algorithm>
+
#include <boost/icl/interval_set.hpp>
#include "common/common_types.h"
#include "common/container/unordered_set.h"
@@ -17,24 +18,28 @@ namespace Dynarmic::Backend {
template<typename P>
void BlockRangeInformation<P>::AddRange(boost::icl::discrete_interval<P> range, IR::LocationDescriptor location) {
- block_ranges.add(std::make_pair(range, ::Common::unordered_set<IR::LocationDescriptor>{location}));
+ if (!boost::icl::is_empty(range)) {
+ ranges.push_back({boost::icl::first(range), boost::icl::last(range), location});
+ }
}
template<typename P>
void BlockRangeInformation<P>::ClearCache() {
- block_ranges.clear();
+ ranges.clear();
}
template<typename P>
-::Common::unordered_set<IR::LocationDescriptor> BlockRangeInformation<P>::InvalidateRanges(const boost::icl::interval_set<P>& ranges) {
+::Common::unordered_set<IR::LocationDescriptor> BlockRangeInformation<P>::InvalidateRanges(const boost::icl::interval_set<P>& invalidated) {
::Common::unordered_set<IR::LocationDescriptor> erase_locations;
- for (auto invalidate_interval : ranges) {
- auto pair = block_ranges.equal_range(invalidate_interval);
- for (auto it = pair.first; it != pair.second; ++it)
- for (const auto& descriptor : it->second)
- erase_locations.insert(descriptor);
- }
- // TODO: EFFICIENCY: Remove ranges that are to be erased.
+ std::erase_if(ranges, [&](const Range& range) {
+ for (const auto& interval : invalidated) {
+ if (range.first <= boost::icl::last(interval) && boost::icl::first(interval) <= range.last) {
+ erase_locations.insert(range.location);
+ return true;
+ }
+ }
+ return false;
+ });
return erase_locations;
}
diff --git a/src/dynarmic/src/dynarmic/backend/block_range_information.h b/src/dynarmic/src/dynarmic/backend/block_range_information.h
index 8f7daa9d9c..f894240603 100644
--- a/src/dynarmic/src/dynarmic/backend/block_range_information.h
+++ b/src/dynarmic/src/dynarmic/backend/block_range_information.h
@@ -8,11 +8,9 @@
#pragma once
-#include <set>
+#include <vector>
-#include <boost/icl/interval_map.hpp>
#include <boost/icl/interval_set.hpp>
-#include "common/container/unordered_map.h"
#include "common/container/unordered_set.h"
#include "dynarmic/ir/location_descriptor.h"
@@ -24,8 +22,18 @@ class BlockRangeInformation {
public:
void AddRange(boost::icl::discrete_interval<P> range, IR::LocationDescriptor location);
void ClearCache();
- ::Common::unordered_set<IR::LocationDescriptor> InvalidateRanges(const boost::icl::interval_set<P>& ranges);
- boost::icl::interval_map<P, ::Common::unordered_set<IR::LocationDescriptor>> block_ranges;
+ ::Common::unordered_set<IR::LocationDescriptor> InvalidateRanges(const boost::icl::interval_set<P>& invalidated);
+
+private:
+ /// The guest code [first, last] a block was translated from. Code is invalidated rarely (when
+ /// it is unmapped or reprotected), so a list scanned then costs least: an interval map of
+ /// block sets held ~300 bytes per block.
+ struct Range {
+ P first;
+ P last;
+ IR::LocationDescriptor location;
+ };
+ std::vector<Range> ranges;
};
} // namespace Dynarmic::Backend
diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp
index 5c6a90e15a..e0e3c463d1 100644
--- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp
+++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp
@@ -1168,7 +1168,7 @@ bool EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationD
} else {
if (e.conf.enable_cycle_counting) {
e.code.cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0);
- e.patch_information[terminal.next].jg.push_back(e.code.getCurr());
+ e.AddPatchLocation(terminal.next, EmitX64::PatchKind::Jg);
if (const auto next_bb = e.GetBasicBlock(terminal.next)) {
e.EmitPatchJg(terminal.next, next_bb->entrypoint);
} else {
@@ -1176,7 +1176,7 @@ bool EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationD
}
} else {
e.code.cmp(dword[e.code.ABI_JIT_PTR + offsetof(A32JitState, halt_reason)], 0);
- e.patch_information[terminal.next].jz.push_back(e.code.getCurr());
+ e.AddPatchLocation(terminal.next, EmitX64::PatchKind::Jz);
if (const auto next_bb = e.GetBasicBlock(terminal.next)) {
e.EmitPatchJz(terminal.next, next_bb->entrypoint);
} else {
@@ -1196,7 +1196,7 @@ bool EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlockFast terminal, IR::Locat
e.code.mov(MJitStateReg(A32::Reg::PC), A32::LocationDescriptor{terminal.next}.PC());
e.code.ReturnFromRunCode();
} else {
- e.patch_information[terminal.next].jmp.push_back(e.code.getCurr());
+ e.AddPatchLocation(terminal.next, EmitX64::PatchKind::Jmp);
if (const auto next_bb = e.GetBasicBlock(terminal.next)) {
e.EmitPatchJmp(terminal.next, next_bb->entrypoint);
} else {
diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h
index a106bb6482..eb36bffd88 100644
--- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h
+++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h
@@ -87,13 +87,17 @@ public:
// Fastmem information
using DoNotFastmemMarker = std::tuple<IR::LocationDescriptor, unsigned>;
+ /// Where a fastmem access that faults goes: code addresses are offsets in the code space.
struct FastmemPatchInfo {
- u64 resume_rip;
- u64 callback;
- DoNotFastmemMarker marker;
- bool recompile;
+ u32 rip;
+ u32 resume_rip;
+ u32 callback;
+ u32 inst_name : 31;
+ u32 recompile : 1;
+ IR::LocationDescriptor location;
};
std::optional<DoNotFastmemMarker> ShouldFastmem(A32EmitContext& ctx, IR::Inst* inst) const;
+ void AddFastmemPatch(CodePtr location, CodePtr resume_location, void (*callback)(), const DoNotFastmemMarker& marker, bool recompile);
FakeCall FastmemCallback(u64 rip);
// Memory access helpers
@@ -127,7 +131,7 @@ public:
RegAlloc reg_alloc; //reusable reg alloc
BlockRangeInformation<u32> block_ranges;
std::array<FastDispatchEntry, fast_dispatch_table_size> fast_dispatch_table;
- ::Common::unordered_map<u64, FastmemPatchInfo> fastmem_patch_info;
+ std::vector<FastmemPatchInfo> fastmem_patch_info; // sorted by rip
::Common::unordered_map<std::tuple<bool, size_t, int, int>, void (*)()> read_fallbacks;
::Common::unordered_map<std::tuple<bool, size_t, int, int>, void (*)()> write_fallbacks;
::Common::unordered_map<std::tuple<bool, size_t, int, int>, void (*)()> exclusive_write_fallbacks;
diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp
index 71e5e62cd9..2307226744 100644
--- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp
+++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp
@@ -628,7 +628,7 @@ bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationD
if (e.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) {
if (e.conf.enable_cycle_counting) {
e.code.cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0);
- e.patch_information[terminal.next].jg.push_back(e.code.getCurr());
+ e.AddPatchLocation(terminal.next, EmitX64::PatchKind::Jg);
if (const auto next_bb = e.GetBasicBlock(terminal.next)) {
e.EmitPatchJg(terminal.next, next_bb->entrypoint);
} else {
@@ -636,7 +636,7 @@ bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationD
}
} else {
e.code.cmp(dword[e.code.ABI_JIT_PTR + offsetof(A64JitState, halt_reason)], 0);
- e.patch_information[terminal.next].jz.push_back(e.code.getCurr());
+ e.AddPatchLocation(terminal.next, EmitX64::PatchKind::Jz);
if (const auto next_bb = e.GetBasicBlock(terminal.next)) {
e.EmitPatchJz(terminal.next, next_bb->entrypoint);
} else {
@@ -656,7 +656,7 @@ bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationD
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor, bool is_single_step) {
if (e.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) {
- e.patch_information[terminal.next].jmp.push_back(e.code.getCurr());
+ e.AddPatchLocation(terminal.next, EmitX64::PatchKind::Jmp);
if (auto next_bb = e.GetBasicBlock(terminal.next)) {
e.EmitPatchJmp(terminal.next, next_bb->entrypoint);
} else {
diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h
index 1310b4ad34..a9f2d9b650 100644
--- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h
+++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h
@@ -83,13 +83,17 @@ public:
// Fastmem information
using DoNotFastmemMarker = std::tuple<IR::LocationDescriptor, unsigned>;
+ /// Where a fastmem access that faults goes: code addresses are offsets in the code space.
struct FastmemPatchInfo {
- u64 resume_rip;
- u64 callback;
- DoNotFastmemMarker marker;
- bool recompile;
+ u32 rip;
+ u32 resume_rip;
+ u32 callback;
+ u32 inst_name : 31;
+ u32 recompile : 1;
+ IR::LocationDescriptor location;
};
std::optional<DoNotFastmemMarker> ShouldFastmem(A64EmitContext& ctx, IR::Inst* inst) const;
+ void AddFastmemPatch(CodePtr location, CodePtr resume_location, void (*callback)(), const DoNotFastmemMarker& marker, bool recompile);
FakeCall FastmemCallback(u64 rip);
// Memory access helpers
@@ -123,7 +127,7 @@ public:
RegAlloc reg_alloc; //reusable reg alloc
BlockRangeInformation<u64> block_ranges;
std::array<FastDispatchEntry, fast_dispatch_table_size> fast_dispatch_table;
- ::Common::unordered_map<u64, FastmemPatchInfo> fastmem_patch_info;
+ std::vector<FastmemPatchInfo> fastmem_patch_info; // sorted by rip
::Common::unordered_map<std::tuple<bool, size_t, int, int>, void (*)()> read_fallbacks;
::Common::unordered_map<std::tuple<bool, size_t, int, int>, void (*)()> write_fallbacks;
::Common::unordered_map<std::tuple<bool, size_t, int, int>, void (*)()> exclusive_write_fallbacks;
diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp
index b9df3987ca..84b9888bf5 100644
--- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp
+++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp
@@ -102,7 +102,7 @@ void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, I
code.mov(index_reg.cvt32(), dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_rsb_ptr]);
code.mov(loc_desc_reg, target.Value());
- patch_information[target].mov_rcx.push_back(code.getCurr());
+ AddPatchLocation(target, PatchKind::MovRcx);
EmitPatchMovRcx(target_code_ptr);
code.mov(qword[code.ABI_JIT_PTR + index_reg * 8 + code.GetJitStateInfo().offsetof_rsb_location_descriptors], loc_desc_reg);
code.mov(qword[code.ABI_JIT_PTR + index_reg * 8 + code.GetJitStateInfo().offsetof_rsb_codeptrs], rcx);
@@ -357,37 +357,61 @@ EmitX64::BlockDescriptor EmitX64::RegisterBlock(const IR::LocationDescriptor& de
return block_desc;
}
-void EmitX64::Patch(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
- const CodePtr save_code_ptr = code.getCurr();
- const PatchInformation& patch_info = patch_information[target_desc];
-
- for (CodePtr location : patch_info.jg) {
- code.SetCodePtr(location);
- EmitPatchJg(target_desc, target_code_ptr);
+void EmitX64::AddPatchLocation(const IR::LocationDescriptor& target_desc, PatchKind kind) {
+ const size_t offset = code.getCurr<const u8*>() - static_cast<const u8*>(code.getCode());
+ ASSERT(offset > 0 && offset < (size_t(1) << 30));
+ const u32 entry = u32(offset << 2) | u32(kind);
+ PatchInformation& patch_info = patch_information[target_desc];
+ for (u32& slot : patch_info.first) {
+ if (slot == 0) {
+ slot = entry;
+ return;
+ }
}
-
- for (CodePtr location : patch_info.jz) {
- code.SetCodePtr(location);
- EmitPatchJz(target_desc, target_code_ptr);
+ if (!patch_info.rest) {
+ patch_info.rest = std::make_unique<std::vector<u32>>();
}
+ patch_info.rest->push_back(entry);
+}
- for (CodePtr location : patch_info.jmp) {
- code.SetCodePtr(location);
- EmitPatchJmp(target_desc, target_code_ptr);
+void EmitX64::Patch(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
+ const auto it = patch_information.find(target_desc);
+ if (it == patch_information.end()) {
+ return;
}
-
- for (CodePtr location : patch_info.mov_rcx) {
- code.SetCodePtr(location);
- EmitPatchMovRcx(target_code_ptr);
+ const CodePtr save_code_ptr = code.getCurr();
+ const auto patch = [&](u32 entry) {
+ code.SetCodePtr(static_cast<const u8*>(code.getCode()) + (entry >> 2));
+ switch (PatchKind(entry & 3)) {
+ case PatchKind::Jg:
+ EmitPatchJg(target_desc, target_code_ptr);
+ break;
+ case PatchKind::Jz:
+ EmitPatchJz(target_desc, target_code_ptr);
+ break;
+ case PatchKind::Jmp:
+ EmitPatchJmp(target_desc, target_code_ptr);
+ break;
+ case PatchKind::MovRcx:
+ EmitPatchMovRcx(target_code_ptr);
+ break;
+ }
+ };
+ for (const u32 entry : it->second.first) {
+ if (entry != 0) {
+ patch(entry);
+ }
+ }
+ if (it->second.rest) {
+ for (const u32 entry : *it->second.rest) {
+ patch(entry);
+ }
}
-
code.SetCodePtr(save_code_ptr);
}
void EmitX64::Unpatch(const IR::LocationDescriptor& target_desc) {
- if (patch_information.count(target_desc)) {
- Patch(target_desc, nullptr);
- }
+ Patch(target_desc, nullptr);
}
void EmitX64::ClearCache() {
diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h
index 5e540e5f70..327cac7668 100644
--- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h
+++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h
@@ -116,12 +116,16 @@ public:
virtual bool EmitTerminal(IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept = 0;
// Patching
+ enum class PatchKind : u32 { Jg, Jz, Jmp, MovRcx };
+ /// Places in emitted code that jump to a block (or load its entrypoint), patched when it is
+ /// compiled or invalidated: each the place's offset in the code space times four plus its
+ /// PatchKind, 0 when unused. Most blocks are linked from one or two places.
struct PatchInformation {
- boost::container::small_vector<CodePtr, 4> jg; //4*8=32
- boost::container::small_vector<CodePtr, 4> jz; //4*8=32
- boost::container::small_vector<CodePtr, 4> jmp; //4*8=32
- boost::container::small_vector<CodePtr, 4> mov_rcx; //4*8=32
+ std::array<u32, 2> first{};
+ std::unique_ptr<std::vector<u32>> rest;
};
+ /// Records that the code about to be emitted at the current position is a patch of `kind`.
+ void AddPatchLocation(const IR::LocationDescriptor& target_desc, PatchKind kind);
void Patch(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr);
virtual void Unpatch(const IR::LocationDescriptor& target_desc);
virtual void EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr = nullptr) = 0;
diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc
index 8bb8be3d5b..689e507abe 100644
--- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc
+++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc
@@ -30,15 +30,48 @@ std::optional<AxxEmitX64::DoNotFastmemMarker> AxxEmitX64::ShouldFastmem(AxxEmitC
return marker;
}
+void AxxEmitX64::AddFastmemPatch(CodePtr location, CodePtr resume_location, void (*callback)(), const DoNotFastmemMarker& marker, bool recompile) {
+ const u64 base = std::bit_cast<u64>(code.getCode());
+ const auto offset = [base](u64 address) {
+ ASSERT(address >= base && address - base <= UINT32_MAX);
+ return u32(address - base);
+ };
+ FastmemPatchInfo info{
+ .rip = offset(std::bit_cast<u64>(location)),
+ .resume_rip = offset(std::bit_cast<u64>(resume_location)),
+ .callback = offset(std::bit_cast<u64>(callback)),
+ .inst_name = 0,
+ .recompile = 0,
+ .location = std::get<0>(marker),
+ };
+ info.inst_name = std::get<1>(marker);
+ info.recompile = recompile ? 1 : 0;
+ // Code is emitted in address order; only a block's deferred fallbacks can come after a later
+ // access of the same block.
+ auto it = fastmem_patch_info.end();
+ if (!fastmem_patch_info.empty() && fastmem_patch_info.back().rip >= info.rip) {
+ it = std::lower_bound(fastmem_patch_info.begin(), fastmem_patch_info.end(), info.rip,
+ [](const FastmemPatchInfo& entry, u32 value) { return entry.rip < value; });
+ if (it != fastmem_patch_info.end() && it->rip == info.rip) {
+ return;
+ }
+ }
+ fastmem_patch_info.insert(it, info);
+}
+
FakeCall AxxEmitX64::FastmemCallback(u64 rip_) {
- const auto iter = fastmem_patch_info.find(rip_);
- if (iter != fastmem_patch_info.end()) {
+ const u64 base = std::bit_cast<u64>(code.getCode());
+ const auto iter = rip_ >= base && rip_ - base <= UINT32_MAX
+ ? std::lower_bound(fastmem_patch_info.begin(), fastmem_patch_info.end(), u32(rip_ - base),
+ [](const FastmemPatchInfo& entry, u32 value) { return entry.rip < value; })
+ : fastmem_patch_info.end();
+ if (iter != fastmem_patch_info.end() && iter->rip == u32(rip_ - base)) {
FakeCall result{
- .call_rip = iter->second.callback,
- .ret_rip = iter->second.resume_rip,
+ .call_rip = base + iter->callback,
+ .ret_rip = base + iter->resume_rip,
};
- if (iter->second.recompile) {
- const auto marker = iter->second.marker;
+ if (iter->recompile) {
+ const DoNotFastmemMarker marker{iter->location, static_cast<unsigned>(iter->inst_name)};
do_not_fastmem.insert(marker);
InvalidateBasicBlocks({std::get<0>(marker)});
}
@@ -99,14 +132,7 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
code.L(*abort);
code.call(wrapped_fn);
- fastmem_patch_info.emplace(
- std::bit_cast<u64>(location),
- FastmemPatchInfo{
- std::bit_cast<u64>(code.getCurr()),
- std::bit_cast<u64>(wrapped_fn),
- *fastmem_marker,
- conf.recompile_on_fastmem_failure,
- });
+ AddFastmemPatch(location, code.getCurr(), wrapped_fn, *fastmem_marker, conf.recompile_on_fastmem_failure);
EmitCheckMemoryAbort(ctx, inst, end);
code.jmp(*end, code.T_NEAR);
@@ -186,14 +212,7 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
code.L(*abort);
code.call(wrapped_fn);
- fastmem_patch_info.emplace(
- std::bit_cast<u64>(location),
- FastmemPatchInfo{
- std::bit_cast<u64>(code.getCurr()),
- std::bit_cast<u64>(wrapped_fn),
- *fastmem_marker,
- conf.recompile_on_fastmem_failure,
- });
+ AddFastmemPatch(location, code.getCurr(), wrapped_fn, *fastmem_marker, conf.recompile_on_fastmem_failure);
EmitCheckMemoryAbort(ctx, inst, end);
code.jmp(*end, code.T_NEAR);
@@ -357,14 +376,7 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
- fastmem_patch_info.emplace(
- std::bit_cast<u64>(location),
- FastmemPatchInfo{
- std::bit_cast<u64>(code.getCurr()),
- std::bit_cast<u64>(wrapped_fn),
- *fastmem_marker,
- conf.recompile_on_exclusive_fastmem_failure,
- });
+ AddFastmemPatch(location, code.getCurr(), wrapped_fn, *fastmem_marker, conf.recompile_on_exclusive_fastmem_failure);
code.L(*end);
@@ -495,14 +507,7 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
code.L(*abort);
code.call(wrapped_fn);
- fastmem_patch_info.emplace(
- std::bit_cast<u64>(location),
- FastmemPatchInfo{
- std::bit_cast<u64>(code.getCurr()),
- std::bit_cast<u64>(wrapped_fn),
- *fastmem_marker,
- conf.recompile_on_exclusive_fastmem_failure,
- });
+ AddFastmemPatch(location, code.getCurr(), wrapped_fn, *fastmem_marker, conf.recompile_on_exclusive_fastmem_failure);
code.xor_(status.cvt32(), status.cvt32()); //dep-break
code.test(code.al, code.al);