Inlining instance dictionary functions

Marcin 'Qrczak' Kowalczyk qrczak@knm.org.pl
30 Apr 2001 09:33:26 GMT


I checked what code is generated for operations in the
'StateT Int (Writer [Int])' monad which I used.

It's horrible: every '>>=' and 'tell' is extracted from Monad or
MonadWriter dictionaries built at runtime, even though they are used
on ground types. It's because dictionary functions for some instances,
e.g. 'instance Monad m => Monad (StateT s m)', are not inlined.

I added {-# INLINE instance #-} in various places in MonadState
etc. and it helped a lot: code generated for a sample usage was much
smaller (!).

Wouldn't it be reasonable to inline instance dictionary functions
by default? Classes are often used for parametrizing of small core
operations used everywhere, when it's important that they have a
chance of getting inlined. Today they often don't have the chance even
if they are small when there are many methods, because the instance
dictionary function is out of line.

I'm not sure that it's always ok, so I'm asking. Perhaps sometimes
it would lead to unacceptable code bloat, or it's not safe to mark
some of them inline? I see these choices:

1. mark them inline always, remove {-# INLINE instance #-} support,
2. mark them inline by default, add {-# NOINLINE instance #-} support,
3. increase inlining threshold for instance dictionary functions,
4. keep the status quo, add more {-# INLINE instance #-} to libraries.

I would do 1. if there are no objections. I'm currently compiling
ghc with this inining enabled unconditionally to see how it works
(typecheck/TcInstDcls.lhs).


BTW. 'WriterT [Int] (State Int)' happens to be better than 'StateT Int
(Writer [Int])' (with inlining instances) - the latter performs silly
[]++xs operations which are optimized away in the former case. I don't
know why there is the difference. These monads are not isomorphic
but from looking at the STG code it shouldn't be relevant. Anyway,
let's resolve the inlining issue before. A testcase is here:
    test :: WriterT [Int] (State Int) () -- or the other
    test = do
        x <- get
        tell [x]
        put (x+1)
        when (x < 1000) test


BTW/2. Sometimes ghc complains about the unavailability of
PrelGHC.(#,,,lots-of-commas,,,#), no matter how this inlining is
resolved, e.g.
    module Test where
    import SizedSeq
    test :: Sized [] a -> Sized [] a
    test s = append s s
compiled with -O -package data

-- 
 __("<  Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/
 \__/
  ^^                      SYGNATURA ZASTĘPCZA
QRCZAK