Thanks very much for this reply, Joachim. I see that `-fno-do-lambda-eta-expansion` with my example prevents moving the computation under the lambda where it gets repeatedly evaluated. I don't understand what this code motion/substitution has to do with eta-expansion. Is it that the `let` expression itself is eta-expanded? The GHC Users Guide describes this flag as "eta-expand let-bindings to increase their arity", which doesn't seem to fit here, since the `let`-bindings are not function-valued (though the `let` expression is).
Thanks also for the suggestion of using `-dverbose-core2core` to see where the unwanted substitution happened. Did you measure whether this really is a problem? The benefits of not > dealing with dynamically allocated functions might outweigh the cost of > recalculating sin. No, I haven't measured. In this case, I'm compiling Haskell to GLSL for execution on a GPU, where the inner lambda will be over space, which means at least one application per pixel, so the computations moved under the inner lambda will be redundantly computed a few millions of times per frame (and much more with anti-aliasing). Instead, I want to move those calculations to once per frame and stored in quickly accessed video memory. As the space-independent computation gets more complex, I expect the saving to grow. Thanks again, -- Conal On Tue, Jul 18, 2017 at 12:08 PM, Joachim Breitner <m...@joachim-breitner.de > wrote: > Hi, > > > Am Dienstag, den 18.07.2017, 08:34 -0700 schrieb Conal Elliott: > > I'm seeing what looks like repeated computation under a lambda with > > `-O` and `-O2`. The following definition: > > > > > exampleC :: Double -> Double -> Double > > > exampleC = \ t -> let s = sin t in \ x -> x + s > > > > yields this Core: > > > > > -- RHS size: {terms: 13, types: 6, coercions: 0} > > > exampleC :: Double -> Double -> Double > > > exampleC = > > > \ (t_afI6 :: Double) (eta_B1 :: Double) -> > > > case eta_B1 of _ { D# x_aj5c -> > > > case t_afI6 of _ { D# x1_aj5l -> > > > D# (+## x_aj5c (sinDouble# x1_aj5l)) > > > } > > > } > > ghc -O -dverbose-core2core shows you that the problem is this phase: > > ==================== Simplifier ==================== > Max iterations = 4 > SimplMode {Phase = 2 [main], > inline, > rules, > eta-expand, > case-of-case} > > It does not happen with -fno-do-lambda-eta-expansion (but you’d lose in > other parts.) > > > I'm concerned because many of my uses of such functions involve > > computations dependent only on `t` (time) but with millions of uses > > (space) per `t`. (I'm working on a GHC Core plugin (compiling to > > categories), with one use generating graphics GPU code.) > > Did you measure whether this really is a problem? The benefits of not > dealing with dynamically allocated functions might outweigh the cost of > recalculating sin. > > Greetings, > Joachim > -- > Joachim Breitner > m...@joachim-breitner.de > http://www.joachim-breitner.de/ > > _______________________________________________ > ghc-devs mailing list > ghc-devs@haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs > >
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs