diff options
| author | Sintendo <bram.speeckaert@gmail.com> | 2021-01-09 22:52:18 +0100 |
|---|---|---|
| committer | Sintendo <bram.speeckaert@gmail.com> | 2021-01-09 22:52:18 +0100 |
| commit | 305cd31bd9eaa05b4453160afcdfaeaa9618c699 (patch) | |
| tree | f27d010757c38d6908d6d904f501205d2afa0271 /Source/Core | |
| parent | 0776263c5e1f205f77c4836c1489c7200da34763 (diff) | |
Jit64: Fix FinalizeCarryOverflow XER[OV/SO]
FinalizeCarryOverflow didn't maintain XER[OV/SO] properly due to an
oversight. Here's the code it would generate:
0: 9c pushf
1: 80 65 3b fe and BYTE PTR [rbp+0x3b],0xfe
5: 71 04 jno b <jno>
7: c6 45 3b 03 mov BYTE PTR [rbp+0x3b],0x3
000000000000000b <jno>:
b: 9d popf
At first glance it seems reasonable. The host flags are carefully
preserved with PUSHF. The AND instruction clears XER[OV]. Next, an
conditional branch checks the host's overflow flag and, if needed, skips
over a MOV that sets XER[OV/SO]. Finally, host flags are restored with
POPF.
However, the AND instruction also clears the host's overflow flag. As a
result, the branch that follows it is always taken and the MOV is always
skipped. The end result is that XER[OV] is always cleared while XER[SO]
is left unchanged.
Putting POPF immediately after the AND would fix this, but we already
have GenerateOverflow doing it correctly (and without the PUSHF/POPF
shenanigans too). So let's just use that instead.
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 10 |
1 files changed, 1 insertions, 9 deletions
diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index bd4b20a2d3..8ec307889a 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -122,15 +122,7 @@ void Jit64::FinalizeCarryOverflow(bool oe, bool inv) { if (oe) { - // Make sure not to lose the carry flags (not a big deal, this path is rare). - PUSHF(); - // XER[OV] = 0 - AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); - FixupBranch jno = J_CC(CC_NO); - // XER[OV/SO] = 1 - MOV(8, PPCSTATE(xer_so_ov), Imm8(XER_SO_MASK | XER_OV_MASK)); - SetJumpTarget(jno); - POPF(); + GenerateOverflow(); } // Do carry FinalizeCarry(inv ? CC_NC : CC_C); |
