summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2021-11-06 12:55:36 -0400
committerBen Gamari <ben@smart-cactus.org>2022-03-02 09:00:44 -0500
commit7896cd36e4036648aa59c2b942eea4653466350b (patch)
tree554730789d1bf48fc7cb4fe7fe9e13936c869d9a
parente220ab5abfa3a1601d247a860d34820dfe68ce88 (diff)
downloadhaskell-7896cd36e4036648aa59c2b942eea4653466350b.tar.gz
nativeGen/x86: Don't encode large shift offsets
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. (cherry picked from commit 31370f1afe1e2f071b3569fb5ed4a115096127ca) (cherry picked from commit 1724ac37633b2796e2410296e8a34bc8e1fa4934)
-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 3596cb8baf..820938dd0e 100644
--- a/compiler/GHC/CmmToAsm/X86/CodeGen.hs
+++ b/compiler/GHC/CmmToAsm/X86/CodeGen.hs
@@ -1004,7 +1004,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