
Hi I have a program (below) which when compiled with -O2 gives the result: H:\work\supero\charcount>type log.txt | diff.exe i am here 109 done The process tried to write to a nonexistent pipe. And when compiled with -O0 gives: H:\work\supero\charcount>type log.txt | diff i am here 109 i am here 111 done The process tried to write to a nonexistent pipe. It tries to read two characters, so I really do want two characters to appear. I have tried NOINLINE, but with no effect. Any suggestions? Thanks Neil --------------- -- The program import System.IO.Unsafe import System.IO import Data.Word import Debug.Trace main = p_System_IO_hGetChar 1 `seq` p_System_IO_hGetChar 2 `seq` putStrLn "done" {-# NOINLINE wrapIO #-} wrapIO x = unsafePerformIO (x >>= return) foreign import ccall "stdio.h getchar" getchar :: IO Word8 {-# NOINLINE p_System_IO_hGetChar #-} p_System_IO_hGetChar h = trace "i am here" $ wrapIO (getchar >>= \c -> print c >> return (if c == (-1) then 0 else chr_ c)) chr_ = fromEnum

Hi Bulat,
Wednesday, May 2, 2007, 7:00:05 PM, you wrote:
{-# NOINLINE wrapIO #-} wrapIO x = unsafePerformIO (x >>= return)
-fno-cse ? it's usual company for unsafePerformIO+NOINLINE :)
No luck, alas. A slightly tweaked version, which is slightly simpler and still gives the same behaviour is below. Thanks Neil ---------------------- main = p_System_IO_hGetChar undefined `seq` p_System_IO_hGetChar 12 `seq` putStrLn "done" foreign import ccall "stdio.h getchar" getchar :: IO Word8 {-# NOINLINE p_System_IO_hGetChar #-} p_System_IO_hGetChar h = trace "i am here" $ unsafePerformIO (getchar >>= \c -> print c >> return (if c == (-1) then 0 else chr_ c)) chr_ = fromEnum

Hi
Thanks to dcoutts, I have now come up with an answer. I don't
understand why it works now, but not before. I do remember than
browsing either Core or STG is not a fun thing to do...
p_System_IO_hGetChar h = trace "i am here" $
unsafePerformIO $ getCharIO h
{-# NOINLINE getCharIO #-}
getCharIO h = do
c <- getchar
print c
return $ if c == (-1) then 0 else chr_ c
Thanks
Neil
On 5/2/07, Neil Mitchell
Hi Bulat,
Wednesday, May 2, 2007, 7:00:05 PM, you wrote:
{-# NOINLINE wrapIO #-} wrapIO x = unsafePerformIO (x >>= return)
-fno-cse ? it's usual company for unsafePerformIO+NOINLINE :)
No luck, alas. A slightly tweaked version, which is slightly simpler and still gives the same behaviour is below.
Thanks
Neil
----------------------
main = p_System_IO_hGetChar undefined `seq` p_System_IO_hGetChar 12 `seq` putStrLn "done"
foreign import ccall "stdio.h getchar" getchar :: IO Word8
{-# NOINLINE p_System_IO_hGetChar #-} p_System_IO_hGetChar h = trace "i am here" $ unsafePerformIO (getchar >>= \c -> print c >> return (if c == (-1) then 0 else chr_ c))
chr_ = fromEnum

On Wed, 2007-05-02 at 16:33 +0100, Neil Mitchell wrote:
Hi
Thanks to dcoutts, I have now come up with an answer. I don't understand why it works now, but not before.
main = p_System_IO_hGetChar 1 `seq` p_System_IO_hGetChar 2 `seq` putStrLn "done" This is fine (though note that p_System_IO_hGetChar 1 is a constant) the real problem is here: {-# NOINLINE p_System_IO_hGetChar #-} p_System_IO_hGetChar h = trace "i am here" $ unsafePerformIO $ getchar >>= \c -> print c >> return (if c == (-1) then 0 else chr_ c) You've tried to trick ghc into always calling this by passing a dummy 'h' parameter. Then 'h' is never used in the body. Note however that the whole body of this function is a constant and so ghc can (and at -O2 does) float it out as a CAF. This means you get the side effects of p_System_IO_hGetChar at most once. The solution of course is to use a full data dependency like IO or ST uses.
I do remember than browsing either Core or STG is not a fun thing to do...
So yeah, we see the above CAFs and let floating by looking at the core. We could do with a prettier pretty printer for core, I agree. Duncan

Neil Mitchell wrote:
Hi
Thanks to dcoutts, I have now come up with an answer. I don't understand why it works now, but not before. I do remember than browsing either Core or STG is not a fun thing to do...
p_System_IO_hGetChar h = trace "i am here" $ unsafePerformIO $ getCharIO h
{-# NOINLINE getCharIO #-} getCharIO h = do c <- getchar print c return $ if c == (-1) then 0 else chr_ c
This is clearly a misuse of unsafePerformIO (as I'm sure you're aware). Just out of interest - what's the context? Cheers, Simon

Hi Simon,
This is clearly a misuse of unsafePerformIO (as I'm sure you're aware). Just out of interest - what's the context?
I am writing an optimiser for Yhc, doing whole-program optimisation, with the intention of keeping it fast and high performance. Since writing out Yhc bytecode would kill any performance benefits, I am writing back to Haskell to be compiled with GHC. So the basic sequence of steps is: compile Haskell to Yhc Core transform Yhc Core convert Yhc Core to Haskell compile Haskell to GHC The problem I'm currently overcoming is that Yhc inserts its own IO monad, which isn't the same as the GHC one. By the time I get to GHC Haskell, all of the Yhc monad is invisible to GHC, so I have to unsafePerformIO the getchar/putchar functions. With this as the primitive getchar, it seems to work for my particular example, but is clearly a bit fragile. All the examples I'm doing for now are wc -c, wc -l, so shouldn't stress the IO much more than getchar/putchar. Thanks Neil
participants (4)
-
Bulat Ziganshin
-
Duncan Coutts
-
Neil Mitchell
-
Simon Marlow