Switch to using a patched GHC

This commit is contained in:
Ryan Trinkle 2023-07-09 12:34:47 -04:00
parent ebdd46e76e
commit 6b27e947ee
3 changed files with 46 additions and 25 deletions

View File

@ -1,15 +1,21 @@
{-# LANGUAGE RecursiveDo #-}
{-# OPTIONS_GHC -fplugin UIO #-}
module Test.UIO where
module Test.UIO (test) where
import GHC.IO
import GHC.Magic
import Data.IORef
import Control.Monad
import UIO
import Test.UIO.MultiModule
import Test.UIO.Builder
test :: IO ()
test = do
putStrLn "testUIOBuilder"
testUIOBuilder
{-
putStrLn "testUIOFix"
testUIOFix
putStrLn "testUIOUnique"
@ -26,8 +32,11 @@ test = do
testIO
putStrLn "testMultiModule"
testMultiModule
-- putStrLn "testUIOPrintLots"
-- testUIOPrintLots
putStrLn "testFloatIn"
testFloatIn
putStrLn "testUIOPrintLots"
testUIOPrintLots
-}
{-# NOINLINE testUIOUnique #-}
testUIOUnique :: IO ()
@ -106,6 +115,16 @@ testUIOCycle = runUIO $ mdo
r <- timeless $ newIORef $ CycleRef r
pure ()
{-# NOINLINE testFloatIn #-}
testFloatIn :: IO ()
testFloatIn = runUIO $ do
r <- timeless $ newIORef 0
x <- unordered $ atomicModifyIORef r $ \x -> (succ x, succ x)
let {-# NOINLINE blah #-}
blah :: IO ()
blah = IO $ oneShot (\s -> unIO (print x) s)
unordered $ replicateM_ 10 blah
{-# NOINLINE testIO #-}
testIO :: IO ()
testIO = do

View File

@ -11,6 +11,7 @@ import Data.Foldable
import Data.Semigroup
import GHC.IO
import GHC.Prim
import GHC.Magic
import UIO.Plugin as X
@ -42,12 +43,12 @@ instance Applicative UIO where
{-# INLINE (<*>) #-}
pure x = UIO (\_ -> (RemainingWork, x))
UIO m *> UIO k = UIO (\s ->
let (ms, _) = m (uniqueState 1# s)
(ks, b) = k (uniqueState 2# s)
let (ms, _) = m (uniqueState# 1# s)
(ks, b) = k (uniqueState# 2# s)
in (ms <> ks, b))
UIO m <*> UIO k = UIO (\s ->
let (ms, f) = m (uniqueState 1# s)
(ks, x) = k (uniqueState 2# s)
let (ms, f) = m (uniqueState# 1# s)
(ks, x) = k (uniqueState# 2# s)
in (ms <> ks, f x))
instance Monad UIO where
@ -55,8 +56,8 @@ instance Monad UIO where
{-# INLINE (>>=) #-}
(>>) = (*>)
UIO m >>= k = UIO (\s ->
let (ms, a) = m (uniqueState 1# s)
(ks, b) = unUIO (k a) (uniqueState 2# s)
let (ms, a) = m (uniqueState# 1# s)
(ks, b) = unUIO (k a) (uniqueState# 2# s)
in (ms <> ks, b))
instance MonadFix UIO where
@ -68,7 +69,7 @@ instance MonadFix UIO where
runUIO :: UIO a -> IO a
runUIO (UIO m) = do
-- We use a bang pattern here instead of "evaluate", because "evaluate" leaves a "seq#" clutting up our core, but the bang pattern does not
(!RemainingWork, result) <- IO (\s -> (# s, m s #)) --TODO: This returns the same state we were given; should we call uniqueState 1 or something on it?
(!RemainingWork, result) <- IO (\s -> (# s, m s #)) --TODO: This returns the same state we were given; should we call uniqueState# 1# or something on it?
pure result
-- The following is marked NOINLINE because unsafeDupablePerformIO is marked NOINLINE. I don't really understand it.
@ -81,11 +82,10 @@ unordered (IO m) = UIO (\s -> let x = case m s of (# _, x #) -> x in (x `seq` Re
timeless :: IO a -> UIO a
timeless (IO m) = UIO (\s -> (RemainingWork, case m s of (# _, x #) -> x))
-- Force GHC to treat each of these state tokens as unique. This way, multiple identical calls, e.g. to newIORef are not treated as identical, because they have different state tokens. Ideally, we would inline this after common sub-expression elimination finishes, so that it is costless.
{-# NOINLINE uniqueState #-}
uniqueState :: Int# -> State# RealWorld -> State# RealWorld
uniqueState = uniqueState'
{-# INLINE listen #-}
listen :: UIO a -> UIO (RemainingWork, a)
listen (UIO m) = UIO (\s -> let (done, a) = m s in (done, (done, a)))
{-# NOINLINE uniqueState' #-}
uniqueState' :: Int# -> State# RealWorld -> State# RealWorld
uniqueState' _ s = s
{-# INLINE after #-}
after :: RemainingWork -> UIO a -> UIO a
after w (UIO m) = UIO (\s -> m (w `seq` s))

View File

@ -4,20 +4,21 @@
module UIO.Plugin (plugin) where
import GHC.Plugins
import Data.Generics.Schemes (everywhereM)
import Data.Generics.Aliases (mkM)
--import Data.Generics.Schemes (everywhereM)
--import Data.Generics.Aliases (mkM)
plugin :: Plugin
plugin = defaultPlugin
{ {- installCoreToDos = install
, -} pluginRecompile = purePlugin
}
{-
isSpecificFunction :: Id -> Bool
isSpecificFunction f = case nameModule_maybe (idName f) of
Just m -> moduleNameString (moduleName m) == "UIO" && getOccString f == "uniqueState"
Nothing -> False
plugin :: Plugin
plugin = defaultPlugin
{ installCoreToDos = install
, pluginRecompile = purePlugin
}
install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
install _ todos = do
let myPass = CoreDoPluginPass ("Inline UIO.uniqueState") inlineSpecificFunction
@ -53,3 +54,4 @@ inlineSpecificFunctionBindM transform (NonRec b e) = do
inlineSpecificFunctionBindM transform (Rec pairs) = do
pairs' <- mapM (\(b, e) -> everywhereM (mkM transform) e >>= \e' -> return (b, e')) pairs
return (Rec pairs')
-}