diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/GHC/Cmm/Info.hs | 19 | ||||
-rw-r--r-- | compiler/GHC/CmmToAsm.hs | 25 | ||||
-rw-r--r-- | compiler/GHC/CmmToLlvm.hs | 6 | ||||
-rw-r--r-- | compiler/GHC/CmmToLlvm/Base.hs | 13 | ||||
-rw-r--r-- | compiler/GHC/Data/Stream.hs | 165 | ||||
-rw-r--r-- | compiler/GHC/Driver/CodeOutput.hs | 2 |
6 files changed, 119 insertions, 111 deletions
diff --git a/compiler/GHC/Cmm/Info.hs b/compiler/GHC/Cmm/Info.hs index 9298df2544..eaa3c2a923 100644 --- a/compiler/GHC/Cmm/Info.hs +++ b/compiler/GHC/Cmm/Info.hs @@ -72,19 +72,20 @@ mkEmptyContInfoTable info_lbl cmmToRawCmm :: Logger -> DynFlags -> Stream IO CmmGroupSRTs a -> IO (Stream IO RawCmmGroup a) cmmToRawCmm logger dflags cmms - = do { uniqs <- mkSplitUniqSupply 'i' - ; let do_one :: UniqSupply -> [CmmDeclSRTs] -> IO (UniqSupply, [RawCmmDecl]) - do_one uniqs cmm = + = do { + ; let do_one :: [CmmDeclSRTs] -> IO [RawCmmDecl] + do_one cmm = do + uniqs <- mkSplitUniqSupply 'i' -- NB. strictness fixes a space leak. DO NOT REMOVE. withTimingSilent logger dflags (text "Cmm -> Raw Cmm") - forceRes $ - case initUs uniqs $ concatMapM (mkInfoTable dflags) cmm of - (b,uniqs') -> return (uniqs',b) - ; return (snd <$> Stream.mapAccumL_ do_one uniqs cmms) + (\x -> seqList x ()) + -- TODO: It might be better to make `mkInfoTable` run in + -- IO as well so we don't have to pass around + -- a UniqSupply (see #16843) + (return $ initUs_ uniqs $ concatMapM (mkInfoTable dflags) cmm) + ; return (Stream.mapM do_one cmms) } - where forceRes (uniqs, rawcmms) = - uniqs `seq` foldr (\decl r -> decl `seq` r) () rawcmms -- Make a concrete info table, represented as a list of CmmStatic -- (it can't be simply a list of Word, because the SRT field is diff --git a/compiler/GHC/CmmToAsm.hs b/compiler/GHC/CmmToAsm.hs index 8201b14ab9..5eda3f03a8 100644 --- a/compiler/GHC/CmmToAsm.hs +++ b/compiler/GHC/CmmToAsm.hs @@ -11,6 +11,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UnboxedTuples #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} @@ -296,7 +297,7 @@ finishNativeGen logger dflags config modLoc bufh@(BufHandle _ _ h) us ngs Opt_D_dump_asm_stats "NCG stats" FormatText -cmmNativeGenStream :: (OutputableP Platform statics, Outputable jumpDest, Instruction instr) +cmmNativeGenStream :: forall statics jumpDest instr a . (OutputableP Platform statics, Outputable jumpDest, Instruction instr) => Logger -> DynFlags -> NCGConfig @@ -304,14 +305,21 @@ cmmNativeGenStream :: (OutputableP Platform statics, Outputable jumpDest, Instru -> NcgImpl statics instr jumpDest -> BufHandle -> UniqSupply - -> Stream IO RawCmmGroup a + -> Stream.Stream IO RawCmmGroup a -> NativeGenAcc statics instr -> IO (NativeGenAcc statics instr, UniqSupply, a) cmmNativeGenStream logger dflags config modLoc ncgImpl h us cmm_stream ngs - = do r <- Stream.runStream cmm_stream - case r of - Left a -> + = loop us (Stream.runStream cmm_stream) ngs + where + ncglabel = text "NCG" + loop :: UniqSupply + -> Stream.StreamS IO RawCmmGroup a + -> NativeGenAcc statics instr + -> IO (NativeGenAcc statics instr, UniqSupply, a) + loop us s ngs = + case s of + Stream.Done a -> return (ngs { ngs_imports = reverse $ ngs_imports ngs , ngs_natives = reverse $ ngs_natives ngs , ngs_colorStats = reverse $ ngs_colorStats ngs @@ -319,7 +327,8 @@ cmmNativeGenStream logger dflags config modLoc ncgImpl h us cmm_stream ngs }, us, a) - Right (cmms, cmm_stream') -> do + Stream.Effect m -> m >>= \cmm_stream' -> loop us cmm_stream' ngs + Stream.Yield cmms cmm_stream' -> do (us', ngs'') <- withTimingSilent logger dflags @@ -345,10 +354,8 @@ cmmNativeGenStream logger dflags config modLoc ncgImpl h us cmm_stream ngs let ngs'' = ngs' { ngs_debug = ngs_debug ngs' ++ ldbgs, ngs_labels = [] } return (us', ngs'') - cmmNativeGenStream logger dflags config modLoc ncgImpl h us' - cmm_stream' ngs'' + loop us' cmm_stream' ngs'' - where ncglabel = text "NCG" -- | Do native code generation on all these cmms. -- diff --git a/compiler/GHC/CmmToLlvm.hs b/compiler/GHC/CmmToLlvm.hs index 3cf7b50ceb..21cfdf6dcd 100644 --- a/compiler/GHC/CmmToLlvm.hs +++ b/compiler/GHC/CmmToLlvm.hs @@ -77,13 +77,13 @@ llvmCodeGen logger dflags h cmm_stream -- run code generation a <- runLlvm logger dflags (fromMaybe supportedLlvmVersion mb_ver) bufh $ - llvmCodeGen' dflags (liftStream cmm_stream) + llvmCodeGen' dflags cmm_stream bFlush bufh return a -llvmCodeGen' :: DynFlags -> Stream.Stream LlvmM RawCmmGroup a -> LlvmM a +llvmCodeGen' :: DynFlags -> Stream.Stream IO RawCmmGroup a -> LlvmM a llvmCodeGen' dflags cmm_stream = do -- Preamble renderLlvm header @@ -91,7 +91,7 @@ llvmCodeGen' dflags cmm_stream cmmMetaLlvmPrelude -- Procedures - a <- Stream.consume cmm_stream llvmGroupLlvmGens + a <- Stream.consume cmm_stream liftIO llvmGroupLlvmGens -- Declare aliases for forward references opts <- getLlvmOpts diff --git a/compiler/GHC/CmmToLlvm/Base.hs b/compiler/GHC/CmmToLlvm/Base.hs index 84c82ef873..a943bfcebb 100644 --- a/compiler/GHC/CmmToLlvm/Base.hs +++ b/compiler/GHC/CmmToLlvm/Base.hs @@ -19,14 +19,14 @@ module GHC.CmmToLlvm.Base ( llvmVersionStr, llvmVersionList, LlvmM, - runLlvm, liftStream, withClearVars, varLookup, varInsert, + runLlvm, withClearVars, varLookup, varInsert, markStackReg, checkStackReg, funLookup, funInsert, getLlvmVer, getDynFlags, dumpIfSetLlvm, renderLlvm, markUsedVar, getUsedVars, ghcInternalFunctions, getPlatform, getLlvmOpts, getMetaUniqueId, - setUniqMeta, getUniqMeta, + setUniqMeta, getUniqMeta, liftIO, cmmToLlvmType, widthToLlvmFloat, widthToLlvmInt, llvmFunTy, llvmFunSig, llvmFunArgs, llvmStdFunAttrs, llvmFunAlign, llvmInfAlign, @@ -62,7 +62,6 @@ import GHC.Utils.BufHandle ( BufHandle ) import GHC.Types.Unique.Set import GHC.Types.Unique.Supply import GHC.Utils.Logger -import qualified GHC.Data.Stream as Stream import Data.Maybe (fromJust) import Control.Monad (ap) @@ -387,14 +386,6 @@ getEnv f = LlvmM (\env -> return (f env, env)) modifyEnv :: (LlvmEnv -> LlvmEnv) -> LlvmM () modifyEnv f = LlvmM (\env -> return ((), f env)) --- | Lift a stream into the LlvmM monad -liftStream :: Stream.Stream IO a x -> Stream.Stream LlvmM a x -liftStream s = Stream.Stream $ do - r <- liftIO $ Stream.runStream s - case r of - Left b -> return (Left b) - Right (a, r2) -> return (Right (a, liftStream r2)) - -- | Clear variables from the environment for a subcomputation withClearVars :: LlvmM a -> LlvmM a withClearVars m = LlvmM $ \env -> do diff --git a/compiler/GHC/Data/Stream.hs b/compiler/GHC/Data/Stream.hs index 7996ee7343..4e2bee4311 100644 --- a/compiler/GHC/Data/Stream.hs +++ b/compiler/GHC/Data/Stream.hs @@ -1,3 +1,6 @@ +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TupleSections #-} -- ----------------------------------------------------------------------------- -- -- (c) The University of Glasgow 2012 @@ -6,25 +9,28 @@ -- | Monadic streams module GHC.Data.Stream ( - Stream(..), yield, liftIO, - collect, collect_, consume, fromList, - map, mapM, mapAccumL, mapAccumL_ + Stream(..), StreamS(..), runStream, yield, liftIO, + collect, consume, fromList, + map, mapM, mapAccumL_ ) where import GHC.Prelude hiding (map,mapM) import Control.Monad hiding (mapM) +import Control.Monad.IO.Class -- | -- @Stream m a b@ is a computation in some Monad @m@ that delivers a sequence -- of elements of type @a@ followed by a result of type @b@. -- --- More concretely, a value of type @Stream m a b@ can be run using @runStream@ +-- More concretely, a value of type @Stream m a b@ can be run using @runStreamInternal@ -- in the Monad @m@, and it delivers either -- --- * the final result: @Left b@, or --- * @Right (a,str)@, where @a@ is the next element in the stream, and @str@ --- is a computation to get the rest of the stream. +-- * the final result: @Done b@, or +-- * @Yield a str@ where @a@ is the next element in the stream, and @str@ +-- is the rest of the stream +-- * @Effect mstr@ where @mstr@ is some action running in @m@ which +-- generates the rest of the stream. -- -- Stream is itself a Monad, and provides an operation 'yield' that -- produces a new element of the stream. This makes it convenient to turn @@ -38,57 +44,73 @@ import Control.Monad hiding (mapM) -- Stream, and the consumer pulls on the stream each time it wants a -- new value. -- -newtype Stream m a b = Stream { runStream :: m (Either b (a, Stream m a b)) } +-- 'Stream' is implemented in the "yoneda" style for efficiency. By +-- representing a stream in this manner 'fmap' and '>>=' operations are +-- accumulated in the function parameters before being applied once when +-- the stream is destroyed. In the old implementation each usage of 'mapM' +-- and '>>=' would traverse the entire stream in order to apply the +-- substitution at the leaves. +-- +-- The >>= operation for 'Stream' was a hot-spot in the ticky profile for +-- the "ManyConstructors" test which called the 'cg' function many times in +-- @StgToCmm.hs@ +-- +newtype Stream m a b = + Stream { runStreamInternal :: forall r' r . + (a -> m r') -- For fusing calls to `map` and `mapM` + -> (b -> StreamS m r' r) -- For fusing `>>=` + -> StreamS m r' r } + +runStream :: Applicative m => Stream m r' r -> StreamS m r' r +runStream st = runStreamInternal st pure Done + +data StreamS m a b = Yield a (StreamS m a b) + | Done b + | Effect (m (StreamS m a b)) -instance Monad f => Functor (Stream f a) where +instance Monad m => Functor (StreamS m a) where fmap = liftM -instance Monad m => Applicative (Stream m a) where - pure a = Stream (return (Left a)) +instance Monad m => Applicative (StreamS m a) where + pure = Done (<*>) = ap -instance Monad m => Monad (Stream m a) where +instance Monad m => Monad (StreamS m a) where + a >>= k = case a of + Done r -> k r + Yield a s -> Yield a (s >>= k) + Effect m -> Effect (fmap (>>= k) m) - Stream m >>= k = Stream $ do - r <- m - case r of - Left b -> runStream (k b) - Right (a,str) -> return (Right (a, str >>= k)) +instance Functor (Stream f a) where + fmap = liftM -yield :: Monad m => a -> Stream m a () -yield a = Stream (return (Right (a, return ()))) +instance Applicative (Stream m a) where + pure a = Stream $ \_f g -> g a + (<*>) = ap -liftIO :: IO a -> Stream IO b a -liftIO io = Stream $ io >>= return . Left +instance Monad (Stream m a) where + Stream m >>= k = Stream $ \f h -> m f (\a -> runStreamInternal (k a) f h) + +instance MonadIO m => MonadIO (Stream m b) where + liftIO io = Stream $ \_f g -> Effect (g <$> liftIO io) + +yield :: Monad m => a -> Stream m a () +yield a = Stream $ \f rest -> Effect (flip Yield (rest ()) <$> f a) -- | Turn a Stream into an ordinary list, by demanding all the elements. collect :: Monad m => Stream m a () -> m [a] -collect str = go str [] +collect str = go [] (runStream str) where - go str acc = do - r <- runStream str - case r of - Left () -> return (reverse acc) - Right (a, str') -> go str' (a:acc) + go acc (Done ()) = return (reverse acc) + go acc (Effect m) = m >>= go acc + go acc (Yield a k) = go (a:acc) k --- | Turn a Stream into an ordinary list, by demanding all the elements. -collect_ :: Monad m => Stream m a r -> m ([a], r) -collect_ str = go str [] - where - go str acc = do - r <- runStream str - case r of - Left r -> return (reverse acc, r) - Right (a, str') -> go str' (a:acc) - -consume :: Monad m => Stream m a b -> (a -> m ()) -> m b -consume str f = do - r <- runStream str - case r of - Left ret -> return ret - Right (a, str') -> do - f a - consume str' f +consume :: (Monad m, Monad n) => Stream m a b -> (forall a . m a -> n a) -> (a -> n ()) -> n b +consume str l f = go (runStream str) + where + go (Done r) = return r + go (Yield a p) = f a >> go p + go (Effect m) = l m >>= go -- | Turn a list into a 'Stream', by yielding each element in turn. fromList :: Monad m => [a] -> Stream m a () @@ -96,40 +118,27 @@ fromList = mapM_ yield -- | Apply a function to each element of a 'Stream', lazily map :: Monad m => (a -> b) -> Stream m a x -> Stream m b x -map f str = Stream $ do - r <- runStream str - case r of - Left x -> return (Left x) - Right (a, str') -> return (Right (f a, map f str')) +map f str = Stream $ \g h -> runStreamInternal str (g . f) h -- | Apply a monadic operation to each element of a 'Stream', lazily mapM :: Monad m => (a -> m b) -> Stream m a x -> Stream m b x -mapM f str = Stream $ do - r <- runStream str - case r of - Left x -> return (Left x) - Right (a, str') -> do - b <- f a - return (Right (b, mapM f str')) - --- | analog of the list-based 'mapAccumL' on Streams. This is a simple --- way to map over a Stream while carrying some state around. -mapAccumL :: Monad m => (c -> a -> m (c,b)) -> c -> Stream m a () - -> Stream m b c -mapAccumL f c str = Stream $ do - r <- runStream str - case r of - Left () -> return (Left c) - Right (a, str') -> do - (c',b) <- f c a - return (Right (b, mapAccumL f c' str')) - -mapAccumL_ :: Monad m => (c -> a -> m (c,b)) -> c -> Stream m a r +mapM f str = Stream $ \g h -> runStreamInternal str (g <=< f) h + +-- | Note this is not very efficient because it traverses the whole stream +-- before rebuilding it, avoid using it if you can. mapAccumL used to +-- implemented but it wasn't used anywhere in the compiler and has similar +-- effiency problems. +mapAccumL_ :: forall m a b c r . Monad m => (c -> a -> m (c,b)) -> c -> Stream m a r -> Stream m b (c, r) -mapAccumL_ f c str = Stream $ do - r <- runStream str - case r of - Left r -> return (Left (c, r)) - Right (a, str') -> do - (c',b) <- f c a - return (Right (b, mapAccumL_ f c' str')) +mapAccumL_ f c str = Stream $ \f h -> go c f h (runStream str) + + where + go :: c + -> (b -> m r') + -> ((c, r) -> StreamS m r' r1) + -> StreamS m a r + -> StreamS m r' r1 + go c _f1 h1 (Done r) = h1 (c, r) + go c f1 h1 (Yield a p) = Effect (f c a >>= (\(c', b) -> f1 b + >>= \r' -> return $ Yield r' (go c' f1 h1 p))) + go c f1 h1 (Effect m) = Effect (go c f1 h1 <$> m) diff --git a/compiler/GHC/Driver/CodeOutput.hs b/compiler/GHC/Driver/CodeOutput.hs index fb6d04afbf..134ee2f960 100644 --- a/compiler/GHC/Driver/CodeOutput.hs +++ b/compiler/GHC/Driver/CodeOutput.hs @@ -149,7 +149,7 @@ outputC logger dflags filenm cmm_stream packages = FormatC doc printForC dflags h doc - Stream.consume cmm_stream writeC + Stream.consume cmm_stream id writeC {- ************************************************************************ |