summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/GHC/CmmToAsm/X86/CodeGen.hs11
1 files changed, 10 insertions, 1 deletions
diff --git a/compiler/GHC/CmmToAsm/X86/CodeGen.hs b/compiler/GHC/CmmToAsm/X86/CodeGen.hs
index dccff1ef9d..52f2a52123 100644
--- a/compiler/GHC/CmmToAsm/X86/CodeGen.hs
+++ b/compiler/GHC/CmmToAsm/X86/CodeGen.hs
@@ -1003,7 +1003,16 @@ getRegister' _ is32Bit (CmmMachOp mop [x, y]) = -- dyadic MachOps
-> NatM Register
{- Case1: shift length as immediate -}
- shift_code width instr x (CmmLit lit) = do
+ shift_code width instr x (CmmLit lit)
+ -- Handle the case of a shift larger than the width of the shifted value.
+ -- This is necessary since x86 applies a mask of 0x1f to the shift
+ -- amount, meaning that, e.g., `shr 47, $eax` will actually shift by
+ -- `47 & 0x1f == 15`. See #20626.
+ | CmmInt n _ <- lit
+ , n >= fromIntegral (widthInBits width)
+ = getRegister $ CmmLit $ CmmInt 0 width
+
+ | otherwise = do
x_code <- getAnyReg x
let
format = intFormat width