Constant folding optimises 1 into 3
A recent Hadrian issue [1] led me to finding a rather embarrassing bug:
-- This is just subtraction in disguise
minus :: Int -> Int -> Int
minus x y = (8 - y) - (8 - x)
{-# NOINLINE minus #-}
main :: IO ()
main = print (2 `minus` 1)
When compiled using ghc-8.6.0.20180810
without optimisation this prints 1
, as expected, but when compiled with -O
this prints 3
.
Here is the incorrect rewrite rule [2]:
(L y :-: v) :-: (L x :-: w) -> return $ mkL (y-x) `add` (w `add` v)
This should be changed to:
(L y :-: v) :-: (L x :-: w) -> return $ mkL (y-x) `add` (w `sub` v)
Happy to submit the fix, but I'm not yet fully convinced that there are no other lurking bugs. This whole constant folding business is very error-prone.
[1] https://github.com/snowleopard/hadrian/issues/641
[2] https://github.com/ghc/ghc/blob/master/compiler/prelude/PrelRules.hs#L1786