[GHC] #12656: ghci floats out constant despite -fno-cse, resulting in very unintuitive behaviour

#12656: ghci floats out constant despite -fno-cse, resulting in very unintuitive behaviour -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: Incorrect result Unknown/Multiple | at runtime Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- Consider this program using `Data.Vector.unsafeThaw` and `-fno-cse`: {{{ {-# OPTIONS_GHC -fno-cse #-} import qualified Data.Vector as V import qualified Data.Vector.Mutable as VM main :: IO () main = do foo 100000 foo 100000 foo :: Int -> IO () foo n = do indexVector <- V.unsafeThaw $ V.generate n id x <- VM.read indexVector 5 VM.write indexVector 5 (x * x) print x -- In GHCI, we get: -- -- > :set -fno-cse -- -- > foo 100000 -- 5 -- > foo 100000 -- 5 -- -- > let f = foo 100000 in f >> f -- 5 -- 25 }}} I would expect that {{{
let f = foo 100000 in f >> f 5 5 }}}
Shouldn't `-fno-cse` fix this? (Note: With `ghc` instead of `ghci`, we don't observe this behaviour.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghci floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Description changed by nh2: @@ -13,0 +13,2 @@ + + let f = foo 100000 in f >> f @@ -47,1 +49,1 @@ - (Note: With `ghc` instead of `ghci`, we don't observe this behaviour.) + (Note: This also happens with `ghc` instead of `ghci`.) New description: Consider this program using `Data.Vector.unsafeThaw` and `-fno-cse`: {{{ {-# OPTIONS_GHC -fno-cse #-} import qualified Data.Vector as V import qualified Data.Vector.Mutable as VM main :: IO () main = do foo 100000 foo 100000 let f = foo 100000 in f >> f foo :: Int -> IO () foo n = do indexVector <- V.unsafeThaw $ V.generate n id x <- VM.read indexVector 5 VM.write indexVector 5 (x * x) print x -- In GHCI, we get: -- -- > :set -fno-cse -- -- > foo 100000 -- 5 -- > foo 100000 -- 5 -- -- > let f = foo 100000 in f >> f -- 5 -- 25 }}} I would expect that {{{
let f = foo 100000 in f >> f 5 5 }}}
Shouldn't `-fno-cse` fix this? (Note: This also happens with `ghc` instead of `ghci`.) -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nh2): Note that `{-# OPTIONS_GHC -fno-full-laziness #-}` also doesn't help here; how could I prevent the floating-out so that the use of `unsafeThaw` is safe? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nh2): Another note, using `-O` fixes the problem with `-O`, `main` prints: {{{ 5 5 5 5 }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nh2): This is using ghc `8.0.1` with `vector` from stackage `lts-7.1`. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nomeata): Have you tried `{-# NOINLINE foo #-}`? With unsafe stuff, it is often important to keep this local. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bitonic): I've verified that this happens with GHC 7.8 (lts-3) too. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bitonic): nomeata: `NOINLINE` will prevent this behavior because there will be no opportunity for floating out the expression and eliminating it. However, we're trying to understand why `-fno-full-laziness -fno-cse` does not prevent this, since it seems like it should. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bitonic): Actually I spoke too soon: this doesn't work even with `NOINLINE`! {{{ $ cat weird-float.hs import qualified Data.Vector as V import qualified Data.Vector.Mutable as VM main :: IO () main = do foo 100000 foo 100000 let f = foo 100000 in f >> f {-# NOINLINE foo #-} foo :: Int -> IO () foo n = do indexVector <- V.unsafeThaw $ V.generate n id x <- VM.read indexVector 5 VM.write indexVector 5 (x * x) print x $ stack exec --resolver lts-7 --package vector -- ghc -fforce-recomp -package vector -O0 -fno-full-laziness -fno-cse weird-float.hs -o weird- float-lts-7 Run from outside a project, using implicit global project config Using resolver: lts-7 specified on command line Selected resolver: lts-7.2 [1 of 1] Compiling Main ( weird-float.hs, weird-float.o ) Linking weird-float-lts-7 ... $ ./weird-float-lts-7 5 5 5 25 $ stack exec --resolver lts-7 --package vector -- ghc --version Run from outside a project, using implicit global project config Using resolver: lts-7 specified on command line Selected resolver: lts-7.2 The Glorious Glasgow Haskell Compilation System, version 8.0.1 }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by rwbarton): First note that `main` (and thus `-fno-cse`) is a red herring, since the behavior under consideration is that of `let f = foo 100000 in f >> f` which does not mention `main`. But this is just normal Haskell laziness in action, which becomes clear if you desugar `foo`. {{{ foo :: Int -> IO () foo n = (>>=) (V.unsafeThaw $ V.generate n id) (...) }}} If you bind `foo 100000` to a name `f`, then `f`'s subexpression `V.generate 100000 id` will only ever be evaluated once during the lifetime of `f`. Moral: `unsafeThaw` is unsafe. What's more mysterious is why you get the "expected" behavior from compiled code. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nomeata):
What's more mysterious is why you get the "expected" behavior from compiled code.
That could be the effect of the state hack, turning foo n = (>>=) (V.unsafeThaw $ V.generate n id) (...) into foo n rw# = (>>=) (V.unsafeThaw $ V.generate n id) (...) rw# and hence making `foo 1000` a PAP where nothing is shared yet. (Did not look at the Core, though.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:11 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bitonic): rwbarton: You're very right -- the fact that it "worked" compiling normally threw us in a loop. Thanks for clarifying! In light of this, I think we should warn people that `unsafeThaw` is way unsafer than the docs imply... -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by rwbarton): Oh I misread some of the earlier comments; it's only with `-O` that you get the "expected" behavior, while `ghc` without optimization behaves the same as `ghci`. Then there is no mystery (and indeed `-fno-state-hack` restores the non-optimized behavior as nomeata guessed). -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:13 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12656: ghc floats out constant despite -fno-cse -------------------------------------+------------------------------------- Reporter: nh2 | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj):
In light of this, I think we should warn people that unsafeThaw is way unsafer than the docs imply...
Or at least that if you are going to use `unsafeThaw` then `-fno-state- hack` would be a good companion. Simon -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12656#comment:14 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC