aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxtam <jj.tobola2@gmail.com>2026-10-30 21:49:15 +0100
committerxtam <jj.tobola2@gmail.com>2026-10-30 21:49:15 +0100
commita4a746b47b1d1ee02ddf1fe528c7db05800eec2c (patch)
tree320fd13bf6ceb1e8e88b0164ed0e1c5d9a714a3f /src
parent3e950dd677b6d7dca04541855ad5751d057371ea (diff)
fix: restore Mario Kart World text by accepting R0 shader returns
Do not treat the reserved destination field of Ampere RET as a write to the return-link register. Keep return linkage validation and rejection of actual link-register writes. Add three regression tests covering R0 and R55 links, copied links, and overwritten links. Validation: 10 assertions pass; user confirmed the compiled patch restores text in Mario Kart World. AI-assisted implementation and commit message using OpenAI Codex.
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/frontend/ampere/lower_to_maxwell.h3
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/video_core/ampere_returns.cpp51
3 files changed, 54 insertions, 1 deletions
diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h
index 0bed72eaec..031f7fac75 100644
--- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h
+++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h
@@ -92,7 +92,8 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) {
active_link = call_links[call];
}
}
- if (active_link && insn.Bits(16, 8) == *active_link)
+ // RET has no destination GPR; bits 16..23 are reserved, not a write to R0.
+ if (active_link && opcode != 0x950 && insn.Bits(16, 8) == *active_link)
return fail(index, "native callee overwrites link register");
}
// Scratch values and emulated uniform state occupy reserved high GPRs.
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 875c40604c..dd6f5d97b5 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -19,6 +19,7 @@ add_executable(tests
core/core_timing.cpp
core/internal_network/network.cpp
video_core/memory_tracker.cpp
+ video_core/ampere_returns.cpp
input_common/calibration_configuration_job.cpp
)
diff --git a/src/tests/video_core/ampere_returns.cpp b/src/tests/video_core/ampere_returns.cpp
new file mode 100644
index 0000000000..56b8b374da
--- /dev/null
+++ b/src/tests/video_core/ampere_returns.cpp
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <array>
+#include <catch2/catch_test_macros.hpp>
+
+#include "shader_recompiler/frontend/ampere/lower_to_maxwell.h"
+
+namespace {
+using Shader::Ampere::Instruction;
+using Shader::Ampere::LowerToMaxwell;
+
+TEST_CASE("Ampere returns do not write the link register", "[video_core][ampere]") {
+ for (const u32 link : {0U, 55U}) {
+ const std::array<Instruction, 4> code{{
+ {{0x00007802U | (link << 16), 0x20, 0x00000f00, 0}},
+ {{0x00007944, 0x10, 0x03c00000, 0}},
+ {{0x0000794d, 0, 0x03800000, 0}},
+ {{0x00007950U | (link << 24), 0xffffffc0, 0x03c3ffff, 0}},
+ }};
+ const auto lowered = LowerToMaxwell(code);
+ REQUIRE(static_cast<bool>(lowered));
+ REQUIRE(lowered.source_size == sizeof(code));
+ REQUIRE(lowered.instructions.back() == 0xe32000000007000fULL);
+ }
+}
+
+TEST_CASE("Ampere returns can read a copy of the R0 link", "[video_core][ampere]") {
+ const std::array<Instruction, 5> code{{
+ {{0x00007802, 0x20, 0x00000f00, 0}},
+ {{0x00007944, 0x10, 0x03c00000, 0}},
+ {{0x0000794d, 0, 0x03800000, 0}},
+ {{0x00017202, 0, 0x00000f00, 0}},
+ {{0x01007950, 0xffffffb0, 0x03c3ffff, 0}},
+ }};
+ REQUIRE(static_cast<bool>(LowerToMaxwell(code)));
+}
+
+TEST_CASE("Ampere callees still reject writes to the link", "[video_core][ampere]") {
+ const std::array<Instruction, 5> code{{
+ {{0x00007802, 0x20, 0x00000f00, 0}},
+ {{0x00007944, 0x10, 0x03c00000, 0}},
+ {{0x0000794d, 0, 0x03800000, 0}},
+ {{0x00007802, 0, 0x00000f00, 0}},
+ {{0x00007950, 0xffffffb0, 0x03c3ffff, 0}},
+ }};
+ const auto lowered = LowerToMaxwell(code);
+ REQUIRE(!static_cast<bool>(lowered));
+ REQUIRE(lowered.error == "native callee overwrites link register");
+ REQUIRE(lowered.error_offset == 0x30);
+}
+} // namespace