diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index a040f2d52..2e07e7805 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -2224,9 +2224,10 @@ void OpDispatchBuilder::RCRSmallerOp(OpcodeArgs) { Tmp = _Bfi(OpSize::i64Bit, 17, 34, Tmp, Tmp); } - // Entire bitfield has been setup - // Just extract the 8 or 16bits we need - Ref Res = _Lshr(OpSize::i32Bit, Tmp, Src); + // Entire bitfield has been setup. Just extract the 8 or 16bits we need. + // 64-bit shift used because we want to rotate in our cascaded upper bits + // rather than zeroes. + Ref Res = _Lshr(OpSize::i64Bit, Tmp, Src); StoreResult(GPRClass, Op, Res, -1); diff --git a/unittests/ASM/FEX_bugs/LargeRotatesForSmallSizes.asm b/unittests/ASM/FEX_bugs/LargeRotatesForSmallSizes.asm new file mode 100644 index 000000000..14d28d028 --- /dev/null +++ b/unittests/ASM/FEX_bugs/LargeRotatesForSmallSizes.asm @@ -0,0 +1,115 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4142434445464748", + "RBX": "0x4142434445464748", + "RCX": "0x4142434445464748", + "RDX": "0x4142434445464748", + "RSI": "0x4142434445464714", + "RDI": "0x414243444546478a", + "RBP": "0x4142434445464704", + "RSP": "0x414243444546478a", + "R8": "0x4142434445461d22", + "R9": "0x41424344454651d2", + "R10": "0x4142434445461d20", + "R11": "0x41424344454651d2", + "R12": "0x4142434445463a45", + "R13": "0x41424344454608e9", + "R14": "0x4142434445463a41", + "R15": "0x41424344454608e9" + } +} +%endif + +; FEX-Emu had a bug where 8-bit and 16-bit rotates with carry generated incorrect results when the rotate amount was larger than the data size. +; This is well defined in x86 semantics. + +mov cl, 0x9 +stc +jmp .test +.test: +; 8-bit: Test 1-bit past data size, plus carry +rcr byte [rel .data + (0 * 8)], cl +rcl byte [rel .data + (1 * 8)], cl + +mov cl, 0x9 +clc +jmp .test2 +.test2: +; 8-bit: Test 1-bit past data size, no carry +rcr byte [rel .data + (2 * 8)], cl +rcl byte [rel .data + (3 * 8)], cl + +mov cl, 0x1f +stc +jmp .test3 +.test3: +; 8-bit: Test maximum 32-bit rotate, plus carry +rcr byte [rel .data + (4 * 8)], cl +rcl byte [rel .data + (5 * 8)], cl + +mov cl, 0x1f +clc +jmp .test4 +.test4: +; 8-bit: Test maximum 32-bit rotate, plus carry +rcr byte [rel .data + (6 * 8)], cl +rcl byte [rel .data + (7 * 8)], cl + +mov cl, 0xF +stc +jmp .test5 +.test5: +; 16-bit: Test 1-bit past data size, plus carry +rcr word [rel .data + (8 * 8)], cl +rcl word [rel .data + (9 * 8)], cl + +mov cl, 0xF +clc +jmp .test6 +.test6: +; 16-bit: Test 1-bit past data size, no carry +rcr word [rel .data + (10 * 8)], cl +rcl word [rel .data + (11 * 8)], cl + +mov cl, 0x1f +stc +jmp .test7 +.test7: +; 16-bit: Test maximum 32-bit rotate, plus carry +rcr word [rel .data + (12 * 8)], cl +rcl word [rel .data + (13 * 8)], cl + +mov cl, 0x1f +clc +jmp .test8 +.test8: +; 16-bit: Test maximum 32-bit rotate, plus carry +rcr word [rel .data + (14 * 8)], cl +rcl word [rel .data + (15 * 8)], cl + +jmp .end +.end: + +; Load all the results in order +mov rax, [rel .data + (0 * 8)] +mov rbx, [rel .data + (1 * 8)] +mov rcx, [rel .data + (2 * 8)] +mov rdx, [rel .data + (3 * 8)] +mov rsi, [rel .data + (4 * 8)] +mov rdi, [rel .data + (5 * 8)] +mov rbp, [rel .data + (6 * 8)] +mov rsp, [rel .data + (7 * 8)] +mov r8, [rel .data + (8 * 8)] +mov r9, [rel .data + (9 * 8)] +mov r10, [rel .data + (10 * 8)] +mov r11, [rel .data + (11 * 8)] +mov r12, [rel .data + (12 * 8)] +mov r13, [rel .data + (13 * 8)] +mov r14, [rel .data + (14 * 8)] +mov r15, [rel .data + (15 * 8)] + +hlt + +.data: +times 16 dq 0x4142434445464748 diff --git a/unittests/InstructionCountCI/FlagM/PrimaryGroup.json b/unittests/InstructionCountCI/FlagM/PrimaryGroup.json index fda6ba24f..637baee98 100644 --- a/unittests/InstructionCountCI/FlagM/PrimaryGroup.json +++ b/unittests/InstructionCountCI/FlagM/PrimaryGroup.json @@ -947,7 +947,7 @@ "bfi x21, x21, #9, #9", "bfi x21, x21, #18, #18", "bfi x21, x21, #36, #9", - "lsr w20, w21, #2", + "lsr x20, x21, #2", "bfxil x4, x20, #0, #8", "rmif x21, #0, #nzCv" ] @@ -1089,7 +1089,7 @@ "bfi x21, x20, #16, #1", "bfi x21, x21, #17, #17", "bfi x21, x21, #34, #17", - "lsr w20, w21, #2", + "lsr x20, x21, #2", "bfxil x4, x20, #0, #16", "rmif x21, #0, #nzCv" ] @@ -1613,7 +1613,7 @@ "bfi x21, x21, #9, #9", "bfi x21, x21, #18, #18", "bfi x21, x21, #36, #9", - "lsr w20, w21, w5", + "lsr x20, x21, x5", "bfxil x4, x20, #0, #8", "sub w22, w5, #0x1 (1)", "lsr w21, w21, w22", @@ -1840,7 +1840,7 @@ "bfi x21, x20, #16, #1", "bfi x21, x21, #17, #17", "bfi x21, x21, #34, #17", - "lsr w20, w21, w5", + "lsr x20, x21, x5", "bfxil x4, x20, #0, #16", "sub w22, w5, #0x1 (1)", "lsr w21, w21, w22", diff --git a/unittests/InstructionCountCI/PrimaryGroup.json b/unittests/InstructionCountCI/PrimaryGroup.json index 069e585b8..c35c36402 100644 --- a/unittests/InstructionCountCI/PrimaryGroup.json +++ b/unittests/InstructionCountCI/PrimaryGroup.json @@ -1043,7 +1043,7 @@ "bfi x21, x21, #9, #9", "bfi x21, x21, #18, #18", "bfi x21, x21, #36, #9", - "lsr w20, w21, #2", + "lsr x20, x21, #2", "bfxil x4, x20, #0, #8", "ubfx x20, x21, #1, #1", "mrs x21, nzcv", @@ -1222,7 +1222,7 @@ "bfi x21, x20, #16, #1", "bfi x21, x21, #17, #17", "bfi x21, x21, #34, #17", - "lsr w20, w21, #2", + "lsr x20, x21, #2", "bfxil x4, x20, #0, #16", "ubfx x20, x21, #1, #1", "mrs x21, nzcv", @@ -1900,7 +1900,7 @@ "bfi x21, x21, #9, #9", "bfi x21, x21, #18, #18", "bfi x21, x21, #36, #9", - "lsr w20, w21, w5", + "lsr x20, x21, x5", "bfxil x4, x20, #0, #8", "sub w22, w5, #0x1 (1)", "lsr w21, w21, w22", @@ -2175,7 +2175,7 @@ "bfi x21, x20, #16, #1", "bfi x21, x21, #17, #17", "bfi x21, x21, #34, #17", - "lsr w20, w21, w5", + "lsr x20, x21, x5", "bfxil x4, x20, #0, #16", "sub w22, w5, #0x1 (1)", "lsr w21, w21, w22",