[GHC] #13996: Non-cheap primop is duplicated

#13996: Non-cheap primop is duplicated -------------------------------------+------------------------------------- Reporter: simonpj | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- Conal Elliot [https://mail.haskell.org/pipermail/ghc- devs/2017-July/014407.html writes]: I have {{{ exampleC :: Double -> Double -> Double exampleC = \ t -> let s = sin t in \ x -> x + s }}} But the `sin` ends up being pushed inside the lambda by the optimiser, like so: {{{ exampleC = \ t x -> x + sin t }}} So if I do `map (exampleC v) xs` I end up computing `sin v` once for each element of `xs` rather than once. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13996 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13996: Non-cheap primop is duplicated -------------------------------------+------------------------------------- Reporter: simonpj | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.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 simonpj): It’s a cost-model thing. GHC finds that the call to `sin` amounts to a single call to the primop `sinDouble#`. Is that cheap? If so, better to push it inside the inner lambda, so the two lambdas come together (generally a big win). E.g. if it was a single ‘add’ instruction, definitely better to push it inside. Look at `PrimOp.primOpIsCheap`; you’ll see that “cheapness” is approximated by * no side effects * cant fail * is a single instruction (i.e not a call to an out-of-line run-time system procedure) These three properties are set in `prelude/primops.txt.pp` Alas, `sinDouble#` satisfies all three things so it’s regarded as cheap. As Joachim says this may just be the wrong cost model for you. What to do? * Mitigate: `-fno-lambda-eta-expansion` * Hack to make `sin` look expensive: in `primops.txt.pp` set `can_fail` to true. This isn't true, but it's always safe. It'll have other minor effects on optimising `sin` but I doubt it'll matter. * The Right Thing: add a `is_expensive` property for each primop and set it in `primops.txt.pp`. That's a bit more work, but it lets us say what we want. I don't feel strongly about which path to take. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13996#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13996: Non-cheap primop is duplicated -------------------------------------+------------------------------------- Reporter: simonpj | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.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 mboes):
better to push it inside the inner lambda, so the two lambdas come together (generally a big win).
Note in particular that `-fno-lambda-eta-expansion` can be a huge pessimization in the following way. Consider this program: {{{#!hs module Main where f :: Double -> Double -> Double f t = let s = sin t in \x -> x + s main = do print $ sum [ f t x | t <- [1..10000], x <- [1..10000]] }}} `ghc --make -O2` yields a program that runs in constant space. Whereas adding `-fno-do-lambda-eta-expansion` to the command-line yields a program that segfaults, because its memory consumption blew up and it ultimately ran out of space. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13996#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13996: Non-cheap primop is duplicated -------------------------------------+------------------------------------- Reporter: simonpj | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.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 conal): Thanks for the explanation, Simon. The eta-expansion policy sounds very sensible to me, and now I understand that more expensive computations will not get pushed under lambdas. If GHC's cost model turns out not to fit my use, I can add some simple post-GHC transformations on the representation I use for generating GPU code. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13996#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13996: Non-cheap primop is duplicated -------------------------------------+------------------------------------- Reporter: simonpj | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.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: | -------------------------------------+------------------------------------- Changes (by George): * cc: George (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13996#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC