recursion-ninja pushed to branch wip/fix-25664 at Glasgow Haskell Compiler / GHC Commits: f68225ba by Recursion Ninja at 2025-10-09T13:28:07-04:00 Do not perform MUL/DIV/REM by "power of two" optimization if the value is outside the (signed) logical range of the Integer type's bit-width. Minimal test case added, using the reproducer provided by @clyring: https://gitlab.haskell.org/ghc/ghc/-/issues/25664#note_606177 - - - - - 4 changed files: - compiler/GHC/Cmm/Opt.hs - + testsuite/tests/cmm/opt/T25664.hs - + testsuite/tests/cmm/opt/T25664.stdout - testsuite/tests/cmm/opt/all.T Changes: ===================================== compiler/GHC/Cmm/Opt.hs ===================================== @@ -395,26 +395,39 @@ cmmMachOpFoldM platform mop [x, (CmmLit (CmmInt 1 rep))] one = CmmLit (CmmInt 1 (wordWidth platform)) -- Now look for multiplication/division by powers of 2 (integers). - -cmmMachOpFoldM platform mop [x, (CmmLit (CmmInt n _))] +-- +-- Naively this is as simple a matter as left/right bit shifts, +-- but the Cmm representation if integral values quickly complicated the matter. +-- +-- We must carefully narrow the value to be within the range of values for the +-- type's logical bit-width. However, Cmm only represents values as *signed* +-- integers internally yet the logical type may be unsigned. If we are dealing +-- with a negative integer type at width @_w@, the only negative number that +-- wraps around to be a positive power of 2 after calling narrowU is -2^(_w - 1) +-- which wraps round to 2^(_w - 1), and multiplying by -2^(_w - 1) is indeed +-- the same as a left shift by (w - 1), so this is OK. +-- +-- ToDo: See #25664 (comment 605821) describing a change to the Cmm literal representation. +-- When/If this is completed, this code must be refactored to account for the explicit width sizes. +cmmMachOpFoldM platform mop [x, (CmmLit (CmmInt n _w))] = case mop of MO_Mul rep - | Just p <- exactLog2 n -> + | Just p <- exactLog2 (narrowU rep n) -> Just $! (cmmMachOpFold platform (MO_Shl rep) [x, CmmLit (CmmInt p $ wordWidth platform)]) MO_U_Quot rep - | Just p <- exactLog2 n -> + | Just p <- exactLog2 (narrowU rep n) -> Just $! (cmmMachOpFold platform (MO_U_Shr rep) [x, CmmLit (CmmInt p $ wordWidth platform)]) MO_U_Rem rep - | Just _ <- exactLog2 n -> + | Just _ <- exactLog2 (narrowU rep n) -> Just $! (cmmMachOpFold platform (MO_And rep) [x, CmmLit (CmmInt (n - 1) rep)]) MO_S_Quot rep - | Just p <- exactLog2 n, + | Just p <- exactLog2 (narrowS rep n), CmmReg _ <- x -> -- We duplicate x in signedQuotRemHelper, hence require -- it is a reg. FIXME: remove this restriction. Just $! (cmmMachOpFold platform (MO_S_Shr rep) [signedQuotRemHelper rep p, CmmLit (CmmInt p $ wordWidth platform)]) MO_S_Rem rep - | Just p <- exactLog2 n, + | Just p <- exactLog2 (narrowS rep n), CmmReg _ <- x -> -- We duplicate x in signedQuotRemHelper, hence require -- it is a reg. FIXME: remove this restriction. -- We replace (x `rem` 2^p) by (x - (x `quot` 2^p) * 2^p). ===================================== testsuite/tests/cmm/opt/T25664.hs ===================================== @@ -0,0 +1,17 @@ +{-# OPTIONS_GHC -O -fno-full-laziness #-} +{-# LANGUAGE MagicHash #-} + +import GHC.Exts +import GHC.Int + +mb8 :: Int8 -> Int8 +{-# OPAQUE mb8 #-} +mb8 (I8# i) = I8# (i `quotInt8#` (noinline intToInt8# 128#)) + +mb16 :: Int16 -> Int16 +{-# OPAQUE mb16 #-} +mb16 (I16# i) = I16# (i `quotInt16#` (noinline intToInt16# 32768#)) + +main :: IO () +main = print (mb8 minBound) >> print (mb16 minBound) + ===================================== testsuite/tests/cmm/opt/T25664.stdout ===================================== @@ -0,0 +1,2 @@ +1 +1 ===================================== testsuite/tests/cmm/opt/all.T ===================================== @@ -12,3 +12,6 @@ test('T25771', [cmm_src, only_ways(['optasm']), grep_errmsg(r'(12\.345|0\.6640625)',[1]), ], compile, ['-ddump-cmm']) + +# Cmm should correctly account for word size when performing MUL/DIV/REM by a power of 2 optimization. +test('T25664', normal, compile_and_run, ['']) \ No newline at end of file View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/f68225bab863b67daddd7d0151e979fc... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/f68225bab863b67daddd7d0151e979fc... You're receiving this email because of your account on gitlab.haskell.org.