{-# LANGUAGE PatternSynonyms #-}
module GHC.Core.Opt.Simplify.Monad (
TopEnvConfig(..), SimplM,
initSmpl, traceSmpl,
getSimplRules,
MonadUnique(..), newId, newJoinId,
SimplCount, tick, freeTick, checkedTick,
getSimplCount, zeroSimplCount, pprSimplCount,
plusSimplCount, isZeroSimplCount
) where
import GHC.Prelude
import GHC.Types.Var ( Var, isId, mkLocalVar )
import GHC.Types.Name ( mkSystemVarName )
import GHC.Types.Id ( Id, mkSysLocalOrCoVarM )
import GHC.Types.Id.Info ( IdDetails(..), vanillaIdInfo, setArityInfo )
import GHC.Core.Type ( Type, Mult )
import GHC.Core.Opt.Stats
import GHC.Core.Rules
import GHC.Core.Utils ( mkLamTypes )
import GHC.Types.Unique.Supply
import GHC.Driver.Flags
import GHC.Utils.Outputable
import GHC.Data.FastString
import GHC.Utils.Monad
import GHC.Utils.Logger as Logger
import GHC.Utils.Misc ( count )
import GHC.Utils.Panic (throwGhcExceptionIO, GhcException (..))
import GHC.Types.Basic ( IntWithInf, treatZeroAsInf, mkIntWithInf )
import Control.Monad ( ap )
import GHC.Core.Multiplicity ( pattern ManyTy )
import GHC.Exts( oneShot )
newtype SimplM result
= SM' { forall result.
SimplM result
-> SimplTopEnv -> SimplCount -> IO (result, SimplCount)
unSM :: SimplTopEnv
-> SimplCount
-> IO (result, SimplCount)}
pattern SM :: (SimplTopEnv -> SimplCount
-> IO (result, SimplCount))
-> SimplM result
pattern $mSM :: forall {r} {result}.
SimplM result
-> ((SimplTopEnv -> SimplCount -> IO (result, SimplCount)) -> r)
-> ((# #) -> r)
-> r
$bSM :: forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM m <- SM' m
where
SM SimplTopEnv -> SimplCount -> IO (result, SimplCount)
m = (SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM' ((SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplTopEnv -> SimplCount -> IO (result, SimplCount)
forall a b. (a -> b) -> a -> b
oneShot ((SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> (SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplTopEnv
-> SimplCount
-> IO (result, SimplCount)
forall a b. (a -> b) -> a -> b
$ \SimplTopEnv
env -> (SimplCount -> IO (result, SimplCount))
-> SimplCount -> IO (result, SimplCount)
forall a b. (a -> b) -> a -> b
oneShot ((SimplCount -> IO (result, SimplCount))
-> SimplCount -> IO (result, SimplCount))
-> (SimplCount -> IO (result, SimplCount))
-> SimplCount
-> IO (result, SimplCount)
forall a b. (a -> b) -> a -> b
$ \SimplCount
ct -> SimplTopEnv -> SimplCount -> IO (result, SimplCount)
m SimplTopEnv
env SimplCount
ct)
data TopEnvConfig = TopEnvConfig
{ TopEnvConfig -> Int
te_history_size :: !Int
, TopEnvConfig -> Int
te_tick_factor :: !Int
}
data SimplTopEnv
= STE {
SimplTopEnv -> TopEnvConfig
st_config :: !TopEnvConfig
, SimplTopEnv -> Logger
st_logger :: !Logger
, SimplTopEnv -> IntWithInf
st_max_ticks :: !IntWithInf
, SimplTopEnv -> IO RuleEnv
st_read_ruleenv :: !(IO RuleEnv)
}
initSmpl :: Logger
-> IO RuleEnv
-> TopEnvConfig
-> Int
-> SimplM a
-> IO (a, SimplCount)
initSmpl :: forall a.
Logger
-> IO RuleEnv
-> TopEnvConfig
-> Int
-> SimplM a
-> IO (a, SimplCount)
initSmpl Logger
logger IO RuleEnv
read_ruleenv TopEnvConfig
cfg Int
size SimplM a
m
= do
let simplCount :: SimplCount
simplCount = Bool -> SimplCount
zeroSimplCount (Bool -> SimplCount) -> Bool -> SimplCount
forall a b. (a -> b) -> a -> b
$ Logger -> DumpFlag -> Bool
logHasDumpFlag Logger
logger DumpFlag
Opt_D_dump_simpl_stats
SimplM a -> SimplTopEnv -> SimplCount -> IO (a, SimplCount)
forall result.
SimplM result
-> SimplTopEnv -> SimplCount -> IO (result, SimplCount)
unSM SimplM a
m SimplTopEnv
env SimplCount
simplCount
where
env :: SimplTopEnv
env = STE { st_config :: TopEnvConfig
st_config = TopEnvConfig
cfg
, st_logger :: Logger
st_logger = Logger
logger
, st_max_ticks :: IntWithInf
st_max_ticks = TopEnvConfig -> Int -> IntWithInf
computeMaxTicks TopEnvConfig
cfg Int
size
, st_read_ruleenv :: IO RuleEnv
st_read_ruleenv = IO RuleEnv
read_ruleenv
}
computeMaxTicks :: TopEnvConfig -> Int -> IntWithInf
computeMaxTicks :: TopEnvConfig -> Int -> IntWithInf
computeMaxTicks TopEnvConfig
cfg Int
size
= Int -> IntWithInf
treatZeroAsInf (Int -> IntWithInf) -> Int -> IntWithInf
forall a b. (a -> b) -> a -> b
$
Integer -> Int
forall a. Num a => Integer -> a
fromInteger ((Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
base_size)
Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int
tick_factor Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
magic_multiplier))
Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
100)
where
tick_factor :: Int
tick_factor = TopEnvConfig -> Int
te_tick_factor TopEnvConfig
cfg
base_size :: Int
base_size = Int
100
magic_multiplier :: Int
magic_multiplier = Int
40
{-# INLINE thenSmpl #-}
{-# INLINE thenSmpl_ #-}
{-# INLINE returnSmpl #-}
{-# INLINE mapSmpl #-}
instance Functor SimplM where
fmap :: forall a b. (a -> b) -> SimplM a -> SimplM b
fmap = (a -> b) -> SimplM a -> SimplM b
forall a b. (a -> b) -> SimplM a -> SimplM b
mapSmpl
instance Applicative SimplM where
pure :: forall a. a -> SimplM a
pure = a -> SimplM a
forall a. a -> SimplM a
returnSmpl
<*> :: forall a b. SimplM (a -> b) -> SimplM a -> SimplM b
(<*>) = SimplM (a -> b) -> SimplM a -> SimplM b
forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap
*> :: forall a b. SimplM a -> SimplM b -> SimplM b
(*>) = SimplM a -> SimplM b -> SimplM b
forall a b. SimplM a -> SimplM b -> SimplM b
thenSmpl_
instance Monad SimplM where
>> :: forall a b. SimplM a -> SimplM b -> SimplM b
(>>) = SimplM a -> SimplM b -> SimplM b
forall a b. SimplM a -> SimplM b -> SimplM b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
(*>)
>>= :: forall a b. SimplM a -> (a -> SimplM b) -> SimplM b
(>>=) = SimplM a -> (a -> SimplM b) -> SimplM b
forall a b. SimplM a -> (a -> SimplM b) -> SimplM b
thenSmpl
mapSmpl :: (a -> b) -> SimplM a -> SimplM b
mapSmpl :: forall a b. (a -> b) -> SimplM a -> SimplM b
mapSmpl a -> b
f SimplM a
m = SimplM a -> (a -> SimplM b) -> SimplM b
forall a b. SimplM a -> (a -> SimplM b) -> SimplM b
thenSmpl SimplM a
m (b -> SimplM b
forall a. a -> SimplM a
returnSmpl (b -> SimplM b) -> (a -> b) -> a -> SimplM b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f)
returnSmpl :: a -> SimplM a
returnSmpl :: forall a. a -> SimplM a
returnSmpl a
e = (SimplTopEnv -> SimplCount -> IO (a, SimplCount)) -> SimplM a
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM (\SimplTopEnv
_st_env SimplCount
sc -> (a, SimplCount) -> IO (a, SimplCount)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a
e, SimplCount
sc))
thenSmpl :: SimplM a -> (a -> SimplM b) -> SimplM b
thenSmpl_ :: SimplM a -> SimplM b -> SimplM b
thenSmpl :: forall a b. SimplM a -> (a -> SimplM b) -> SimplM b
thenSmpl SimplM a
m a -> SimplM b
k
= (SimplTopEnv -> SimplCount -> IO (b, SimplCount)) -> SimplM b
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM ((SimplTopEnv -> SimplCount -> IO (b, SimplCount)) -> SimplM b)
-> (SimplTopEnv -> SimplCount -> IO (b, SimplCount)) -> SimplM b
forall a b. (a -> b) -> a -> b
$ \SimplTopEnv
st_env SimplCount
sc0 -> do
(m_result, sc1) <- SimplM a -> SimplTopEnv -> SimplCount -> IO (a, SimplCount)
forall result.
SimplM result
-> SimplTopEnv -> SimplCount -> IO (result, SimplCount)
unSM SimplM a
m SimplTopEnv
st_env SimplCount
sc0
unSM (k m_result) st_env sc1
thenSmpl_ :: forall a b. SimplM a -> SimplM b -> SimplM b
thenSmpl_ SimplM a
m SimplM b
k
= (SimplTopEnv -> SimplCount -> IO (b, SimplCount)) -> SimplM b
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM ((SimplTopEnv -> SimplCount -> IO (b, SimplCount)) -> SimplM b)
-> (SimplTopEnv -> SimplCount -> IO (b, SimplCount)) -> SimplM b
forall a b. (a -> b) -> a -> b
$ \SimplTopEnv
st_env SimplCount
sc0 -> do
(_, sc1) <- SimplM a -> SimplTopEnv -> SimplCount -> IO (a, SimplCount)
forall result.
SimplM result
-> SimplTopEnv -> SimplCount -> IO (result, SimplCount)
unSM SimplM a
m SimplTopEnv
st_env SimplCount
sc0
unSM k st_env sc1
traceSmpl :: String -> SDoc -> SimplM ()
traceSmpl :: String -> SDoc -> SimplM ()
traceSmpl String
herald SDoc
doc
= do logger <- SimplM Logger
forall (m :: * -> *). HasLogger m => m Logger
getLogger
liftIO $ Logger.putDumpFileMaybe logger Opt_D_dump_simpl_trace "Simpl Trace"
FormatText
(hang (text herald) 2 doc)
{-# INLINE traceSmpl #-}
simplTag :: Char
simplTag :: Char
simplTag = Char
's'
instance MonadUnique SimplM where
getUniqueSupplyM :: SimplM UniqSupply
getUniqueSupplyM = IO UniqSupply -> SimplM UniqSupply
forall a. IO a -> SimplM a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO UniqSupply -> SimplM UniqSupply)
-> IO UniqSupply -> SimplM UniqSupply
forall a b. (a -> b) -> a -> b
$ Char -> IO UniqSupply
mkSplitUniqSupply Char
simplTag
getUniqueM :: SimplM Unique
getUniqueM = IO Unique -> SimplM Unique
forall a. IO a -> SimplM a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Unique -> SimplM Unique) -> IO Unique -> SimplM Unique
forall a b. (a -> b) -> a -> b
$ Char -> IO Unique
uniqFromTag Char
simplTag
instance HasLogger SimplM where
getLogger :: SimplM Logger
getLogger = (SimplTopEnv -> Logger) -> SimplM Logger
forall a. (SimplTopEnv -> a) -> SimplM a
gets SimplTopEnv -> Logger
st_logger
instance MonadIO SimplM where
liftIO :: forall a. IO a -> SimplM a
liftIO = (SimplTopEnv -> IO a) -> SimplM a
forall a. (SimplTopEnv -> IO a) -> SimplM a
liftIOWithEnv ((SimplTopEnv -> IO a) -> SimplM a)
-> (IO a -> SimplTopEnv -> IO a) -> IO a -> SimplM a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> SimplTopEnv -> IO a
forall a b. a -> b -> a
const
getSimplRules :: SimplM RuleEnv
getSimplRules :: SimplM RuleEnv
getSimplRules = (SimplTopEnv -> IO RuleEnv) -> SimplM RuleEnv
forall a. (SimplTopEnv -> IO a) -> SimplM a
liftIOWithEnv SimplTopEnv -> IO RuleEnv
st_read_ruleenv
liftIOWithEnv :: (SimplTopEnv -> IO a) -> SimplM a
liftIOWithEnv :: forall a. (SimplTopEnv -> IO a) -> SimplM a
liftIOWithEnv SimplTopEnv -> IO a
m = (SimplTopEnv -> SimplCount -> IO (a, SimplCount)) -> SimplM a
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM (\SimplTopEnv
st_env SimplCount
sc -> do
x <- SimplTopEnv -> IO a
m SimplTopEnv
st_env
return (x, sc))
gets :: (SimplTopEnv -> a) -> SimplM a
gets :: forall a. (SimplTopEnv -> a) -> SimplM a
gets SimplTopEnv -> a
f = (SimplTopEnv -> IO a) -> SimplM a
forall a. (SimplTopEnv -> IO a) -> SimplM a
liftIOWithEnv (a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> IO a) -> (SimplTopEnv -> a) -> SimplTopEnv -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SimplTopEnv -> a
f)
newId :: FastString -> Mult -> Type -> SimplM Id
newId :: FastString -> Mult -> Mult -> SimplM Id
newId FastString
fs Mult
w Mult
ty = FastString -> Mult -> Mult -> SimplM Id
forall (m :: * -> *).
MonadUnique m =>
FastString -> Mult -> Mult -> m Id
mkSysLocalOrCoVarM FastString
fs Mult
w Mult
ty
newJoinId :: [Var] -> Type -> SimplM Id
newJoinId :: [Id] -> Mult -> SimplM Id
newJoinId [Id]
bndrs Mult
body_ty
= do { uniq <- SimplM Unique
forall (m :: * -> *). MonadUnique m => m Unique
getUniqueM
; let name = Unique -> FastString -> Name
mkSystemVarName Unique
uniq (String -> FastString
fsLit String
"$j")
join_id_ty = [Id] -> Mult -> Mult
mkLamTypes [Id]
bndrs Mult
body_ty
arity = (Id -> Bool) -> [Id] -> Int
forall a. (a -> Bool) -> [a] -> Int
count Id -> Bool
isId [Id]
bndrs
join_arity = [Id] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Id]
bndrs
details = Int -> Maybe [CbvMark] -> IdDetails
JoinId Int
join_arity Maybe [CbvMark]
forall a. Maybe a
Nothing
id_info = IdInfo
vanillaIdInfo IdInfo -> Int -> IdInfo
`setArityInfo` Int
arity
; return (mkLocalVar details name ManyTy join_id_ty id_info) }
getSimplCount :: SimplM SimplCount
getSimplCount :: SimplM SimplCount
getSimplCount = (SimplTopEnv -> SimplCount -> IO (SimplCount, SimplCount))
-> SimplM SimplCount
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM (\SimplTopEnv
_st_env SimplCount
sc -> (SimplCount, SimplCount) -> IO (SimplCount, SimplCount)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (SimplCount
sc, SimplCount
sc))
tick :: Tick -> SimplM ()
tick :: Tick -> SimplM ()
tick Tick
t = (SimplTopEnv -> SimplCount -> IO ((), SimplCount)) -> SimplM ()
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM (\SimplTopEnv
st_env SimplCount
sc -> let
history_size :: Int
history_size = TopEnvConfig -> Int
te_history_size (SimplTopEnv -> TopEnvConfig
st_config SimplTopEnv
st_env)
sc' :: SimplCount
sc' = Int -> Tick -> SimplCount -> SimplCount
doSimplTick Int
history_size Tick
t SimplCount
sc
in SimplCount
sc' SimplCount -> IO ((), SimplCount) -> IO ((), SimplCount)
forall a b. a -> b -> b
`seq` ((), SimplCount) -> IO ((), SimplCount)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((), SimplCount
sc'))
checkedTick :: Tick -> SimplM ()
checkedTick :: Tick -> SimplM ()
checkedTick Tick
t
= (SimplTopEnv -> SimplCount -> IO ((), SimplCount)) -> SimplM ()
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM (\SimplTopEnv
st_env SimplCount
sc ->
if SimplTopEnv -> IntWithInf
st_max_ticks SimplTopEnv
st_env IntWithInf -> IntWithInf -> Bool
forall a. Ord a => a -> a -> Bool
<= Int -> IntWithInf
mkIntWithInf (SimplCount -> Int
simplCountN SimplCount
sc)
then GhcException -> IO ((), SimplCount)
forall a. GhcException -> IO a
throwGhcExceptionIO (GhcException -> IO ((), SimplCount))
-> GhcException -> IO ((), SimplCount)
forall a b. (a -> b) -> a -> b
$
String -> SDoc -> GhcException
PprProgramError String
"Simplifier ticks exhausted" (SimplCount -> SDoc
msg SimplCount
sc)
else let
history_size :: Int
history_size = TopEnvConfig -> Int
te_history_size (SimplTopEnv -> TopEnvConfig
st_config SimplTopEnv
st_env)
sc' :: SimplCount
sc' = Int -> Tick -> SimplCount -> SimplCount
doSimplTick Int
history_size Tick
t SimplCount
sc
in SimplCount
sc' SimplCount -> IO ((), SimplCount) -> IO ((), SimplCount)
forall a b. a -> b -> b
`seq` ((), SimplCount) -> IO ((), SimplCount)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((), SimplCount
sc'))
where
msg :: SimplCount -> SDoc
msg SimplCount
sc = [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat
[ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"When trying" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Tick -> SDoc
forall a. Outputable a => a -> SDoc
ppr Tick
t
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"To increase the limit, use -fsimpl-tick-factor=N (default 100)."
, SDoc
forall doc. IsLine doc => doc
space
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"In addition try adjusting -funfolding-case-threshold=N and"
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"-funfolding-case-scaling=N for the module in question."
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Using threshold=1 and scaling=5 should break most inlining loops."
, SDoc
forall doc. IsLine doc => doc
space
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"If you need to increase the tick factor substantially, while also"
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"adjusting unfolding parameters please file a bug report and"
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"indicate the factor you needed."
, SDoc
forall doc. IsLine doc => doc
space
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"If GHC was unable to complete compilation even"
SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"with a very large factor"
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"(a thousand or more), please consult the"
SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc
doubleQuotes (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Known bugs or infelicities")
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"section in the Users Guide before filing a report. There are a"
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"few situations unlikely to occur in practical programs for which"
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"simplifier non-termination has been judged acceptable."
, SDoc
forall doc. IsLine doc => doc
space
, SimplCount -> SDoc
forall {doc}. IsLine doc => SimplCount -> doc
pp_details SimplCount
sc
, SimplCount -> SDoc
pprSimplCount SimplCount
sc ]
pp_details :: SimplCount -> doc
pp_details SimplCount
sc
| SimplCount -> Bool
hasDetailedCounts SimplCount
sc = doc
forall doc. IsOutput doc => doc
empty
| Bool
otherwise = String -> doc
forall doc. IsLine doc => String -> doc
text String
"To see detailed counts use -ddump-simpl-stats"
freeTick :: Tick -> SimplM ()
freeTick :: Tick -> SimplM ()
freeTick Tick
t
= (SimplTopEnv -> SimplCount -> IO ((), SimplCount)) -> SimplM ()
forall result.
(SimplTopEnv -> SimplCount -> IO (result, SimplCount))
-> SimplM result
SM (\SimplTopEnv
_st_env SimplCount
sc -> let sc' :: SimplCount
sc' = Tick -> SimplCount -> SimplCount
doFreeSimplTick Tick
t SimplCount
sc
in SimplCount
sc' SimplCount -> IO ((), SimplCount) -> IO ((), SimplCount)
forall a b. a -> b -> b
`seq` ((), SimplCount) -> IO ((), SimplCount)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((), SimplCount
sc'))