X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Fstranal%2FWorkWrap.lhs;h=a3219abb2044e780f8cf8a4bbe5a0815b2c968b7;hb=cbbee4e8727c583daf32d9bf17f00afaa839ef10;hp=71f9ef831756df690335096bcec0ad9a648b3272;hpb=62eeda5aed31173b234b2965ccf4bd6979ffd9a4;p=ghc-hetmet.git diff --git a/compiler/stranal/WorkWrap.lhs b/compiler/stranal/WorkWrap.lhs index 71f9ef8..a3219ab 100644 --- a/compiler/stranal/WorkWrap.lhs +++ b/compiler/stranal/WorkWrap.lhs @@ -6,32 +6,31 @@ \begin{code} module WorkWrap ( wwTopBinds, mkWrapper ) where -#include "HsVersions.h" - import CoreSyn import CoreUnfold ( certainlyWillInline ) -import CoreUtils ( exprType, exprIsHNF ) +import CoreUtils ( exprType, exprIsHNF, mkInlineMe ) import CoreArity ( exprArity ) import Var -import Id ( Id, idType, isOneShotLambda, +import Id ( Id, idType, isOneShotLambda, idUnfolding, setIdNewStrictness, mkWorkerId, - setIdWorkerInfo, setInlinePragma, + setIdWorkerInfo, setInlineActivation, setIdArity, idInfo ) -import MkId ( lazyIdKey, lazyIdUnfolding ) import Type ( Type ) import IdInfo import NewDemand ( Demand(..), StrictSig(..), DmdType(..), DmdResult(..), Demands(..), mkTopDmdType, isBotRes, returnsCPR, topSig, isAbsent ) import UniqSupply -import Unique ( hasKey ) -import BasicTypes ( RecFlag(..), isNonRec, isNeverActive ) +import BasicTypes ( RecFlag(..), isNonRec, isNeverActive, + Activation, inlinePragmaActivation ) import VarEnv ( isEmptyVarEnv ) import Maybes ( orElse ) import WwLib import Util ( lengthIs, notNull ) import Outputable import MonadUtils + +#include "HsVersions.h" \end{code} We take Core bindings whose binders have: @@ -106,17 +105,12 @@ matching by looking for strict arguments of the correct type. \begin{code} wwExpr :: CoreExpr -> UniqSM CoreExpr -wwExpr e@(Type _) = return e -wwExpr e@(Lit _) = return e +wwExpr e@(Type {}) = return e +wwExpr e@(Lit {}) = return e +wwExpr e@(Var {}) = return e wwExpr e@(Note InlineMe _) = return e -- Don't w/w inside InlineMe's -wwExpr e@(Var v) - | v `hasKey` lazyIdKey = return lazyIdUnfolding - | otherwise = return e - -- HACK alert: Inline 'lazy' after strictness analysis - -- (but not inside InlineMe's) - wwExpr (Lam binder expr) = Lam binder <$> wwExpr expr @@ -161,7 +155,7 @@ reason), then we don't w-w it. The only reason this is monadised is for the unique supply. -Note [Don't w/w inline things] +Note [Don't w/w inline things (a)] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's very important to refrain from w/w-ing an INLINE function If we do so by mistake we transform @@ -182,6 +176,21 @@ Notice that we refrain from w/w'ing an INLINE function even if it is in a recursive group. It might not be the loop breaker. (We could test for loop-breaker-hood, but I'm not sure that ever matters.) +Note [Don't w/w inline things (b)] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In general, therefore, we refrain from w/w-ing *small* functions, +because they'll inline anyway. But we must take care: it may look +small now, but get to be big later after other inling has happened. +So we take the precaution of adding an INLINE pragma to any such +functions. + +I made this change when I observed a big function at the end of +compilation with a useful strictness signature but no w-w. When +I measured it on nofib, it didn't make much difference; just a few +percent improved allocation on one benchmark (bspt/Euclid.space). +But nothing got worse. + + \begin{code} tryWW :: RecFlag -> Id -- The fn binder @@ -193,21 +202,22 @@ tryWW :: RecFlag -- if two, then a worker and a -- wrapper. tryWW is_rec fn_id rhs - | -- isNonRec is_rec && -- Now omitted: see Note [Don't w/w inline things] - certainlyWillInline unfolding - - || isNeverActive inline_prag + | isNeverActive inline_act -- No point in worker/wrappering if the thing is never inlined! -- Because the no-inline prag will prevent the wrapper ever -- being inlined at a call site. - = return [ (new_fn_id, rhs) ] + -- + -- Furthermore, don't even expose strictness info + = return [ (fn_id, rhs) ] | is_thunk && worthSplittingThunk maybe_fn_dmd res_info = ASSERT2( isNonRec is_rec, ppr new_fn_id ) -- The thunk must be non-recursive + checkSize new_fn_id rhs $ splitThunk new_fn_id rhs | is_fun && worthSplittingFun wrap_dmds res_info - = splitFun new_fn_id fn_info wrap_dmds res_info inline_prag rhs + = checkSize new_fn_id rhs $ + splitFun new_fn_id fn_info wrap_dmds res_info inline_act rhs | otherwise = return [ (new_fn_id, rhs) ] @@ -215,8 +225,7 @@ tryWW is_rec fn_id rhs where fn_info = idInfo fn_id maybe_fn_dmd = newDemandInfo fn_info - unfolding = unfoldingInfo fn_info - inline_prag = inlinePragInfo fn_info + inline_act = inlinePragmaActivation (inlinePragInfo fn_info) -- In practice it always will have a strictness -- signature, even if it's a uninformative one @@ -236,9 +245,19 @@ tryWW is_rec fn_id rhs is_thunk = not is_fun && not (exprIsHNF rhs) --------------------- -splitFun :: Id -> IdInfo -> [Demand] -> DmdResult -> InlinePragInfo -> Expr Var +checkSize :: Id -> CoreExpr -> UniqSM [(Id,CoreExpr)] -> UniqSM [(Id,CoreExpr)] + -- See Note [Don't w/w inline things (a) and (b)] +checkSize fn_id rhs thing_inside + | certainlyWillInline unfolding = return [ (fn_id, mkInlineMe rhs) ] + -- Note [Don't w/w inline things (b)] + | otherwise = thing_inside + where + unfolding = idUnfolding fn_id + +--------------------- +splitFun :: Id -> IdInfo -> [Demand] -> DmdResult -> Activation -> Expr Var -> UniqSM [(Id, CoreExpr)] -splitFun fn_id fn_info wrap_dmds res_info inline_prag rhs +splitFun fn_id fn_info wrap_dmds res_info inline_act rhs = WARN( not (wrap_dmds `lengthIs` arity), ppr fn_id <+> (ppr arity $$ ppr wrap_dmds $$ ppr res_info) ) (do { -- The arity should match the signature @@ -247,13 +266,14 @@ splitFun fn_id fn_info wrap_dmds res_info inline_prag rhs ; let work_rhs = work_fn rhs work_id = mkWorkerId work_uniq fn_id (exprType work_rhs) - `setInlinePragma` inline_prag - -- Any inline pragma (which sets when inlining is active) + `setInlineActivation` inline_act + -- Any inline activation (which sets when inlining is active) -- on the original function is duplicated on the worker and wrapper -- It *matters* that the pragma stays on the wrapper -- It seems sensible to have it on the worker too, although we -- can't think of a compelling reason. (In ptic, INLINE things are - -- not w/wd) + -- not w/wd). However, the RuleMatchInfo is not transferred since + -- it does not make sense for workers to be constructorlike. `setIdNewStrictness` StrictSig (mkTopDmdType work_demands work_res_info) -- Even though we may not be at top level, -- it's ok to give it an empty DmdEnv