dynarmic: Implement VectorMin/Max{S,U}64 emitters
Implements the missing A64 backend emitters for VectorMinS64, VectorMinU64, VectorMaxS64, and VectorMaxU64. These IR opcodes are generated by the optimizer but lack direct hardware instruction support for 64-bit elements in the base NEON set (e.g., UMIN.2D does not exist). They are implemented using a compare (CMGT/CMHI) followed by a bitwise select (BSL). This correctly selects between the two source registers, whereas using BIT would incorrectly zero out elements. Unit tests could not be added to a64.cpp because UMIN.2D is not a valid A64 instruction, causing the assembler (Oaknut) to reject it. The fix was verified by running Team Sonic Racing on macOS (Apple Silicon), which previously crashed on this synthetic opcode. Fixes crash in Team Sonic Racing.
This commit is contained in:
parent
75fda70db2
commit
fb9d1a9644
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -867,10 +867,10 @@ void EmitIR<IR::Opcode::VectorMaxS32>(oaknut::CodeGenerator& code, EmitContext&
|
|||
|
||||
template<>
|
||||
void EmitIR<IR::Opcode::VectorMaxS64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
UNREACHABLE();
|
||||
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
||||
code.CMGT(Qresult->D2(), Qa->D2(), Qb->D2());
|
||||
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
||||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
@ -890,10 +890,10 @@ void EmitIR<IR::Opcode::VectorMaxU32>(oaknut::CodeGenerator& code, EmitContext&
|
|||
|
||||
template<>
|
||||
void EmitIR<IR::Opcode::VectorMaxU64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
UNREACHABLE();
|
||||
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
||||
code.CMHI(Qresult->D2(), Qa->D2(), Qb->D2());
|
||||
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
||||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
@ -913,10 +913,10 @@ void EmitIR<IR::Opcode::VectorMinS32>(oaknut::CodeGenerator& code, EmitContext&
|
|||
|
||||
template<>
|
||||
void EmitIR<IR::Opcode::VectorMinS64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
UNREACHABLE();
|
||||
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
||||
code.CMGT(Qresult->D2(), Qb->D2(), Qa->D2());
|
||||
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
||||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
@ -936,10 +936,10 @@ void EmitIR<IR::Opcode::VectorMinU32>(oaknut::CodeGenerator& code, EmitContext&
|
|||
|
||||
template<>
|
||||
void EmitIR<IR::Opcode::VectorMinU64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
UNREACHABLE();
|
||||
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
||||
code.CMHI(Qresult->D2(), Qb->D2(), Qa->D2());
|
||||
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
||||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
|||
Loading…
Reference in New Issue