[source]

compiler/simplCore/SimplCore.hs

Note [Inline in InitialPhase]

[note link]

In GHC 8 and earlier we did not inline anything in the InitialPhase. But that is confusing for users because when they say INLINE they expect the function to inline right away.

So now we do inlining immediately, even in the InitialPhase, assuming that the Id’s Activation allows it.

This is a surprisingly big deal. Compiler performance improved a lot when I made this change:

perf/compiler/T5837.run            T5837 [stat too good] (normal)
perf/compiler/parsing001.run       parsing001 [stat too good] (normal)
perf/compiler/T12234.run           T12234 [stat too good] (optasm)
perf/compiler/T9020.run            T9020 [stat too good] (optasm)
perf/compiler/T3064.run            T3064 [stat too good] (normal)
perf/compiler/T9961.run            T9961 [stat too good] (normal)
perf/compiler/T13056.run           T13056 [stat too good] (optasm)
perf/compiler/T9872d.run           T9872d [stat too good] (normal)
perf/compiler/T783.run             T783 [stat too good] (normal)
perf/compiler/T12227.run           T12227 [stat too good] (normal)
perf/should_run/lazy-bs-alloc.run  lazy-bs-alloc [stat too good] (normal)
perf/compiler/T1969.run            T1969 [stat too good] (normal)
perf/compiler/T9872a.run           T9872a [stat too good] (normal)
perf/compiler/T9872c.run           T9872c [stat too good] (normal)
perf/compiler/T9872b.run           T9872b [stat too good] (normal)
perf/compiler/T9872d.run           T9872d [stat too good] (normal)

Note [RULEs enabled in SimplGently]

[note link]

RULES are enabled when doing “gentle” simplification. Two reasons:

  • We really want the class-op cancellation to happen:

    op (df d1 d2) –> $cop3 d1 d2

    because this breaks the mutual recursion between ‘op’ and ‘df’

  • I wanted the RULE

    lift String ===> …

    to work in Template Haskell when simplifying splices, so we get simpler code for literal strings

But watch out: list fusion can prevent floating. So use phase control to switch off those rules until after floating.

Note [Messing up the exported Id’s RULES]

[note link]

We must be careful about discarding (obviously) or even merging the RULES on the exported Id. The example that went bad on me at one stage was this one:

iterate :: (a -> a) -> a -> [a]
    [Exported]
iterate = iterateList
iterateFB c f x = x `c` iterateFB c f (f x)
iterateList f x =  x : iterateList f (f x)
    [Not exported]
{-# RULES
"iterate"   forall f x.     iterate f x = build (\c _n -> iterateFB c f x)
"iterateFB"                 iterateFB (:) = iterateList
 #-}

This got shorted out to:

iterateList :: (a -> a) -> a -> [a]
iterateList = iterate
iterateFB c f x = x `c` iterateFB c f (f x)
iterate f x =  x : iterate f (f x)
{-# RULES
"iterate"   forall f x.     iterate f x = build (\c _n -> iterateFB c f x)
"iterateFB"                 iterateFB (:) = iterate
 #-}
And now we get an infinite loop in the rule system
iterate f x -> build (cn -> iterateFB c f x)
-> iterateFB (:) f x -> iterate f x
Old “solution”:
use rule switching-off pragmas to get rid of iterateList in the first place

But in principle the user might want rules that only apply to the Id he says. And inline pragmas are similar

{-# NOINLINE f #-} f = local local = <stuff>

Then we do not want to get rid of the NOINLINE.

Hence hasShortableIdinfo.

Note [Rules and indirection-zapping]

[note link]

Problem: what if x_exported has a RULE that mentions something in …bindings…? Then the things mentioned can be out of scope! Solution

  1. Make sure that in this pass the usage-info from x_exported is
    available for …bindings…
  2. If there are any such RULES, rec-ify the entire top-level. It’ll get sorted out next time round

Other remarks

If more than one exported thing is equal to a local thing (i.e., the local thing really is shared), then we do one only: begin{verbatim}

x_local = …. x_exported1 = x_local x_exported2 = x_local
==>

x_exported1 = ….

x_exported2 = x_exported1

end{verbatim}

We rely on prior eta reduction to simplify things like begin{verbatim}

x_exported = /tyvars -> x_local tyvars
==>
x_exported = x_local

end{verbatim} Hence,there’s a possibility of leaving unchanged something like this: begin{verbatim}

x_local = …. x_exported1 = x_local Int

end{verbatim} By the time we’ve thrown away the types in STG land this could be eliminated. But I don’t think it’s very common and it’s dangerous to do this fiddling in STG land because we might elminate a binding that’s mentioned in the unfolding for something.

Note [Indirection zapping and ticks]

[note link]

Unfortunately this is another place where we need a special case for ticks. The following happens quite regularly:

x_local = <expression>
x_exported = tick<x> x_local

Which we want to become:

x_exported =  tick<x> <expression>

As it makes no sense to keep the tick and the expression on separate bindings. Note however that that this might increase the ticks scoping over the execution of x_local, so we can only do this for floatable ticks. More often than not, other references will be unfoldings of x_exported, and therefore carry the tick anyway.

Note [Transferring IdInfo]

[note link]

If we have
lcl_id = e; exp_id = lcl_id
and lcl_id has useful IdInfo, we don’t want to discard it by going
gbl_id = e; lcl_id = gbl_id

Instead, transfer IdInfo from lcl_id to exp_id, specifically * (Stable) unfolding * Strictness * Rules * Inline pragma

Overwriting, rather than merging, seems to work ok.

We also zap the InlinePragma on the lcl_id. It might originally have had a NOINLINE, which we have now transferred; and we really want the lcl_id to inline now that its RHS is trivial!