
#11731: Simplifier: Inlining trivial let can lose sharing -------------------------------------+------------------------------------- Reporter: nomeata | Owner: Type: bug | Status: new 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): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nomeata):
I tried the test program with -O; but it only prints "Evaluated" once. So, strangely, I can't reproduce the bug. What exact commands did you use?
Well spotted! I ran with `-O2`, and indeed, it does not happen with `-O`, but with `-O -fspec-constr`. Nothing deep here, it’s just that constructor specialization is required in this particular example to massage the code into the shape we want.
Does using -flate-dmd-anal fix the problem?
Indeed it does. It recalculates the demand signature correctly, and will share the `shareMeThunk`. But after `-flate-dmd-anal`, there is another round of worker-wrapper and simplifier. So the principle, the problem could occur again. I would prefer to take a step back and think about what, at the level of Core, the semantics of {{{ let x = y in foo x }}} should be, independent of any possible annotations. Here a digression that follows that train of thought: If this code should indeed guarantee that `y` is evaluated at most once, then rewriting to `foo y` is in general wrong (and may only be justified if we ''know'' that `foo` evaluates its argument only once – this is more conservative than not doing the substitution if we happen to know that it can go wrong). Alternatively, we declare the semantics that a `let` with a trivial RHS should ''not'' (guarantee) sharin (just like a trivial function argument does not indicate sharing!). But then the problem was one step earlier where GHC replaced {{{ let x = case (y,z) of (y,z) -> y in foo x }}} with the trivial let above. Maybe it should have changed it to something like {{{ let x = share y in foo x }}} where `share` is a magic id that is semantically the identity, but prevents the `let` from being trivial. Now `x` can even be safely inlined then `foo (share y)`. The simplifier could know some rules about when occurrences of `share` can be removed (e.g. when the argument is not trivial any more, or when it is itself known to be shared). -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/11731#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler