INLINABLE pragma affects optimization choices when function body is inlined
I am using GHC 9.4.2 on x86_64 Ubuntu.
The attached example demonstrates that adding INLINABLE
to a function can cause it to optimize worse than it would with no annotation at all. Interestingly, a full INLINE
pragma restores the original performance.
Looking at the generated core, it does appear that all three cases are being inlined, yet for some reason the INLINABLE
case doesn't optimize as well as the unannotated or INLINE
cases do (there appears to be an extra jump in the loop).
The example code can be found here inline-anomalies.tar.gz, and the performance difference can be observed by using cabal build
and time
on the resulting binary. I've inlined the code here for quick eyeballing (EDIT: compiling with -fdicts-strict
is necessary to reproduce):
Lib.hs
module Lib where
import Control.Monad.ST
import Data.Foldable
import qualified Data.Vector.Primitive.Mutable as MPR
-- {-# INLINABLE go #-}
go :: (MPR.Prim a , Integral a , Foldable f) => f a -> a
go xs = runST do
mv <- MPR.new 1
for_ xs \i -> do
MPR.unsafeRead mv 0 >>= \v -> MPR.unsafeWrite mv 0 (v + i)
MPR.unsafeRead mv 0
Main.hs
module Main where
import Lib
data MyList a = MyList [ a ] Int
deriving Functor
instance Foldable MyList where
{-# INLINE foldr #-}
foldr f z (MyList xs _) = foldr f z xs
{-# INLINE length #-}
length (MyList _ l) = l
main :: IO ()
main = print do
let c :: Int
c = 1000000000
go (MyList [ 1 .. c ] c)