{-# LANGUAGE BangPatterns #-}
module GHC.Core.Opt.Simplify.Inline (
couldBeSmallEnoughToInline,
smallEnoughToInline,
callSiteInline, CallCtxt(..),
) where
import GHC.Prelude
import GHC.Driver.Flags
import GHC.Core
import GHC.Core.Unfold
import GHC.Types.Id
import GHC.Types.Basic ( Arity, RecFlag(..) )
import GHC.Utils.Logger
import GHC.Utils.Misc
import GHC.Utils.Outputable
import GHC.Types.Name
import Data.List (isPrefixOf)
couldBeSmallEnoughToInline :: UnfoldingOpts -> Int -> CoreExpr -> Bool
couldBeSmallEnoughToInline :: UnfoldingOpts -> Int -> CoreExpr -> Bool
couldBeSmallEnoughToInline UnfoldingOpts
opts Int
threshold CoreExpr
rhs
= case UnfoldingOpts -> Int -> [Id] -> CoreExpr -> ExprSize
sizeExpr UnfoldingOpts
opts Int
threshold [] CoreExpr
body of
ExprSize
TooBig -> Bool
False
ExprSize
_ -> Bool
True
where
([Id]
_, CoreExpr
body) = CoreExpr -> ([Id], CoreExpr)
forall b. Expr b -> ([b], Expr b)
collectBinders CoreExpr
rhs
smallEnoughToInline :: UnfoldingOpts -> Unfolding -> Bool
smallEnoughToInline :: UnfoldingOpts -> Unfolding -> Bool
smallEnoughToInline UnfoldingOpts
opts (CoreUnfolding {uf_guidance :: Unfolding -> UnfoldingGuidance
uf_guidance = UnfoldingGuidance
guidance})
= case UnfoldingGuidance
guidance of
UnfIfGoodArgs {ug_size :: UnfoldingGuidance -> Int
ug_size = Int
size} -> Int
size Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= UnfoldingOpts -> Int
unfoldingUseThreshold UnfoldingOpts
opts
UnfWhen {} -> Bool
True
UnfoldingGuidance
UnfNever -> Bool
False
smallEnoughToInline UnfoldingOpts
_ Unfolding
_
= Bool
False
callSiteInline :: Logger
-> UnfoldingOpts
-> Int
-> Id
-> Bool
-> Bool
-> [ArgSummary]
-> CallCtxt
-> Maybe CoreExpr
callSiteInline :: Logger
-> UnfoldingOpts
-> Int
-> Id
-> Bool
-> Bool
-> [ArgSummary]
-> CallCtxt
-> Maybe CoreExpr
callSiteInline Logger
logger UnfoldingOpts
opts !Int
case_depth Id
id Bool
active_unfolding Bool
lone_variable [ArgSummary]
arg_infos CallCtxt
cont_info
= case IdUnfoldingFun
idUnfolding Id
id of
CoreUnfolding { uf_tmpl :: Unfolding -> CoreExpr
uf_tmpl = CoreExpr
unf_template
, uf_cache :: Unfolding -> UnfoldingCache
uf_cache = UnfoldingCache
unf_cache
, uf_guidance :: Unfolding -> UnfoldingGuidance
uf_guidance = UnfoldingGuidance
guidance }
| Bool
active_unfolding -> Logger
-> UnfoldingOpts
-> Int
-> Id
-> Bool
-> [ArgSummary]
-> CallCtxt
-> CoreExpr
-> UnfoldingCache
-> UnfoldingGuidance
-> Maybe CoreExpr
tryUnfolding Logger
logger UnfoldingOpts
opts Int
case_depth Id
id Bool
lone_variable
[ArgSummary]
arg_infos CallCtxt
cont_info CoreExpr
unf_template
UnfoldingCache
unf_cache UnfoldingGuidance
guidance
| Bool
otherwise -> Logger
-> UnfoldingOpts
-> Id
-> String
-> SDoc
-> Maybe CoreExpr
-> Maybe CoreExpr
forall a. Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline Logger
logger UnfoldingOpts
opts Id
id String
"Inactive unfolding:" (Id -> SDoc
forall a. Outputable a => a -> SDoc
ppr Id
id) Maybe CoreExpr
forall a. Maybe a
Nothing
Unfolding
NoUnfolding -> Maybe CoreExpr
forall a. Maybe a
Nothing
Unfolding
BootUnfolding -> Maybe CoreExpr
forall a. Maybe a
Nothing
OtherCon {} -> Maybe CoreExpr
forall a. Maybe a
Nothing
DFunUnfolding {} -> Maybe CoreExpr
forall a. Maybe a
Nothing
traceInline :: Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline :: forall a. Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline Logger
logger UnfoldingOpts
opts Id
inline_id String
str SDoc
doc a
result
| Bool
enable = Logger -> String -> SDoc -> a -> a
forall a. Logger -> String -> SDoc -> a -> a
logTraceMsg Logger
logger String
str SDoc
doc a
result
| Bool
otherwise = a
result
where
enable :: Bool
enable
| Logger -> DumpFlag -> Bool
logHasDumpFlag Logger
logger DumpFlag
Opt_D_dump_verbose_inlinings
= Bool
True
| Just String
prefix <- UnfoldingOpts -> Maybe String
unfoldingReportPrefix UnfoldingOpts
opts
= String
prefix String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` OccName -> String
occNameString (Id -> OccName
forall a. NamedThing a => a -> OccName
getOccName Id
inline_id)
| Bool
otherwise
= Bool
False
{-# INLINE traceInline #-}
tryUnfolding :: Logger -> UnfoldingOpts -> Int -> Id -> Bool -> [ArgSummary] -> CallCtxt
-> CoreExpr -> UnfoldingCache -> UnfoldingGuidance
-> Maybe CoreExpr
tryUnfolding :: Logger
-> UnfoldingOpts
-> Int
-> Id
-> Bool
-> [ArgSummary]
-> CallCtxt
-> CoreExpr
-> UnfoldingCache
-> UnfoldingGuidance
-> Maybe CoreExpr
tryUnfolding Logger
logger UnfoldingOpts
opts !Int
case_depth Id
id Bool
lone_variable [ArgSummary]
arg_infos
CallCtxt
cont_info CoreExpr
unf_template UnfoldingCache
unf_cache UnfoldingGuidance
guidance
= case UnfoldingGuidance
guidance of
UnfoldingGuidance
UnfNever -> Logger
-> UnfoldingOpts
-> Id
-> String
-> SDoc
-> Maybe CoreExpr
-> Maybe CoreExpr
forall a. Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline Logger
logger UnfoldingOpts
opts Id
id String
str (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"UnfNever") Maybe CoreExpr
forall a. Maybe a
Nothing
UnfWhen { ug_arity :: UnfoldingGuidance -> Int
ug_arity = Int
uf_arity, ug_unsat_ok :: UnfoldingGuidance -> Bool
ug_unsat_ok = Bool
unsat_ok, ug_boring_ok :: UnfoldingGuidance -> Bool
ug_boring_ok = Bool
boring_ok }
| Bool
enough_args Bool -> Bool -> Bool
&& (Bool
boring_ok Bool -> Bool -> Bool
|| Bool
some_benefit Bool -> Bool -> Bool
|| UnfoldingOpts -> Bool
unfoldingVeryAggressive UnfoldingOpts
opts)
-> Logger
-> UnfoldingOpts
-> Id
-> String
-> SDoc
-> Maybe CoreExpr
-> Maybe CoreExpr
forall a. Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline Logger
logger UnfoldingOpts
opts Id
id String
str (Bool -> SDoc -> Bool -> SDoc
mk_doc Bool
some_benefit SDoc
forall doc. IsOutput doc => doc
empty Bool
True) (CoreExpr -> Maybe CoreExpr
forall a. a -> Maybe a
Just CoreExpr
unf_template)
| Bool
otherwise
-> Logger
-> UnfoldingOpts
-> Id
-> String
-> SDoc
-> Maybe CoreExpr
-> Maybe CoreExpr
forall a. Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline Logger
logger UnfoldingOpts
opts Id
id String
str (Bool -> SDoc -> Bool -> SDoc
mk_doc Bool
some_benefit SDoc
forall doc. IsOutput doc => doc
empty Bool
False) Maybe CoreExpr
forall a. Maybe a
Nothing
where
some_benefit :: Bool
some_benefit = Int -> Bool
calc_some_benefit Int
uf_arity
enough_args :: Bool
enough_args = (Int
n_val_args Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
uf_arity) Bool -> Bool -> Bool
|| (Bool
unsat_ok Bool -> Bool -> Bool
&& Int
n_val_args Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0)
UnfIfGoodArgs { ug_args :: UnfoldingGuidance -> [Int]
ug_args = [Int]
arg_discounts, ug_res :: UnfoldingGuidance -> Int
ug_res = Int
res_discount, ug_size :: UnfoldingGuidance -> Int
ug_size = Int
size }
| UnfoldingOpts -> Bool
unfoldingVeryAggressive UnfoldingOpts
opts
-> Logger
-> UnfoldingOpts
-> Id
-> String
-> SDoc
-> Maybe CoreExpr
-> Maybe CoreExpr
forall a. Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline Logger
logger UnfoldingOpts
opts Id
id String
str (Bool -> SDoc -> Bool -> SDoc
mk_doc Bool
some_benefit SDoc
extra_doc Bool
True) (CoreExpr -> Maybe CoreExpr
forall a. a -> Maybe a
Just CoreExpr
unf_template)
| Bool
is_wf Bool -> Bool -> Bool
&& Bool
some_benefit Bool -> Bool -> Bool
&& Bool
small_enough
-> Logger
-> UnfoldingOpts
-> Id
-> String
-> SDoc
-> Maybe CoreExpr
-> Maybe CoreExpr
forall a. Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline Logger
logger UnfoldingOpts
opts Id
id String
str (Bool -> SDoc -> Bool -> SDoc
mk_doc Bool
some_benefit SDoc
extra_doc Bool
True) (CoreExpr -> Maybe CoreExpr
forall a. a -> Maybe a
Just CoreExpr
unf_template)
| Bool
otherwise
-> Logger
-> UnfoldingOpts
-> Id
-> String
-> SDoc
-> Maybe CoreExpr
-> Maybe CoreExpr
forall a. Logger -> UnfoldingOpts -> Id -> String -> SDoc -> a -> a
traceInline Logger
logger UnfoldingOpts
opts Id
id String
str (Bool -> SDoc -> Bool -> SDoc
mk_doc Bool
some_benefit SDoc
extra_doc Bool
False) Maybe CoreExpr
forall a. Maybe a
Nothing
where
some_benefit :: Bool
some_benefit = Int -> Bool
calc_some_benefit ([Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
arg_discounts)
depth_treshold :: Int
depth_treshold = UnfoldingOpts -> Int
unfoldingCaseThreshold UnfoldingOpts
opts
depth_scaling :: Int
depth_scaling = UnfoldingOpts -> Int
unfoldingCaseScaling UnfoldingOpts
opts
depth_penalty :: Int
depth_penalty | Int
case_depth Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
depth_treshold = Int
0
| Bool
otherwise = (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
case_depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
depth_treshold)) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
depth_scaling
adjusted_size :: Int
adjusted_size = Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
depth_penalty Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
discount
small_enough :: Bool
small_enough = Int
adjusted_size Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= UnfoldingOpts -> Int
unfoldingUseThreshold UnfoldingOpts
opts
discount :: Int
discount = [Int] -> Int -> [ArgSummary] -> CallCtxt -> Int
computeDiscount [Int]
arg_discounts Int
res_discount [ArgSummary]
arg_infos CallCtxt
cont_info
extra_doc :: SDoc
extra_doc = [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat [ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"case depth =" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Int -> SDoc
forall doc. IsLine doc => Int -> doc
int Int
case_depth
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"depth based penalty =" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Int -> SDoc
forall doc. IsLine doc => Int -> doc
int Int
depth_penalty
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"discounted size =" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Int -> SDoc
forall doc. IsLine doc => Int -> doc
int Int
adjusted_size ]
where
UnfoldingCache{ uf_is_work_free :: UnfoldingCache -> Bool
uf_is_work_free = Bool
is_wf, uf_expandable :: UnfoldingCache -> Bool
uf_expandable = Bool
is_exp } = UnfoldingCache
unf_cache
mk_doc :: Bool -> SDoc -> Bool -> SDoc
mk_doc Bool
some_benefit SDoc
extra_doc Bool
yes_or_no
= [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat [ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"arg infos" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> [ArgSummary] -> SDoc
forall a. Outputable a => a -> SDoc
ppr [ArgSummary]
arg_infos
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"interesting continuation" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> CallCtxt -> SDoc
forall a. Outputable a => a -> SDoc
ppr CallCtxt
cont_info
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"some_benefit" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Bool -> SDoc
forall a. Outputable a => a -> SDoc
ppr Bool
some_benefit
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"is exp:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Bool -> SDoc
forall a. Outputable a => a -> SDoc
ppr Bool
is_exp
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"is work-free:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Bool -> SDoc
forall a. Outputable a => a -> SDoc
ppr Bool
is_wf
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"guidance" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> UnfoldingGuidance -> SDoc
forall a. Outputable a => a -> SDoc
ppr UnfoldingGuidance
guidance
, SDoc
extra_doc
, String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"ANSWER =" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> if Bool
yes_or_no then String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"YES" else String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"NO"]
ctx :: SDocContext
ctx = LogFlags -> SDocContext
log_default_dump_context (Logger -> LogFlags
logFlags Logger
logger)
str :: String
str = String
"Considering inlining: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ SDocContext -> SDoc -> String
showSDocOneLine SDocContext
ctx (Id -> SDoc
forall a. Outputable a => a -> SDoc
ppr Id
id)
n_val_args :: Int
n_val_args = [ArgSummary] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ArgSummary]
arg_infos
calc_some_benefit :: Arity -> Bool
calc_some_benefit :: Int -> Bool
calc_some_benefit Int
uf_arity
| Bool -> Bool
not Bool
saturated = Bool
interesting_args
| Bool
otherwise = Bool
interesting_args
Bool -> Bool -> Bool
|| Bool
interesting_call
where
saturated :: Bool
saturated = Int
n_val_args Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
uf_arity
over_saturated :: Bool
over_saturated = Int
n_val_args Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
uf_arity
interesting_args :: Bool
interesting_args = (ArgSummary -> Bool) -> [ArgSummary] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ArgSummary -> Bool
nonTriv [ArgSummary]
arg_infos
interesting_call :: Bool
interesting_call
| Bool
over_saturated
= Bool
True
| Bool
otherwise
= case CallCtxt
cont_info of
CallCtxt
CaseCtxt -> Bool -> Bool
not (Bool
lone_variable Bool -> Bool -> Bool
&& Bool
is_exp)
CallCtxt
ValAppCtxt -> Bool
True
CallCtxt
RuleArgCtxt -> Int
uf_arity Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
CallCtxt
DiscArgCtxt -> Int
uf_arity Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
RhsCtxt RecFlag
NonRecursive
-> Int
uf_arity Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
CallCtxt
_other -> Bool
False
computeDiscount :: [Int] -> Int -> [ArgSummary] -> CallCtxt
-> Int
computeDiscount :: [Int] -> Int -> [ArgSummary] -> CallCtxt -> Int
computeDiscount [Int]
arg_discounts Int
res_discount [ArgSummary]
arg_infos CallCtxt
cont_info
= Int
10
Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
10 Int -> Int -> Int
forall a. Num a => a -> a -> a
* [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
actual_arg_discounts
Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
total_arg_discount Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
res_discount'
where
actual_arg_discounts :: [Int]
actual_arg_discounts = (Int -> ArgSummary -> Int) -> [Int] -> [ArgSummary] -> [Int]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> ArgSummary -> Int
forall {a}. Num a => a -> ArgSummary -> a
mk_arg_discount [Int]
arg_discounts [ArgSummary]
arg_infos
total_arg_discount :: Int
total_arg_discount = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int]
actual_arg_discounts
mk_arg_discount :: a -> ArgSummary -> a
mk_arg_discount a
_ ArgSummary
TrivArg = a
0
mk_arg_discount a
_ ArgSummary
NonTrivArg = a
10
mk_arg_discount a
discount ArgSummary
ValueArg = a
discount
res_discount' :: Int
res_discount'
| Ordering
LT <- [Int]
arg_discounts [Int] -> [ArgSummary] -> Ordering
forall a b. [a] -> [b] -> Ordering
`compareLength` [ArgSummary]
arg_infos
= Int
res_discount
| Bool
otherwise
= case CallCtxt
cont_info of
CallCtxt
BoringCtxt -> Int
0
CallCtxt
CaseCtxt -> Int
res_discount
CallCtxt
ValAppCtxt -> Int
res_discount
CallCtxt
_ -> Int
40 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
res_discount