[GHC] #11731: Simplifier: Inlining trivial let can lose sharing

GHC ghc-devs at haskell.org
Thu Mar 31 09:24:55 UTC 2016


#11731: Simplifier: Inlining trivial let can lose sharing
-------------------------------------+-------------------------------------
        Reporter:  nomeata           |                Owner:
            Type:  bug               |               Status:  patch
        Priority:  normal            |            Milestone:
       Component:  Compiler          |              Version:  8.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):  Phab:D2064
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 Meanwhile, there is a separate issue in comment:20.  It seems that for any
 un-saturated lambda, we nuke (a) the `occInfo` on the binders (fair
 enough; the next run of the occurrence analyser will regenerate it), and
 (b) the `demandInfo` on the binders.  The reasoning is explained in
 comment:20.

 But (b) is permanent; it won't be re-generated until the next run of the
 demand analyser.  And, worse, it applies to function definitions
 {{{
 f = \xy . x+y
 }}}
 Here `x` and `y` will be marked as strictly demanded, but that info will
 get stripped after the first run of the simplifier. Try it on
 {{{
 f :: [Int] -> [Int] -> Int
 f x y = head x + head y
 }}}
 After the demand analyser we have
 {{{
 f = \ (x_amY [Dmd=<S,1*U>] :: [Int]) (y_amZ [Dmd=<S,1*U>] :: [Int]) -> ...
 }}}
 but after the first run of the simplifier we get
 {{{
 f = \ (x_amY :: [Int]) (y_amZ :: [Int]) -> ...
 }}}
 (`f` itself still has a strictness signature that says it is strict in
 both args.)

 Does this matter?  Well, the main reason is that if `f` is inlined, we'd
 like to get a strict `let`.  And now we won't.

 Happily I think it is easily fixed.  The key thing is that when doing
 beta-reduction, which effectively does `(\x.e) b` into `let x=b in e`, we
 must kill off x's demand/occurrence info if the lambda is not saturated.

 So, idea, in `Simplify.hs`:

  * Give an extra `Bool` to `simplLam` indictating "saturated".

  * Compute (value) saturation in the `simplExprF1 env expr@(Lam {}) cont`,
 before calling `simpLam`, but do no zapping.

  * In `simplLam`, in the beta-reduction case,
 {{{
 simplLam env (bndr:bndrs) body (ApplyToVal { sc_arg = arg, sc_env = arg_se
                                            , sc_cont = cont })
   = do  { tick (BetaReduction bndr)
         ; simplNonRecE env' (zap_unfolding bndr) (arg, arg_se) (bndrs,
 body) cont }
 }}}
   do the binder-zapping right there, if "saturated" is not true.  (That
 neatly puts it with the unfolding-zapping code.)

 Now the non-beta-reduced lambdas won't be zapped, which is right.

 Would you like to try that?

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11731#comment:30>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list