grin-compiler / grin

GRIN is a compiler back-end for lazy and strict functional languages with whole program optimization support.
https://grin-compiler.github.io/
1.03k stars 38 forks source link

Changing the order of `Transformations` in `defaultOptimizations` improves compilation #18

Closed LightAndLight closed 5 years ago

LightAndLight commented 5 years ago

defaultOptimizations looks like this:

defaultOptimizations :: [Transformation]
defaultOptimizations =
  [ ...
  , InlineEval
  , InlineApply
  , LateInlining
  ]

but if I make sure that InlineEval is run first:

defaultOptimizations :: [Transformation]
defaultOptimizations =
  [ InlineEval
  , ...
  , InlineApply
  , LateInlining
  ]

then my generated code improves. Urban's thesis says that inlining eval and apply are the first simplifications that need to be applied. Maybe this explains the behaviour?


Here is the relevant GRIN code:

eval p.0 =
  v.0 <- fetch p.0
  case v.0 of
    #default ->
      pure v.0
    (Fv1 a.0) ->
      res.0 <- v1 $ a.0
      update p.0 res.0
      pure res.0
    (Fv2 a.1) ->
      res.1 <- v2 $ a.1
      update p.0 res.1
      pure res.1

apply p.1 x.0 =
  case p.1 of
    (P1v1) ->
      v1 $ x.0
    (P1v2) ->
      v2 $ x.0

v1 v3 =
  v4 <- eval $ v3
  pure v4

v2 v5 =
  v6 <- eval $ v5
  pure v6

grinMain =
  v7 <- store (CInt 888)
  v8 <- store (Fv2 v7)
  v9 <- store (Fv1 v8)
  (CInt v10) <- eval $ v9
  v11 <- _prim_int_print $ v10
  pure v11

"Inline Eval Late":

eval.unboxed p.0 =
  v.0 <- fetch p.0
  v.1 <- pure v.0
  case v.1 of
    #default ->
      (CInt unboxed.CInt.0) <- pure v.1
      pure unboxed.CInt.0
    (Fv1 a.0) ->
      eval.unboxed $ a.0
    (Fv2 a.1) ->
      eval.unboxed $ a.1

grinMain =
  v.5 <- pure (CInt 888)
  v.2 <- pure v.5
  v7 <- store v.2
  v.6 <- pure (Fv2 v7)
  v.3 <- pure v.6
  v8 <- store v.3
  v.7 <- pure (Fv1 v8)
  v.4 <- pure v.7
  v9 <- store v.4
  unboxed.CInt.1 <- eval.unboxed $ v9
  _prim_int_print $ unboxed.CInt.1

"Eval inline early":

grinMain =
  a.1.0.58.0.arity.1.0 <- pure 888
  _prim_int_print $ a.1.0.58.0.arity.1.0
LightAndLight commented 5 years ago

Moving InlineEval and InlineApply to the top of the list would be a quick fix :)

csabahruska commented 5 years ago

It might help in some cases, but I think some more sophisticated method is needed to deal with mutual recursive functions. I've seen cases where some manual function cloning did help. It would worth to read the Secrets of the Glasgow Haskell Compiler inliner paper for some inspiration.

andorp commented 5 years ago

Changed in 4260c5ae565345dc1346bab16518d418e5a6baff