
#12620: Allow the user to prevent floating and CSE -------------------------------------+------------------------------------- Reporter: nomeata | Owner: Type: feature | Status: new request | 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: -------------------------------------+------------------------------------- This is a write-up of a rough idea that Andres Löw and me had at ICFP 2016 in order to address some Real World problems Andres noticed and that are currently hard to avoid. The goal is to give the user more control about expressions that the compiler would like to float out (or CSE), but the programmer knows better. Example (assume no list fusion exists): {{{ enum xs = zip [1..] xs }}} This leads to a horrible space leak, as GHC will float out `[1..]` to the top. Our idea is to have a magic function `nofloat :: a -> a` (magic in the same sense as `inline` and `lazy`) that the programmer would use here: {{{ enum xs = zip (nofloat [1..]) xs }}} With these effects: * Sub expressions are not floated out of a `nofloat`. * An expression of the form `nofloat e` would not be floated beyond the innermost enclosing lambda. * Two expressions of the form `nofloat e` would not be commoned up by CSE. This way, unwanted sharing is prevented. In contrast to a hypothetical `veryCheap` function, it does ''not'' mean that the compiler should float it into lambda (no unwanted duplication either). Two open questions (among many others, I am sure:) * Likely, rule matching should look through `nofloat`. At least in this example (and similar ones like `map (nofloat [1..])`, the rules in question will avoid the spaceleaks). * Possibly, nothing should be floated (inlined) ''into'' a `nofloat`. Rationale: Assume the library is changed so that {{{ [n..] = nofloat (realEnumFrom n) {-# INLINE [n..] #-} }}} Then `zip [fib 1000..]` would be rewritten by the inliner to `zip (let x = fib 1000 in (nofloat [x..]))`. Moving the `fib 1000` into the `nofloat` would change the behaviour in a possibly surprising way. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12620 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler