[commit: ghc] master: When finding loop breakers, distinguish INLINE from INLINEABLE (3521c50)
git at git.haskell.org
git at git.haskell.org
Fri Aug 29 16:17:18 UTC 2014
Repository : ssh://git@git.haskell.org/ghc
On branch : master
Link : http://ghc.haskell.org/trac/ghc/changeset/3521c5078dace81b23a72d1e463f9c31d07f3816/ghc
>---------------------------------------------------------------
commit 3521c5078dace81b23a72d1e463f9c31d07f3816
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date: Fri Aug 29 15:18:08 2014 +0100
When finding loop breakers, distinguish INLINE from INLINEABLE
Previously INLINE and INLINEABLE were treated identically, but it's
crucial that we don't choose a wrapper (INLINE) as a loop breaker,
when it is mutually recursive with an INLINEABLE worker.
>---------------------------------------------------------------
3521c5078dace81b23a72d1e463f9c31d07f3816
compiler/coreSyn/CoreSyn.lhs | 17 +++++++++----
compiler/simplCore/OccurAnal.lhs | 55 ++++++++++++++--------------------------
2 files changed, 31 insertions(+), 41 deletions(-)
diff --git a/compiler/coreSyn/CoreSyn.lhs b/compiler/coreSyn/CoreSyn.lhs
index 6627ab0..babece4 100644
--- a/compiler/coreSyn/CoreSyn.lhs
+++ b/compiler/coreSyn/CoreSyn.lhs
@@ -58,7 +58,7 @@ module CoreSyn (
maybeUnfoldingTemplate, otherCons,
isValueUnfolding, isEvaldUnfolding, isCheapUnfolding,
isExpandableUnfolding, isConLikeUnfolding, isCompulsoryUnfolding,
- isStableUnfolding, isStableCoreUnfolding_maybe,
+ isStableUnfolding, hasStableCoreUnfolding_maybe,
isClosedUnfolding, hasSomeUnfolding,
canUnfold, neverUnfoldGuidance, isStableSource,
@@ -929,10 +929,17 @@ expandUnfolding_maybe :: Unfolding -> Maybe CoreExpr
expandUnfolding_maybe (CoreUnfolding { uf_expandable = True, uf_tmpl = rhs }) = Just rhs
expandUnfolding_maybe _ = Nothing
-isStableCoreUnfolding_maybe :: Unfolding -> Maybe UnfoldingSource
-isStableCoreUnfolding_maybe (CoreUnfolding { uf_src = src })
- | isStableSource src = Just src
-isStableCoreUnfolding_maybe _ = Nothing
+hasStableCoreUnfolding_maybe :: Unfolding -> Maybe Bool
+-- Just True <=> has stable inlining, very keen to inline (eg. INLINE pragma)
+-- Just False <=> has stable inlining, open to inlining it (eg. INLINEABLE pragma)
+-- Nothing <=> not table, or cannot inline it anyway
+hasStableCoreUnfolding_maybe (CoreUnfolding { uf_src = src, uf_guidance = guide })
+ | isStableSource src
+ = case guide of
+ UnfWhen {} -> Just True
+ UnfIfGoodArgs {} -> Just False
+ UnfNever -> Nothing
+hasStableCoreUnfolding_maybe _ = Nothing
isCompulsoryUnfolding :: Unfolding -> Bool
isCompulsoryUnfolding (CoreUnfolding { uf_src = InlineCompulsory }) = True
diff --git a/compiler/simplCore/OccurAnal.lhs b/compiler/simplCore/OccurAnal.lhs
index 7a237c8..ca0fc22 100644
--- a/compiler/simplCore/OccurAnal.lhs
+++ b/compiler/simplCore/OccurAnal.lhs
@@ -879,13 +879,14 @@ reOrderNodes depth bndr_set weak_fvs (node : nodes) binds
| isDFunId bndr = 9 -- Never choose a DFun as a loop breaker
-- Note [DFuns should not be loop breakers]
- | Just _ <- isStableCoreUnfolding_maybe (idUnfolding bndr)
- = 3 -- Note [INLINE pragmas]
+ | Just be_very_keen <- hasStableCoreUnfolding_maybe (idUnfolding bndr)
+ = if be_very_keen then 6 -- Note [Loop breakers and INLINE/INLINEABLE pragmas]
+ else 3
-- Data structures are more important than INLINE pragmas
-- so that dictionary/method recursion unravels
- -- Note that this case hits all InlineRule things, so we
- -- never look at 'rhs' for InlineRule stuff. That's right, because
- -- 'rhs' is irrelevant for inlining things with an InlineRule
+ -- Note that this case hits all stable unfoldings, so we
+ -- never look at 'rhs' for stable unfoldings. That's right, because
+ -- 'rhs' is irrelevant for inlining things with a stable unfolding
| is_con_app rhs = 5 -- Data types help with cases: Note [Constructor applications]
@@ -962,43 +963,25 @@ The RULES stuff means that we can't choose $dm as a loop breaker
opInt *and* opBool, and so on. The number of loop breakders is
linear in the number of instance declarations.
-Note [INLINE pragmas]
-~~~~~~~~~~~~~~~~~~~~~
+Note [Loop breakers and INLINE/INLINEABLE pragmas]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Avoid choosing a function with an INLINE pramga as the loop breaker!
If such a function is mutually-recursive with a non-INLINE thing,
then the latter should be the loop-breaker.
- ----> Historical note, dating from when strictness wrappers
- were generated from the strictness signatures:
+It's vital to distinguish between INLINE and INLINEABLE (the
+Bool returned by hasStableCoreUnfolding_maybe). If we start with
+ Rec { {-# INLINEABLE f #-}
+ f x = ...f... }
+and then worker/wrapper it through strictness analysis, we'll get
+ Rec { {-# INLINEABLE $wf #-}
+ $wf p q = let x = (p,q) in ...f...
- Usually this is just a question of optimisation. But a particularly
- bad case is wrappers generated by the demand analyser: if you make
- then into a loop breaker you may get an infinite inlining loop. For
- example:
- rec {
- $wfoo x = ....foo x....
+ {-# INLINE f #-}
+ f x = case x of (p,q) -> $wf p q }
- {-loop brk-} foo x = ...$wfoo x...
- }
- The interface file sees the unfolding for $wfoo, and sees that foo is
- strict (and hence it gets an auto-generated wrapper). Result: an
- infinite inlining in the importing scope. So be a bit careful if you
- change this. A good example is Tree.repTree in
- nofib/spectral/minimax. If the repTree wrapper is chosen as the loop
- breaker then compiling Game.hs goes into an infinite loop. This
- happened when we gave is_con_app a lower score than inline candidates:
-
- Tree.repTree
- = __inline_me (/\a. \w w1 w2 ->
- case Tree.$wrepTree @ a w w1 w2 of
- { (# ww1, ww2 #) -> Branch @ a ww1 ww2 })
- Tree.$wrepTree
- = /\a w w1 w2 ->
- (# w2_smP, map a (Tree a) (Tree.repTree a w1 w) (w w2) #)
-
- Here we do *not* want to choose 'repTree' as the loop breaker.
-
- -----> End of historical note
+Now it is vital that we choose $wf as the loop breaker, so we can
+inline 'f' in '$wf'.
Note [DFuns should not be loop breakers]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
More information about the ghc-commits
mailing list