Skip to content

Optimization problem with zip and iterate

Summary

When compiling under -O2, the pipeline head . map snd . zip [1] . iterate id $ x is optimized to head . iterate id $ x instead of x.

Steps to reproduce

{-# LANGUAGE BangPatterns #-}

test ::  Int -> Int
{-# NOINLINE test #-}
test !x = head . map snd . zip [1] . iterate id $ x

test2 ::  Int -> Int
{-# NOINLINE test2 #-}
test2 !x = head . iterate id $ x

main = do putStrLn . show $ test 3 + test2 2

Compiling the above code with ghc -O2 -ddump-simpl optimize_test.hs > optimize_test.core results in

-- RHS size: {terms: 8, types: 12, coercions: 0, joins: 0/0}
Main.$wtest [InlPrag=NOINLINE] :: GHC.Prim.Int# -> Int
[GblId, Arity=1, Caf=NoCafRefs, Str=<L,U>, Unf=OtherCon []]
Main.$wtest
  = \ (ww_s1H7 :: GHC.Prim.Int#) ->
      case GHC.List.$witerate @ Int (id @ Int) (GHC.Types.I# ww_s1H7) of
      { (# ww2_aOT, ww3_aOU #) ->
      ww2_aOT
      }

-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
Main.$wtest2 [InlPrag=NOINLINE] :: GHC.Prim.Int# -> GHC.Prim.Int#
[GblId, Arity=1, Caf=NoCafRefs, Str=<S,1*U>, Unf=OtherCon []]
Main.$wtest2 = \ (ww_s1Hd :: GHC.Prim.Int#) -> ww_s1Hd

Expected behavior

In test, I would expect GHC to first eliminate map snd . zip [1], and then eliminate iterate. GHC can obviously do this as shown in test2. I suspect some rewrite ordering issue or some problem with boxed/unboxed integers.

Environment

  • GHC version used:
ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.10.1
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information