summaryrefslogtreecommitdiff
path: root/compiler/specialise
diff options
context:
space:
mode:
authorsimonpj@microsoft.com <unknown>2008-12-05 16:54:00 +0000
committersimonpj@microsoft.com <unknown>2008-12-05 16:54:00 +0000
commitd95ce839533391e7118257537044f01cbb1d6694 (patch)
treef0721012658d593367a60c890bb283465da7b339 /compiler/specialise
parentccd0e382566940a508fcb1aa7487bc7a785fc329 (diff)
downloadhaskell-d95ce839533391e7118257537044f01cbb1d6694.tar.gz
Completely new treatment of INLINE pragmas (big patch)
This is a major patch, which changes the way INLINE pragmas work. Although lots of files are touched, the net is only +21 lines of code -- and I bet that most of those are comments! HEADS UP: interface file format has changed, so you'll need to recompile everything. There is not much effect on overall performance for nofib, probably because those programs don't make heavy use of INLINE pragmas. Program Size Allocs Runtime Elapsed Min -11.3% -6.9% -9.2% -8.2% Max -0.1% +4.6% +7.5% +8.9% Geometric Mean -2.2% -0.2% -1.0% -0.8% (The +4.6% for on allocs is cichelli; see other patch relating to -fpass-case-bndr-to-join-points.) The old INLINE system ~~~~~~~~~~~~~~~~~~~~~ The old system worked like this. A function with an INLINE pragam got a right-hand side which looked like f = __inline_me__ (\xy. e) The __inline_me__ part was an InlineNote, and was treated specially in various ways. Notably, the simplifier didn't inline inside an __inline_me__ note. As a result, the code for f itself was pretty crappy. That matters if you say (map f xs), because then you execute the code for f, rather than inlining a copy at the call site. The new story: InlineRules ~~~~~~~~~~~~~~~~~~~~~~~~~~ The new system removes the InlineMe Note altogether. Instead there is a new constructor InlineRule in CoreSyn.Unfolding. This is a bit like a RULE, in that it remembers the template to be inlined inside the InlineRule. No simplification or inlining is done on an InlineRule, just like RULEs. An Id can have an InlineRule *or* a CoreUnfolding (since these are two constructors from Unfolding). The simplifier treats them differently: - An InlineRule is has the substitution applied (like RULES) but is otherwise left undisturbed. - A CoreUnfolding is updated with the new RHS of the definition, on each iteration of the simplifier. An InlineRule fires regardless of size, but *only* when the function is applied to enough arguments. The "arity" of the rule is specified (by the programmer) as the number of args on the LHS of the "=". So it makes a difference whether you say {-# INLINE f #-} f x = \y -> e or f x y = e This is one of the big new features that InlineRule gives us, and it is one that Roman really wanted. In contrast, a CoreUnfolding can fire when it is applied to fewer args than than the function has lambdas, provided the result is small enough. Consequential stuff ~~~~~~~~~~~~~~~~~~~ * A 'wrapper' no longer has a WrapperInfo in the IdInfo. Instead, the InlineRule has a field identifying wrappers. * Of course, IfaceSyn and interface serialisation changes appropriately. * Making implication constraints inline nicely was a bit fiddly. In the end I added a var_inline field to HsBInd.VarBind, which is why this patch affects the type checker slightly * I made some changes to the way in which eta expansion happens in CorePrep, mainly to ensure that *arguments* that become let-bound are also eta-expanded. I'm still not too happy with the clarity and robustness fo the result. * We now complain if the programmer gives an INLINE pragma for a recursive function (prevsiously we just ignored it). Reason for change: we don't want an InlineRule on a LoopBreaker, because then we'd have to check for loop-breaker-hood at occurrence sites (which isn't currenlty done). Some tests need changing as a result. This patch has been in my tree for quite a while, so there are probably some other minor changes.
Diffstat (limited to 'compiler/specialise')
-rw-r--r--compiler/specialise/Specialise.lhs33
1 files changed, 18 insertions, 15 deletions
diff --git a/compiler/specialise/Specialise.lhs b/compiler/specialise/Specialise.lhs
index 4d8efdd8c5..4a1cc4c37b 100644
--- a/compiler/specialise/Specialise.lhs
+++ b/compiler/specialise/Specialise.lhs
@@ -16,7 +16,7 @@ module Specialise ( specProgram ) where
import Id ( Id, idName, idType, mkUserLocal, idCoreRules,
idInlinePragma, setInlinePragma, setIdUnfolding,
- isLocalId )
+ isLocalId, idUnfolding )
import TcType ( Type, mkTyVarTy, tcSplitSigmaTy,
tyVarsOfTypes, tyVarsOfTheta, isClassPred,
tcCmpType, isUnLiftedType
@@ -26,7 +26,7 @@ import CoreSubst ( Subst, mkEmptySubst, extendTvSubstList, lookupIdSubst,
cloneIdBndr, cloneIdBndrs, cloneRecIdBndrs,
extendIdSubst
)
-import CoreUnfold ( mkUnfolding )
+import CoreUnfold ( mkUnfolding, mkInlineRule )
import SimplUtils ( interestingArg )
import Var ( DictId )
import VarSet
@@ -43,6 +43,7 @@ import Name
import MkId ( voidArgId, realWorldPrimId )
import FiniteMap
import Maybes ( catMaybes, isJust )
+import BasicTypes ( Arity )
import Bag
import Util
import Outputable
@@ -831,10 +832,14 @@ specDefn subst calls fn rhs
n_dicts = length theta
inline_prag = idInlinePragma fn
- -- It's important that we "see past" any INLINE pragma
- -- else we'll fail to specialise an INLINE thing
- (inline_rhs, rhs_inside) = dropInline rhs
- (rhs_tyvars, rhs_ids, rhs_body) = collectTyAndValBinders rhs_inside
+ -- Figure out whether the function has an INLINE pragma
+ -- See Note [Inline specialisations]
+ fn_has_inline_rule :: Maybe Arity -- Gives arity of the *specialised* inline rule
+ fn_has_inline_rule = case idUnfolding fn of
+ InlineRule { uf_arity = arity } -> Just (arity - n_dicts)
+ _other -> Nothing
+
+ (rhs_tyvars, rhs_ids, rhs_body) = collectTyAndValBinders rhs
rhs_dict_ids = take n_dicts rhs_ids
body = mkLams (drop n_dicts rhs_ids) rhs_body
@@ -922,10 +927,13 @@ specDefn subst calls fn rhs
-- Add the { d1' = dx1; d2' = dx2 } usage stuff
final_uds = foldr addDictBind rhs_uds dx_binds
- spec_pr | inline_rhs = (spec_f `setInlinePragma` inline_prag, Note InlineMe spec_rhs)
- | otherwise = (spec_f, spec_rhs)
-
- ; return (Just (spec_pr, final_uds, spec_env_rule)) } }
+ -- See Note [Inline specialisations]
+ final_spec_f | Just spec_arity <- fn_has_inline_rule
+ = spec_f `setInlinePragma` inline_prag
+ `setIdUnfolding` mkInlineRule spec_rhs spec_arity
+ | otherwise
+ = spec_f
+ ; return (Just ((final_spec_f, spec_rhs), final_uds, spec_env_rule)) } }
where
my_zipEqual xs ys zs
| debugIsOn && not (equalLength xs ys && equalLength ys zs)
@@ -1090,11 +1098,6 @@ specialised version.
A case in point is dictionary functions, which are current marked
INLINE, but which are worth specialising.
-\begin{code}
-dropInline :: CoreExpr -> (Bool, CoreExpr)
-dropInline (Note InlineMe rhs) = (True, rhs)
-dropInline rhs = (False, rhs)
-\end{code}
%************************************************************************
%* *