Consider this program using Data.Vector.unsafeThaw and -fno-cse:
{-# OPTIONS_GHC -fno-cse #-}import qualified Data.Vector as Vimport qualified Data.Vector.Mutable as VMmain :: IO ()main = do foo 100000 foo 100000 let f = foo 100000 in f >> ffoo :: 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 >> f55
Shouldn't -fno-cse fix this?
(Note: This also happens with ghc instead of ghci.)
Edited
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Child items
0
Show closed items
No child items are currently assigned. Use child items to break down this issue into smaller parts.
Linked items
0
Link issues together to show that they're related or that one is blocking others.
Learn more.
Niklas Hambüchenchanged title from ghci floats out constant despite -fno-cse, resulting in very unintuitive behaviour to ghci floats out constant despite -fno-cse
changed title from ghci floats out constant despite -fno-cse, resulting in very unintuitive behaviour to ghci floats out constant despite -fno-cse
Niklas Hambüchenchanged title from ghci floats out constant despite -fno-cse to ghc floats out constant despite -fno-cse
changed title from ghci floats out constant despite -fno-cse to ghc floats out constant despite -fno-cse
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.
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).
Naturally noinline doesn't have to be used, it would be enough that unsafeThaw was used in some function that is too big or recursive causing for it to not be inlined. This loop, for example, will do the trick:
loop n v = go 0 where go i | i < n = putStrLn ("iter: " ++ show i) >> go (i + 1) | otherwise = V.unsafeThaw v
Maybe nofloat proposed in #12620 could be a solution here.