From d441ebe48914bf0f4f8a5c162cd5b25eafe0c247 Mon Sep 17 00:00:00 2001 From: Stefanos Kornilios Mitsis Poiitidis Date: Thu, 10 Sep 2020 03:56:00 +0300 Subject: [PATCH 1/4] SHLD/SHRD: Less broken flags, correct zero shifts --- .../Source/Interface/Core/OpcodeDispatcher.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 41e2f8520..583f0b168 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -1598,16 +1598,18 @@ void OpDispatchBuilder::SHLDOp(OpcodeArgs) { else Shift = _And(Shift, _Constant(0x1F)); - auto ShiftRight = _Sub(_Constant(Size), Shift); + auto ShiftRight = _Sub(_Constant(Size-1), Shift); OrderedNode *Res{}; auto Tmp1 = _Lshl(Dest, Shift); auto Tmp2 = _Lshr(Src, ShiftRight); + Tmp2 = _Lshr(Tmp2, _Constant(1)); + Res = _Or(Tmp1, Tmp2); StoreResult(GPRClass, Op, Res, -1); - GenerateFlags_ShiftLeft(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), _Bfe(Size, 0, Src)); + GenerateFlags_ShiftLeft(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), _Bfe(Size, 0, Shift)); } void OpDispatchBuilder::SHLDImmediateOp(OpcodeArgs) { @@ -1652,15 +1654,16 @@ void OpDispatchBuilder::SHRDOp(OpcodeArgs) { else Shift = _And(Shift, _Constant(0x1F)); - auto ShiftLeft = _Sub(_Constant(Size), Shift); + auto ShiftLeft = _Sub(_Constant(Size-1), Shift); OrderedNode *Res{}; auto Tmp1 = _Lshr(Dest, Shift); auto Tmp2 = _Lshl(Src, ShiftLeft); + Tmp2 = _Lshl(Tmp2, _Constant(1)); Res = _Or(Tmp1, Tmp2); StoreResult(GPRClass, Op, Res, -1); - GenerateFlags_ShiftRight(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), _Bfe(Size, 0, Src)); + GenerateFlags_ShiftRight(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), _Bfe(Size, 0, Shift)); } void OpDispatchBuilder::SHRDImmediateOp(OpcodeArgs) { From cadf53c9d9a2cfa49951b5e3327252b7d45cc7a3 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 14 Sep 2020 18:06:48 -0700 Subject: [PATCH 2/4] SHRD and SHLD unit tests for flag setting Tests all flags aside from PF --- unittests/ASM/TwoByte/0F_A5_2.asm | 22 ++++++ unittests/ASM/TwoByte/0F_A5_3.asm | 35 +++++++++ unittests/ASM/TwoByte/0F_A5_4.asm | 113 ++++++++++++++++++++++++++++++ unittests/ASM/TwoByte/0F_A5_5.asm | 29 ++++++++ unittests/ASM/TwoByte/0F_A5_6.asm | 29 ++++++++ unittests/ASM/TwoByte/0F_A5_7.asm | 29 ++++++++ unittests/ASM/TwoByte/0F_AD_2.asm | 22 ++++++ unittests/ASM/TwoByte/0F_AD_3.asm | 35 +++++++++ unittests/ASM/TwoByte/0F_AD_4.asm | 113 ++++++++++++++++++++++++++++++ unittests/ASM/TwoByte/0F_AD_5.asm | 29 ++++++++ unittests/ASM/TwoByte/0F_AD_6.asm | 29 ++++++++ unittests/ASM/TwoByte/0F_AD_7.asm | 30 ++++++++ 12 files changed, 515 insertions(+) create mode 100644 unittests/ASM/TwoByte/0F_A5_2.asm create mode 100644 unittests/ASM/TwoByte/0F_A5_3.asm create mode 100644 unittests/ASM/TwoByte/0F_A5_4.asm create mode 100644 unittests/ASM/TwoByte/0F_A5_5.asm create mode 100644 unittests/ASM/TwoByte/0F_A5_6.asm create mode 100644 unittests/ASM/TwoByte/0F_A5_7.asm create mode 100644 unittests/ASM/TwoByte/0F_AD_2.asm create mode 100644 unittests/ASM/TwoByte/0F_AD_3.asm create mode 100644 unittests/ASM/TwoByte/0F_AD_4.asm create mode 100644 unittests/ASM/TwoByte/0F_AD_5.asm create mode 100644 unittests/ASM/TwoByte/0F_AD_6.asm create mode 100644 unittests/ASM/TwoByte/0F_AD_7.asm diff --git a/unittests/ASM/TwoByte/0F_A5_2.asm b/unittests/ASM/TwoByte/0F_A5_2.asm new file mode 100644 index 000000000..4e5f6f1ef --- /dev/null +++ b/unittests/ASM/TwoByte/0F_A5_2.asm @@ -0,0 +1,22 @@ +%ifdef CONFIG +{ + "RegData": { + "R15": "0xFFFFFFFFFFFFFFFF", + "R14": "0x4141414141410000", + "R13": "0", + "R12": "0" + } +} +%endif + +mov cl, 0 +mov r15, -1 +mov r14, 0x4141414141410000 +mov r13, 0 +mov r12, 0 + +shld r14w, r15w, cl +shld r13d, r15d, cl +shld r12, r15, cl + +hlt diff --git a/unittests/ASM/TwoByte/0F_A5_3.asm b/unittests/ASM/TwoByte/0F_A5_3.asm new file mode 100644 index 000000000..b696bd608 --- /dev/null +++ b/unittests/ASM/TwoByte/0F_A5_3.asm @@ -0,0 +1,35 @@ +%ifdef CONFIG +{ + "RegData": { + "R15": "0xFFFFFFFFFFFFFFFF", + "R14": "0x4141414141410000", + "R13": "0", + "R12": "0", + "R11": "0" + } +} +%endif + +mov cl, 0 +mov r15, -1 +mov r14, 0x4141414141410000 +mov r13, 0 +mov r12, 0 +mov r11, 0 + +; Get the incoming flags +mov rax, 0 +lahf +mov r11, rax + +shld r14w, r15w, cl +shld r13d, r15d, cl +shld r12, r15, cl + +; Get the outgoing flags +; None should have changed +mov rax, 0 +lahf +xor r11, rax + +hlt diff --git a/unittests/ASM/TwoByte/0F_A5_4.asm b/unittests/ASM/TwoByte/0F_A5_4.asm new file mode 100644 index 000000000..9e832032b --- /dev/null +++ b/unittests/ASM/TwoByte/0F_A5_4.asm @@ -0,0 +1,113 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "1", + "RBX": "1", + "RDX": "1", + "RSI": "1", + "RBP": "1", + "RSP": "0", + "R8": "0", + "r9": "0" + } +} +%endif + +mov cl, 1 +mov r15, -1 +mov r14, 0xFFFFFFFFFFFF4000 +mov r13, 0xFFFFFFFF40000000 +mov r12, 0x4000000000000000 + +mov rax, 0 +mov rbx, 0 +mov rdx, 0 + +mov rsi, 0 +mov rdi, 0 +mov rbp, 0 + +mov rsp, 0 +mov r8, 0 +mov r9, 0 + +mov r11, 1 + +; Sign from 0->1 should set OF + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r14w, r15w, cl +cmovo rax, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r13d, r15d, cl +cmovo rbx, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r12, r15, cl +cmovo rdx, r11 + +; Sign from 1->0 should set OF +mov r15, -1 +mov r14, 0xFFFFFFFFFFFF8000 +mov r13, 0xFFFFFFFF80000000 +mov r12, 0x8000000000000000 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r14w, r15w, cl +cmovo rsi, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r13d, r15d, cl +cmovo rdi, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r12, r15, cl +cmovo rbp, r11 + +; Sign from 0->0 should NOT set OF +mov r15, -1 +mov r14, 0xFFFFFFFFFFFF0000 +mov r13, 0xFFFFFFFF00000000 +mov r12, 0x0000000000000000 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r14w, r15w, cl +cmovo rsp, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r13d, r15d, cl +cmovo r8, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shld r12, r15, cl +cmovo r9, r11 + +hlt diff --git a/unittests/ASM/TwoByte/0F_A5_5.asm b/unittests/ASM/TwoByte/0F_A5_5.asm new file mode 100644 index 000000000..97138920f --- /dev/null +++ b/unittests/ASM/TwoByte/0F_A5_5.asm @@ -0,0 +1,29 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "1", + "RBX": "1", + "RDX": "1" + } +} +%endif + +mov cl, 2 +mov r15, -1 +mov r14, 0x4141414141414000 +mov r13, 0xFFFFFFFF40000000 +mov r12, 0x4000000000000000 + +mov rax, 0 +mov rbx, 0 +mov rdx, 0 +mov rsi, 1 + +shld r14w, r15w, cl +cmovc rax, rsi +shld r13d, r15d, cl +cmovc rbx, rsi +shld r12, r15, cl +cmovc rdx, rsi + +hlt diff --git a/unittests/ASM/TwoByte/0F_A5_6.asm b/unittests/ASM/TwoByte/0F_A5_6.asm new file mode 100644 index 000000000..d9e58b9cc --- /dev/null +++ b/unittests/ASM/TwoByte/0F_A5_6.asm @@ -0,0 +1,29 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "1", + "RBX": "1", + "RDX": "1" + } +} +%endif + +mov cl, 2 +mov r15, 0 +mov r14, 0x4141414141414000 +mov r13, 0xFFFFFFFF40000000 +mov r12, 0x4000000000000000 + +mov rax, 0 +mov rbx, 0 +mov rdx, 0 +mov rsi, 1 + +shld r14w, r15w, cl +cmovz rax, rsi +shld r13d, r15d, cl +cmovz rbx, rsi +shld r12, r15, cl +cmovz rdx, rsi + +hlt diff --git a/unittests/ASM/TwoByte/0F_A5_7.asm b/unittests/ASM/TwoByte/0F_A5_7.asm new file mode 100644 index 000000000..fa358078e --- /dev/null +++ b/unittests/ASM/TwoByte/0F_A5_7.asm @@ -0,0 +1,29 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "1", + "RBX": "1", + "RDX": "1" + } +} +%endif + +mov cl, 2 +mov r15, 0 +mov r14, 0x4141414141412000 +mov r13, 0xFFFFFFFF20000000 +mov r12, 0x2000000000000000 + +mov rax, 0 +mov rbx, 0 +mov rdx, 0 +mov rsi, 1 + +shld r14w, r15w, cl +cmovs rax, rsi +shld r13d, r15d, cl +cmovs rbx, rsi +shld r12, r15, cl +cmovs rdx, rsi + +hlt diff --git a/unittests/ASM/TwoByte/0F_AD_2.asm b/unittests/ASM/TwoByte/0F_AD_2.asm new file mode 100644 index 000000000..223ac68c9 --- /dev/null +++ b/unittests/ASM/TwoByte/0F_AD_2.asm @@ -0,0 +1,22 @@ +%ifdef CONFIG +{ + "RegData": { + "R15": "0xFFFFFFFFFFFFFFFF", + "R14": "0x4141414141410000", + "R13": "0", + "R12": "0" + } +} +%endif + +mov cl, 0 +mov r15, -1 +mov r14, 0x4141414141410000 +mov r13, 0 +mov r12, 0 + +shrd r14w, r15w, cl +shrd r13d, r15d, cl +shrd r12, r15, cl + +hlt diff --git a/unittests/ASM/TwoByte/0F_AD_3.asm b/unittests/ASM/TwoByte/0F_AD_3.asm new file mode 100644 index 000000000..fec536c1a --- /dev/null +++ b/unittests/ASM/TwoByte/0F_AD_3.asm @@ -0,0 +1,35 @@ +%ifdef CONFIG +{ + "RegData": { + "R15": "0xFFFFFFFFFFFFFFFF", + "R14": "0x4141414141410000", + "R13": "0", + "R12": "0", + "R11": "0" + } +} +%endif + +mov cl, 0 +mov r15, -1 +mov r14, 0x4141414141410000 +mov r13, 0 +mov r12, 0 +mov r11, 0 + +; Get the incoming flags +mov rax, 0 +lahf +mov r11, rax + +shrd r14w, r15w, cl +shrd r13d, r15d, cl +shrd r12, r15, cl + +; Get the outgoing flags +; None should have changed +mov rax, 0 +lahf +xor r11, rax + +hlt diff --git a/unittests/ASM/TwoByte/0F_AD_4.asm b/unittests/ASM/TwoByte/0F_AD_4.asm new file mode 100644 index 000000000..8e28f289c --- /dev/null +++ b/unittests/ASM/TwoByte/0F_AD_4.asm @@ -0,0 +1,113 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "1", + "RBX": "1", + "RDX": "1", + "RSI": "1", + "RBP": "1", + "RSP": "0", + "R8": "0", + "r9": "0" + } +} +%endif + +mov cl, 1 +mov r15, -1 +mov r14, 0xFFFFFFFFFFFF0000 +mov r13, 0xFFFFFFFF00000000 +mov r12, 0 + +mov rax, 0 +mov rbx, 0 +mov rdx, 0 + +mov rsi, 0 +mov rdi, 0 +mov rbp, 0 + +mov rsp, 0 +mov r8, 0 +mov r9, 0 + +mov r11, 1 + +; Sign from 0->1 should set OF + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r14w, r15w, cl +cmovo rax, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r13d, r15d, cl +cmovo rbx, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r12, r15, cl +cmovo rdx, r11 + +; Sign from 1->0 should set OF +mov r15, -1 +mov r14, 0xFFFFFFFFFFFF8000 +mov r13, 0xFFFFFFFF80000000 +mov r12, 0x8000000000000000 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r14w, r15w, cl +cmovo rsi, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r13d, r15d, cl +cmovo rdi, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r12, r15, cl +cmovo rbp, r11 + +; Sign from 0->0 should NOT set OF +mov r15, 0xFFFFFFFFFFFFFFFE +mov r14, 0xFFFFFFFFFFFF0000 +mov r13, 0xFFFFFFFF00000000 +mov r12, 0x0000000000000000 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r14w, r15w, cl +cmovo rsp, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r13d, r15d, cl +cmovo r8, r11 + +; Let's clear OF really quick +mov rax, 0 +ror rax, 1 + +shrd r12, r15, cl +cmovo r9, r11 + +hlt diff --git a/unittests/ASM/TwoByte/0F_AD_5.asm b/unittests/ASM/TwoByte/0F_AD_5.asm new file mode 100644 index 000000000..75eb73af6 --- /dev/null +++ b/unittests/ASM/TwoByte/0F_AD_5.asm @@ -0,0 +1,29 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "1", + "RBX": "1", + "RDX": "1" + } +} +%endif + +mov cl, 2 +mov r15, -1 +mov r14, 0x4141414141410002 +mov r13, 0xFFFFFFFF00000002 +mov r12, 0x0000000000000002 + +mov rax, 0 +mov rbx, 0 +mov rdx, 0 +mov rsi, 1 + +shrd r14w, r15w, cl +cmovc rax, rsi +shrd r13d, r15d, cl +cmovc rbx, rsi +shrd r12, r15, cl +cmovc rdx, rsi + +hlt diff --git a/unittests/ASM/TwoByte/0F_AD_6.asm b/unittests/ASM/TwoByte/0F_AD_6.asm new file mode 100644 index 000000000..84699c14e --- /dev/null +++ b/unittests/ASM/TwoByte/0F_AD_6.asm @@ -0,0 +1,29 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "1", + "RBX": "1", + "RDX": "1" + } +} +%endif + +mov cl, 2 +mov r15, 0 +mov r14, 0x4141414141410002 +mov r13, 0xFFFFFFFF00000002 +mov r12, 0x0000000000000002 + +mov rax, 0 +mov rbx, 0 +mov rdx, 0 +mov rsi, 1 + +shrd r14w, r15w, cl +cmovz rax, rsi +shrd r13d, r15d, cl +cmovz rbx, rsi +shrd r12, r15, cl +cmovz rdx, rsi + +hlt diff --git a/unittests/ASM/TwoByte/0F_AD_7.asm b/unittests/ASM/TwoByte/0F_AD_7.asm new file mode 100644 index 000000000..1d0a7db60 --- /dev/null +++ b/unittests/ASM/TwoByte/0F_AD_7.asm @@ -0,0 +1,30 @@ + +%ifdef CONFIG +{ + "RegData": { + "RAX": "1", + "RBX": "1", + "RDX": "1" + } +} +%endif + +mov cl, 2 +mov r15, 0xFFFFFFFFFFFFFFF2 +mov r14, 0x4141414141410000 +mov r13, 0xFFFFFFFF00000000 +mov r12, 0x0000000000000000 + +mov rax, 0 +mov rbx, 0 +mov rdx, 0 +mov rsi, 1 + +shrd r14w, r15w, cl +cmovs rax, rsi +shrd r13d, r15d, cl +cmovs rbx, rsi +shrd r12, r15, cl +cmovs rdx, rsi + +hlt From ef111eb287bcbb0e8e9489826e13f2858e181299 Mon Sep 17 00:00:00 2001 From: Stefanos Kornilios Mitsis Poiitidis Date: Wed, 16 Sep 2020 22:21:41 +0300 Subject: [PATCH 3/4] unittests: Fix SH*D tests --- unittests/ASM/TwoByte/0F_A5_4.asm | 6 +++--- unittests/ASM/TwoByte/0F_AD_4.asm | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/unittests/ASM/TwoByte/0F_A5_4.asm b/unittests/ASM/TwoByte/0F_A5_4.asm index 9e832032b..3da70fa7c 100644 --- a/unittests/ASM/TwoByte/0F_A5_4.asm +++ b/unittests/ASM/TwoByte/0F_A5_4.asm @@ -1,7 +1,7 @@ %ifdef CONFIG { "RegData": { - "RAX": "1", + "r10": "1", "RBX": "1", "RDX": "1", "RSI": "1", @@ -19,7 +19,7 @@ mov r14, 0xFFFFFFFFFFFF4000 mov r13, 0xFFFFFFFF40000000 mov r12, 0x4000000000000000 -mov rax, 0 +mov r10, 0 mov rbx, 0 mov rdx, 0 @@ -40,7 +40,7 @@ mov rax, 0 ror rax, 1 shld r14w, r15w, cl -cmovo rax, r11 +cmovo r10, r11 ; Let's clear OF really quick mov rax, 0 diff --git a/unittests/ASM/TwoByte/0F_AD_4.asm b/unittests/ASM/TwoByte/0F_AD_4.asm index 8e28f289c..2aa4d1e9e 100644 --- a/unittests/ASM/TwoByte/0F_AD_4.asm +++ b/unittests/ASM/TwoByte/0F_AD_4.asm @@ -1,7 +1,7 @@ %ifdef CONFIG { "RegData": { - "RAX": "1", + "r10": "1", "RBX": "1", "RDX": "1", "RSI": "1", @@ -19,7 +19,7 @@ mov r14, 0xFFFFFFFFFFFF0000 mov r13, 0xFFFFFFFF00000000 mov r12, 0 -mov rax, 0 +mov r10, 0 mov rbx, 0 mov rdx, 0 @@ -40,7 +40,7 @@ mov rax, 0 ror rax, 1 shrd r14w, r15w, cl -cmovo rax, r11 +cmovo r10, r11 ; Let's clear OF really quick mov rax, 0 @@ -57,7 +57,7 @@ shrd r12, r15, cl cmovo rdx, r11 ; Sign from 1->0 should set OF -mov r15, -1 +mov r15, 0 mov r14, 0xFFFFFFFFFFFF8000 mov r13, 0xFFFFFFFF80000000 mov r12, 0x8000000000000000 From 79fa103a04604f9c3880d7d47dbc531ae52627a0 Mon Sep 17 00:00:00 2001 From: Stefanos Kornilios Mitsis Poiitidis Date: Wed, 16 Sep 2020 22:23:53 +0300 Subject: [PATCH 4/4] SH*D: Fix shifts by zero, OF calculation --- .../Interface/Core/OpcodeDispatcher.cpp | 92 ++++++++++++------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 583f0b168..9ac8cfd0a 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -1598,18 +1598,31 @@ void OpDispatchBuilder::SHLDOp(OpcodeArgs) { else Shift = _And(Shift, _Constant(0x1F)); - auto ShiftRight = _Sub(_Constant(Size-1), Shift); + auto CondJump = _CondJump(Shift); + + // Do nothing if shift count is zero + auto JumpTarget = CreateNewCodeBlock(); + SetTrueJumpTarget(CondJump, JumpTarget); + SetCurrentCodeBlock(JumpTarget); + + + auto ShiftRight = _Sub(_Constant(Size), Shift); OrderedNode *Res{}; auto Tmp1 = _Lshl(Dest, Shift); auto Tmp2 = _Lshr(Src, ShiftRight); - Tmp2 = _Lshr(Tmp2, _Constant(1)); Res = _Or(Tmp1, Tmp2); StoreResult(GPRClass, Op, Res, -1); GenerateFlags_ShiftLeft(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), _Bfe(Size, 0, Shift)); + + auto Jump = _Jump(); + auto NextJumpTarget = CreateNewCodeBlock(); + SetJumpTarget(Jump, NextJumpTarget); + SetFalseJumpTarget(CondJump, NextJumpTarget); + SetCurrentCodeBlock(NextJumpTarget); } void OpDispatchBuilder::SHLDImmediateOp(OpcodeArgs) { @@ -1627,17 +1640,19 @@ void OpDispatchBuilder::SHLDImmediateOp(OpcodeArgs) { else Shift &= 0x1F; - OrderedNode *ShiftLeft = _Constant(Shift); - auto ShiftRight = _Constant(Size - Shift); + if (Shift != 0) { + OrderedNode *ShiftLeft = _Constant(Shift); + auto ShiftRight = _Constant(Size - Shift); - OrderedNode *Res{}; - auto Tmp1 = _Lshl(Dest, ShiftLeft); - auto Tmp2 = _Lshr(Src, ShiftRight); - Res = _Or(Tmp1, Tmp2); + OrderedNode *Res{}; + auto Tmp1 = _Lshl(Dest, ShiftLeft); + auto Tmp2 = _Lshr(Src, ShiftRight); + Res = _Or(Tmp1, Tmp2); - StoreResult(GPRClass, Op, Res, -1); + StoreResult(GPRClass, Op, Res, -1); - GenerateFlags_ShiftLeftImmediate(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), Shift); + GenerateFlags_ShiftLeftImmediate(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), Shift); + } } void OpDispatchBuilder::SHRDOp(OpcodeArgs) { @@ -1654,16 +1669,29 @@ void OpDispatchBuilder::SHRDOp(OpcodeArgs) { else Shift = _And(Shift, _Constant(0x1F)); - auto ShiftLeft = _Sub(_Constant(Size-1), Shift); + + auto CondJump = _CondJump(Shift); + + // Do nothing if shift count is zero + auto JumpTarget = CreateNewCodeBlock(); + SetTrueJumpTarget(CondJump, JumpTarget); + SetCurrentCodeBlock(JumpTarget); + + auto ShiftLeft = _Sub(_Constant(Size), Shift); OrderedNode *Res{}; auto Tmp1 = _Lshr(Dest, Shift); auto Tmp2 = _Lshl(Src, ShiftLeft); - Tmp2 = _Lshl(Tmp2, _Constant(1)); Res = _Or(Tmp1, Tmp2); StoreResult(GPRClass, Op, Res, -1); GenerateFlags_ShiftRight(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), _Bfe(Size, 0, Shift)); + + auto Jump = _Jump(); + auto NextJumpTarget = CreateNewCodeBlock(); + SetJumpTarget(Jump, NextJumpTarget); + SetFalseJumpTarget(CondJump, NextJumpTarget); + SetCurrentCodeBlock(NextJumpTarget); } void OpDispatchBuilder::SHRDImmediateOp(OpcodeArgs) { @@ -1681,17 +1709,19 @@ void OpDispatchBuilder::SHRDImmediateOp(OpcodeArgs) { else Shift = Op->Src[1].TypeLiteral.Literal & 0x1F; - OrderedNode *ShiftRight = _Constant(Shift); - auto ShiftLeft = _Constant(Size - Shift); + if (Shift != 0) { + OrderedNode *ShiftRight = _Constant(Shift); + auto ShiftLeft = _Constant(Size - Shift); - OrderedNode *Res{}; - auto Tmp1 = _Lshr(Dest, ShiftRight); - auto Tmp2 = _Lshl(Src, ShiftLeft); - Res = _Or(Tmp1, Tmp2); + OrderedNode *Res{}; + auto Tmp1 = _Lshr(Dest, ShiftRight); + auto Tmp2 = _Lshl(Src, ShiftLeft); + Res = _Or(Tmp1, Tmp2); - StoreResult(GPRClass, Op, Res, -1); + StoreResult(GPRClass, Op, Res, -1); - GenerateFlags_ShiftRightImmediate(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), Shift); + GenerateFlags_ShiftRightImmediate(Op, _Bfe(Size, 0, Res), _Bfe(Size, 0, Dest), Shift); + } } template @@ -4511,16 +4541,14 @@ void OpDispatchBuilder::GenerateFlags_ShiftLeft(FEXCore::X86Tables::DecodedOp Op // SF { - auto SignBitConst = _Constant(GetSrcSize(Op) * 8 - 1); + SetRFLAG(_Bfe(1, GetSrcSize(Op) * 8 - 1, Res)); + } - auto LshrOp = _Lshr(Res, SignBitConst); - SetRFLAG(LshrOp); - - // OF + // OF + { // In the case of left shift. OF is only set from the result of XOR // When Shift > 1 then OF is undefined - auto SourceBit = _Bfe(1, GetSrcSize(Op) * 8 - 1, Src1); - SetRFLAG(_Xor(SourceBit, LshrOp)); + SetRFLAG(_Bfe(1, GetSrcSize(Op) * 8 - 1, _Xor(Src1, Res))); } auto Jump = _Jump(); @@ -4571,17 +4599,15 @@ void OpDispatchBuilder::GenerateFlags_ShiftRight(FEXCore::X86Tables::DecodedOp O // SF { - auto SignBitConst = _Constant(GetSrcSize(Op) * 8 - 1); - - auto LshrOp = _Lshr(Res, SignBitConst); - SetRFLAG(LshrOp); + SetRFLAG(_Bfe(1, GetSrcSize(Op) * 8 - 1, Res)); } // OF { // Only defined when Shift is 1 else undefined - // Is set to the MSB of the original value - SetRFLAG(_Bfe(1, GetSrcSize(Op) * 8 - 1, Src1)); + // OF flag is set if a sign change occurred + + SetRFLAG(_Bfe(1, GetSrcSize(Op) * 8 - 1, _Xor(Src1, Res))); } auto Jump = _Jump();