summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar merry2022-02-27 19:40:05 +0000
committerGravatar merry2022-02-27 19:40:05 +0000
commit16784e5bb3dd043f9430401097a4be42ad21eb91 (patch)
treed09e952371f9e7e90aecba4d8b4e9654d10c50a2 /src
parentMerge pull request #7955 from bunnei/update-dynarmic (diff)
downloadyuzu-16784e5bb3dd043f9430401097a4be42ad21eb91.tar.gz
yuzu-16784e5bb3dd043f9430401097a4be42ad21eb91.tar.xz
yuzu-16784e5bb3dd043f9430401097a4be42ad21eb91.zip
dynarmic: Inline exclusive memory accesses
Inlines implementation of exclusive instructions into JITted code, improving performance of applications relying heavily on these instructions. We also fastmem these instructions for additional speed, with support for appropriate recompilation on fastmem failure. An unsafe optimization to disable the intercore global_monitor is also provided, should one wish to rely solely on cmpxchg semantics for safety. See also: merryhime/dynarmic#664
Diffstat (limited to '')
-rw-r--r--src/common/settings.cpp1
-rw-r--r--src/common/settings.h3
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp12
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp13
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.cpp4
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.h2
-rw-r--r--src/core/arm/exclusive_monitor.h2
-rw-r--r--src/core/hle/kernel/k_address_arbiter.cpp4
-rw-r--r--src/yuzu/configuration/config.cpp4
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp9
-rw-r--r--src/yuzu/configuration/configure_cpu.h1
-rw-r--r--src/yuzu/configuration/configure_cpu.ui12
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.cpp8
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.ui29
-rw-r--r--src/yuzu_cmd/config.cpp3
-rw-r--r--src/yuzu_cmd/default_ini.h13
16 files changed, 113 insertions, 7 deletions
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 2810cec15..877e0faa4 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -176,6 +176,7 @@ void RestoreGlobalState(bool is_powered_on) {
176 values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true); 176 values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true);
177 values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true); 177 values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
178 values.cpuopt_unsafe_fastmem_check.SetGlobal(true); 178 values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
179 values.cpuopt_unsafe_ignore_global_monitor.SetGlobal(true);
179 180
180 // Renderer 181 // Renderer
181 values.renderer_backend.SetGlobal(true); 182 values.renderer_backend.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index d06b23a14..a37d83fb3 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -484,12 +484,15 @@ struct Values {
484 BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"}; 484 BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
485 BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"}; 485 BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
486 BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"}; 486 BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
487 BasicSetting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
488 BasicSetting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
487 489
488 Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"}; 490 Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
489 Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"}; 491 Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
490 Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"}; 492 Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"};
491 Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"}; 493 Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
492 Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"}; 494 Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
495 Setting<bool> cpuopt_unsafe_ignore_global_monitor{true, "cpuopt_unsafe_ignore_global_monitor"};
493 496
494 // Renderer 497 // Renderer
495 RangedSetting<RendererBackend> renderer_backend{ 498 RangedSetting<RendererBackend> renderer_backend{
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index b0d89c539..286976623 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -137,6 +137,8 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
137 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; 137 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
138 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; 138 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
139 config.only_detect_misalignment_via_page_table_on_page_boundary = true; 139 config.only_detect_misalignment_via_page_table_on_page_boundary = true;
140 config.fastmem_exclusive_access = true;
141 config.recompile_on_exclusive_fastmem_failure = true;
140 142
141 // Multi-process state 143 // Multi-process state
142 config.processor_id = core_index; 144 config.processor_id = core_index;
@@ -178,6 +180,12 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
178 if (!Settings::values.cpuopt_fastmem) { 180 if (!Settings::values.cpuopt_fastmem) {
179 config.fastmem_pointer = nullptr; 181 config.fastmem_pointer = nullptr;
180 } 182 }
183 if (!Settings::values.cpuopt_fastmem_exclusives) {
184 config.fastmem_exclusive_access = false;
185 }
186 if (!Settings::values.cpuopt_recompile_exclusives) {
187 config.recompile_on_exclusive_fastmem_failure = false;
188 }
181 } 189 }
182 190
183 // Unsafe optimizations 191 // Unsafe optimizations
@@ -195,6 +203,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
195 if (Settings::values.cpuopt_unsafe_inaccurate_nan) { 203 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
196 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 204 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
197 } 205 }
206 if (Settings::values.cpuopt_unsafe_ignore_global_monitor) {
207 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
208 }
198 } 209 }
199 210
200 // Curated optimizations 211 // Curated optimizations
@@ -203,6 +214,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
203 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 214 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
204 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; 215 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
205 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 216 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
217 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
206 } 218 }
207 219
208 return std::make_unique<Dynarmic::A32::Jit>(config); 220 return std::make_unique<Dynarmic::A32::Jit>(config);
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 56836bd05..d96226c41 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -185,6 +185,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
185 config.fastmem_pointer = page_table->fastmem_arena; 185 config.fastmem_pointer = page_table->fastmem_arena;
186 config.fastmem_address_space_bits = address_space_bits; 186 config.fastmem_address_space_bits = address_space_bits;
187 config.silently_mirror_fastmem = false; 187 config.silently_mirror_fastmem = false;
188
189 config.fastmem_exclusive_access = true;
190 config.recompile_on_exclusive_fastmem_failure = true;
188 } 191 }
189 192
190 // Multi-process state 193 // Multi-process state
@@ -237,6 +240,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
237 if (!Settings::values.cpuopt_fastmem) { 240 if (!Settings::values.cpuopt_fastmem) {
238 config.fastmem_pointer = nullptr; 241 config.fastmem_pointer = nullptr;
239 } 242 }
243 if (!Settings::values.cpuopt_fastmem_exclusives) {
244 config.fastmem_exclusive_access = false;
245 }
246 if (!Settings::values.cpuopt_recompile_exclusives) {
247 config.recompile_on_exclusive_fastmem_failure = false;
248 }
240 } 249 }
241 250
242 // Unsafe optimizations 251 // Unsafe optimizations
@@ -254,6 +263,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
254 if (Settings::values.cpuopt_unsafe_fastmem_check) { 263 if (Settings::values.cpuopt_unsafe_fastmem_check) {
255 config.fastmem_address_space_bits = 64; 264 config.fastmem_address_space_bits = 64;
256 } 265 }
266 if (Settings::values.cpuopt_unsafe_ignore_global_monitor) {
267 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
268 }
257 } 269 }
258 270
259 // Curated optimizations 271 // Curated optimizations
@@ -262,6 +274,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
262 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 274 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
263 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 275 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
264 config.fastmem_address_space_bits = 64; 276 config.fastmem_address_space_bits = 64;
277 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
265 } 278 }
266 279
267 return std::make_shared<Dynarmic::A64::Jit>(config); 280 return std::make_shared<Dynarmic::A64::Jit>(config);
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp b/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
index 397d054a8..ea6b224e0 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
+++ b/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
@@ -37,8 +37,8 @@ u128 DynarmicExclusiveMonitor::ExclusiveRead128(std::size_t core_index, VAddr ad
37 }); 37 });
38} 38}
39 39
40void DynarmicExclusiveMonitor::ClearExclusive() { 40void DynarmicExclusiveMonitor::ClearExclusive(std::size_t core_index) {
41 monitor.Clear(); 41 monitor.ClearProcessor(core_index);
42} 42}
43 43
44bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { 44bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.h b/src/core/arm/dynarmic/arm_exclusive_monitor.h
index 265c4ecef..5a15b43ef 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/arm_exclusive_monitor.h
@@ -29,7 +29,7 @@ public:
29 u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override; 29 u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override;
30 u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override; 30 u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override;
31 u128 ExclusiveRead128(std::size_t core_index, VAddr addr) override; 31 u128 ExclusiveRead128(std::size_t core_index, VAddr addr) override;
32 void ClearExclusive() override; 32 void ClearExclusive(std::size_t core_index) override;
33 33
34 bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override; 34 bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override;
35 bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override; 35 bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override;
diff --git a/src/core/arm/exclusive_monitor.h b/src/core/arm/exclusive_monitor.h
index 62f6e6023..9914ca3da 100644
--- a/src/core/arm/exclusive_monitor.h
+++ b/src/core/arm/exclusive_monitor.h
@@ -23,7 +23,7 @@ public:
23 virtual u32 ExclusiveRead32(std::size_t core_index, VAddr addr) = 0; 23 virtual u32 ExclusiveRead32(std::size_t core_index, VAddr addr) = 0;
24 virtual u64 ExclusiveRead64(std::size_t core_index, VAddr addr) = 0; 24 virtual u64 ExclusiveRead64(std::size_t core_index, VAddr addr) = 0;
25 virtual u128 ExclusiveRead128(std::size_t core_index, VAddr addr) = 0; 25 virtual u128 ExclusiveRead128(std::size_t core_index, VAddr addr) = 0;
26 virtual void ClearExclusive() = 0; 26 virtual void ClearExclusive(std::size_t core_index) = 0;
27 27
28 virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0; 28 virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0;
29 virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0; 29 virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0;
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp
index 783c69858..1d1f5e5f8 100644
--- a/src/core/hle/kernel/k_address_arbiter.cpp
+++ b/src/core/hle/kernel/k_address_arbiter.cpp
@@ -49,7 +49,7 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu
49 } 49 }
50 } else { 50 } else {
51 // Otherwise, clear our exclusive hold and finish 51 // Otherwise, clear our exclusive hold and finish
52 monitor.ClearExclusive(); 52 monitor.ClearExclusive(current_core);
53 } 53 }
54 54
55 // We're done. 55 // We're done.
@@ -78,7 +78,7 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32
78 } 78 }
79 } else { 79 } else {
80 // Otherwise, clear our exclusive hold and finish. 80 // Otherwise, clear our exclusive hold and finish.
81 monitor.ClearExclusive(); 81 monitor.ClearExclusive(current_core);
82 } 82 }
83 83
84 // We're done. 84 // We're done.
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index f915bd856..c2b66ff14 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -609,6 +609,7 @@ void Config::ReadCpuValues() {
609 ReadGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr); 609 ReadGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
610 ReadGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan); 610 ReadGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
611 ReadGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check); 611 ReadGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
612 ReadGlobalSetting(Settings::values.cpuopt_unsafe_ignore_global_monitor);
612 613
613 if (global) { 614 if (global) {
614 ReadBasicSetting(Settings::values.cpu_debug_mode); 615 ReadBasicSetting(Settings::values.cpu_debug_mode);
@@ -621,6 +622,8 @@ void Config::ReadCpuValues() {
621 ReadBasicSetting(Settings::values.cpuopt_misc_ir); 622 ReadBasicSetting(Settings::values.cpuopt_misc_ir);
622 ReadBasicSetting(Settings::values.cpuopt_reduce_misalign_checks); 623 ReadBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
623 ReadBasicSetting(Settings::values.cpuopt_fastmem); 624 ReadBasicSetting(Settings::values.cpuopt_fastmem);
625 ReadBasicSetting(Settings::values.cpuopt_fastmem_exclusives);
626 ReadBasicSetting(Settings::values.cpuopt_recompile_exclusives);
624 } 627 }
625 628
626 qt_config->endGroup(); 629 qt_config->endGroup();
@@ -1139,6 +1142,7 @@ void Config::SaveCpuValues() {
1139 WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr); 1142 WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
1140 WriteGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan); 1143 WriteGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
1141 WriteGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check); 1144 WriteGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
1145 WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_global_monitor);
1142 1146
1143 if (global) { 1147 if (global) {
1144 WriteBasicSetting(Settings::values.cpu_debug_mode); 1148 WriteBasicSetting(Settings::values.cpu_debug_mode);
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index f66cab5d4..bf74ccc7c 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -36,6 +36,7 @@ void ConfigureCpu::SetConfiguration() {
36 ui->cpuopt_unsafe_ignore_standard_fpcr->setEnabled(runtime_lock); 36 ui->cpuopt_unsafe_ignore_standard_fpcr->setEnabled(runtime_lock);
37 ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock); 37 ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock);
38 ui->cpuopt_unsafe_fastmem_check->setEnabled(runtime_lock); 38 ui->cpuopt_unsafe_fastmem_check->setEnabled(runtime_lock);
39 ui->cpuopt_unsafe_ignore_global_monitor->setEnabled(runtime_lock);
39 40
40 ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()); 41 ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue());
41 ui->cpuopt_unsafe_reduce_fp_error->setChecked( 42 ui->cpuopt_unsafe_reduce_fp_error->setChecked(
@@ -46,6 +47,8 @@ void ConfigureCpu::SetConfiguration() {
46 Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()); 47 Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue());
47 ui->cpuopt_unsafe_fastmem_check->setChecked( 48 ui->cpuopt_unsafe_fastmem_check->setChecked(
48 Settings::values.cpuopt_unsafe_fastmem_check.GetValue()); 49 Settings::values.cpuopt_unsafe_fastmem_check.GetValue());
50 ui->cpuopt_unsafe_ignore_global_monitor->setChecked(
51 Settings::values.cpuopt_unsafe_ignore_global_monitor.GetValue());
49 52
50 if (Settings::IsConfiguringGlobal()) { 53 if (Settings::IsConfiguringGlobal()) {
51 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy.GetValue())); 54 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy.GetValue()));
@@ -82,6 +85,9 @@ void ConfigureCpu::ApplyConfiguration() {
82 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check, 85 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check,
83 ui->cpuopt_unsafe_fastmem_check, 86 ui->cpuopt_unsafe_fastmem_check,
84 cpuopt_unsafe_fastmem_check); 87 cpuopt_unsafe_fastmem_check);
88 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_ignore_global_monitor,
89 ui->cpuopt_unsafe_ignore_global_monitor,
90 cpuopt_unsafe_ignore_global_monitor);
85} 91}
86 92
87void ConfigureCpu::changeEvent(QEvent* event) { 93void ConfigureCpu::changeEvent(QEvent* event) {
@@ -120,4 +126,7 @@ void ConfigureCpu::SetupPerGameUI() {
120 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_fastmem_check, 126 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_fastmem_check,
121 Settings::values.cpuopt_unsafe_fastmem_check, 127 Settings::values.cpuopt_unsafe_fastmem_check,
122 cpuopt_unsafe_fastmem_check); 128 cpuopt_unsafe_fastmem_check);
129 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_ignore_global_monitor,
130 Settings::values.cpuopt_unsafe_ignore_global_monitor,
131 cpuopt_unsafe_ignore_global_monitor);
123} 132}
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index ed9af0e9f..733e38be4 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -45,6 +45,7 @@ private:
45 ConfigurationShared::CheckState cpuopt_unsafe_ignore_standard_fpcr; 45 ConfigurationShared::CheckState cpuopt_unsafe_ignore_standard_fpcr;
46 ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan; 46 ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan;
47 ConfigurationShared::CheckState cpuopt_unsafe_fastmem_check; 47 ConfigurationShared::CheckState cpuopt_unsafe_fastmem_check;
48 ConfigurationShared::CheckState cpuopt_unsafe_ignore_global_monitor;
48 49
49 const Core::System& system; 50 const Core::System& system;
50}; 51};
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index d8064db24..5d80a8c91 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -150,6 +150,18 @@
150 </property> 150 </property>
151 </widget> 151 </widget>
152 </item> 152 </item>
153 <item>
154 <widget class="QCheckBox" name="cpuopt_unsafe_ignore_global_monitor">
155 <property name="toolTip">
156 <string>
157 &lt;div&gt;This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions.&lt;/div&gt;
158 </string>
159 </property>
160 <property name="text">
161 <string>Ignore global monitor</string>
162 </property>
163 </widget>
164 </item>
153 </layout> 165 </layout>
154 </widget> 166 </widget>
155 </item> 167 </item>
diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp
index 05a90963d..616a0be75 100644
--- a/src/yuzu/configuration/configure_cpu_debug.cpp
+++ b/src/yuzu/configuration/configure_cpu_debug.cpp
@@ -44,6 +44,12 @@ void ConfigureCpuDebug::SetConfiguration() {
44 Settings::values.cpuopt_reduce_misalign_checks.GetValue()); 44 Settings::values.cpuopt_reduce_misalign_checks.GetValue());
45 ui->cpuopt_fastmem->setEnabled(runtime_lock); 45 ui->cpuopt_fastmem->setEnabled(runtime_lock);
46 ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem.GetValue()); 46 ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem.GetValue());
47 ui->cpuopt_fastmem_exclusives->setEnabled(runtime_lock);
48 ui->cpuopt_fastmem_exclusives->setChecked(
49 Settings::values.cpuopt_fastmem_exclusives.GetValue());
50 ui->cpuopt_recompile_exclusives->setEnabled(runtime_lock);
51 ui->cpuopt_recompile_exclusives->setChecked(
52 Settings::values.cpuopt_recompile_exclusives.GetValue());
47} 53}
48 54
49void ConfigureCpuDebug::ApplyConfiguration() { 55void ConfigureCpuDebug::ApplyConfiguration() {
@@ -56,6 +62,8 @@ void ConfigureCpuDebug::ApplyConfiguration() {
56 Settings::values.cpuopt_misc_ir = ui->cpuopt_misc_ir->isChecked(); 62 Settings::values.cpuopt_misc_ir = ui->cpuopt_misc_ir->isChecked();
57 Settings::values.cpuopt_reduce_misalign_checks = ui->cpuopt_reduce_misalign_checks->isChecked(); 63 Settings::values.cpuopt_reduce_misalign_checks = ui->cpuopt_reduce_misalign_checks->isChecked();
58 Settings::values.cpuopt_fastmem = ui->cpuopt_fastmem->isChecked(); 64 Settings::values.cpuopt_fastmem = ui->cpuopt_fastmem->isChecked();
65 Settings::values.cpuopt_fastmem_exclusives = ui->cpuopt_fastmem_exclusives->isChecked();
66 Settings::values.cpuopt_recompile_exclusives = ui->cpuopt_recompile_exclusives->isChecked();
59} 67}
60 68
61void ConfigureCpuDebug::changeEvent(QEvent* event) { 69void ConfigureCpuDebug::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_cpu_debug.ui b/src/yuzu/configuration/configure_cpu_debug.ui
index 6e635bb2f..2bc268810 100644
--- a/src/yuzu/configuration/configure_cpu_debug.ui
+++ b/src/yuzu/configuration/configure_cpu_debug.ui
@@ -144,7 +144,34 @@
144 </string> 144 </string>
145 </property> 145 </property>
146 <property name="text"> 146 <property name="text">
147 <string>Enable Host MMU Emulation</string> 147 <string>Enable Host MMU Emulation (general memory instructions)</string>
148 </property>
149 </widget>
150 </item>
151 <item>
152 <widget class="QCheckBox" name="cpuopt_fastmem_exclusives">
153 <property name="toolTip">
154 <string>
155 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up exclusive memory accesses by the guest program.&lt;/div&gt;
156 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt;
157 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all exclusive memory accesses to use Software MMU Emulation.&lt;/div&gt;
158 </string>
159 </property>
160 <property name="text">
161 <string>Enable Host MMU Emulation (exclusive memory instructions)</string>
162 </property>
163 </widget>
164 </item>
165 <item>
166 <widget class="QCheckBox" name="cpuopt_recompile_exclusives">
167 <property name="toolTip">
168 <string>
169 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up exclusive memory accesses by the guest program.&lt;/div&gt;
170 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.&lt;/div&gt;
171 </string>
172 </property>
173 <property name="text">
174 <string>Enable recompilation of exclusive memory instructions</string>
148 </property> 175 </property>
149 </widget> 176 </widget>
150 </item> 177 </item>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 30963a8bb..b74411c84 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -280,11 +280,14 @@ void Config::ReadValues() {
280 ReadSetting("Cpu", Settings::values.cpuopt_misc_ir); 280 ReadSetting("Cpu", Settings::values.cpuopt_misc_ir);
281 ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks); 281 ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks);
282 ReadSetting("Cpu", Settings::values.cpuopt_fastmem); 282 ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
283 ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives);
284 ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives);
283 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma); 285 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma);
284 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error); 286 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error);
285 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr); 287 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
286 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan); 288 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan);
287 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check); 289 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check);
290 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor);
288 291
289 // Renderer 292 // Renderer
290 ReadSetting("Renderer", Settings::values.renderer_backend); 293 ReadSetting("Renderer", Settings::values.renderer_backend);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 6d613bf7a..3ac1440c9 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -174,6 +174,14 @@ cpuopt_reduce_misalign_checks =
174# 0: Disabled, 1 (default): Enabled 174# 0: Disabled, 1 (default): Enabled
175cpuopt_fastmem = 175cpuopt_fastmem =
176 176
177# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access)
178# 0: Disabled, 1 (default): Enabled
179cpuopt_fastmem_exclusives =
180
181# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access)
182# 0: Disabled, 1 (default): Enabled
183cpuopt_recompile_exclusives =
184
177# Enable unfuse FMA (improve performance on CPUs without FMA) 185# Enable unfuse FMA (improve performance on CPUs without FMA)
178# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. 186# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
179# 0: Disabled, 1 (default): Enabled 187# 0: Disabled, 1 (default): Enabled
@@ -199,6 +207,11 @@ cpuopt_unsafe_inaccurate_nan =
199# 0: Disabled, 1 (default): Enabled 207# 0: Disabled, 1 (default): Enabled
200cpuopt_unsafe_fastmem_check = 208cpuopt_unsafe_fastmem_check =
201 209
210# Enable faster exclusive instructions
211# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
212# 0: Disabled, 1 (default): Enabled
213cpuopt_unsafe_ignore_global_monitor =
214
202[Renderer] 215[Renderer]
203# Which backend API to use. 216# Which backend API to use.
204# 0 (default): OpenGL, 1: Vulkan 217# 0 (default): OpenGL, 1: Vulkan