diff options
| -rw-r--r-- | src/shader_recompiler/frontend/ampere/lower_to_maxwell.h | 9 | ||||
| -rw-r--r-- | src/tests/video_core/ampere_returns.cpp | 27 |
2 files changed, 34 insertions, 2 deletions
diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h index 79f98017ae..489d003e60 100644 --- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h +++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h @@ -92,8 +92,13 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) { active_link = call_links[call]; } } - // 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) + // RET, BRA, NOP and ISETP/FSETP (predicate outputs) have no destination GPR; bits 16..23 + // are not a write to R0. IMAD.WIDE writes a register pair. + const bool no_destination = opcode == 0x950 || opcode == 0x947 || opcode == 0x918 || + (opcode & 0x1ff) == 0x00c || (opcode & 0x1ff) == 0x00b; + const bool pair = opcode == 0x225 || opcode == 0x625 || opcode == 0x825; + if (active_link && !no_destination && + (insn.Bits(16, 8) == *active_link || (pair && insn.Bits(16, 8) + 1 == *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/video_core/ampere_returns.cpp b/src/tests/video_core/ampere_returns.cpp index 56b8b374da..163758e07e 100644 --- a/src/tests/video_core/ampere_returns.cpp +++ b/src/tests/video_core/ampere_returns.cpp @@ -48,4 +48,31 @@ TEST_CASE("Ampere callees still reject writes to the link", "[video_core][ampere REQUIRE(lowered.error == "native callee overwrites link register"); REQUIRE(lowered.error_offset == 0x30); } + +TEST_CASE("Ampere callees can compare into predicates with an R0 link", "[video_core][ampere]") { + // ISETP's zero destination field is not a write to R0. + const std::array<Instruction, 5> code{{ + {{0x00007802, 0x20, 0x00000f00, 0}}, + {{0x00007944, 0x10, 0x03c00000, 0}}, + {{0x0000794d, 0, 0x03800000, 0}}, + {{0x0100720c, 0x00000002, 0x03f06070, 0}}, + {{0x00007950, 0xffffffb0, 0x03c3ffff, 0}}, + }}; + REQUIRE(static_cast<bool>(LowerToMaxwell(code))); +} + +TEST_CASE("Ampere callees reject a wide multiply over the link", "[video_core][ampere]") { + // IMAD.WIDE.U32 R54:R55 writes the R55 link. + const std::array<Instruction, 5> code{{ + {{0x00377802, 0x20, 0x00000f00, 0}}, + {{0x00007944, 0x10, 0x03c00000, 0}}, + {{0x0000794d, 0, 0x03800000, 0}}, + {{0x01367225, 0x00000002, 0x078e00ff, 0}}, + {{0x37007950, 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 |
