Note [Which transformations are innocuous]
At one point (Jun 18) I wondered if some transformations (ticks)
might be "innocuous", in the sense that they do not unlock a later
transformation that does not occur in the same pass. If so, we could
refrain from bumping the overall tick-count for such innocuous
transformations, and perhaps terminate the simplifier one pass
earlier.
But alas I found that virtually nothing was innocuous! This Note
just records what I learned, in case anyone wants to try again.
These transformations are not innocuous:
*** NB: I think these ones could be made innocuous
EtaExpansion
LetFloatFromLet
LetFloatFromLet
x = K (let z = e2 in Just z)
prepareRhs transforms to
x2 = let z=e2 in Just z
x = K xs
And now more let-floating can happen in the
next pass, on x2
PreInlineUnconditionally
Example in spectral/cichelli/Auxil
hinsert = ...let lo = e in
let j = ...lo... in
case x of
False -> ()
True -> case lo of I# lo' ->
...j...
When we PreInlineUnconditionally j, lo's occ-info changes to once,
so it can be PreInlineUnconditionally in the next pass, and a
cascade of further things can happen.
PostInlineUnconditionally
let x = e in
let y = ...x.. in
case .. of { A -> ...x...y...
B -> ...x...y... }
Current postinlineUnconditinaly will inline y, and then x; sigh.
But PostInlineUnconditionally might also unlock subsequent
transformations for the same reason as PreInlineUnconditionally,
so it's probably not innocuous anyway.
One annoying variant is this. CaseMerge introduces auxiliary bindings
let b = b' in ...
This takes another full run of the simplifier to elimiante. But if
the PostInlineUnconditionally, replacing b with b', is the only thing
that happens in a Simplifier run, that probably really is innocuous.
Perhaps an opportunity here.
KnownBranch, BetaReduction:
May drop chunks of code, and thereby enable PreInlineUnconditionally
for some let-binding which now occurs once
EtaExpansion:
Example in imaginary/digits-of-e1
fail = \void. e where e :: IO ()
> etaExpandRhs
fail = \void. (\s. (e |> g) s) |> sym g where g :: IO () ~ S -> (S,())
> Next iteration of simplify
fail1 = \void. \s. (e |> g) s
fail = fail1 |> Void# -> sym g
And now inline 'fail'
CaseMerge:
case x of y {
DEFAULT -> case y of z { pi -> ei }
alts2 }
> CaseMerge
case x of { pi -> let z = y in ei
; alts2 }
The "let z=y" case-binder-swap gets dealt with in the next pass References 0
This Note does not link to any other.
Referenced by 3
- GHC.Core.Opt.Simplify call site
- GHC.Core.Opt.Stats call site
- Merge Nested Cases GHC.Core.Utils