diff options
author | Sebastian Graf <sebastian.graf@kit.edu> | 2019-02-19 13:52:11 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2019-03-07 20:44:08 -0500 |
commit | 1675d40afe07b9c414eaa37d85819f37f8420118 (patch) | |
tree | 0e0fe32fdf1a70a90e2c531a89b0a16b07fbad20 /compiler | |
parent | 068b7e983f4a0b35f453aa5e609998efd0c3f334 (diff) | |
download | haskell-1675d40afe07b9c414eaa37d85819f37f8420118.tar.gz |
Always do the worker/wrapper split for NOINLINEs
Trac #10069 revealed that small NOINLINE functions didn't get split
into worker and wrapper. This was due to `certainlyWillInline`
saying that any unfoldings with a guidance of `UnfWhen` inline
unconditionally. That isn't the case for NOINLINE functions, so we
catch this case earlier now.
Nofib results:
--------------------------------------------------------------------------------
Program Allocs Instrs
--------------------------------------------------------------------------------
fannkuch-redux -0.3% 0.0%
gg +0.0% +0.1%
maillist -0.2% -0.2%
minimax 0.0% -0.8%
--------------------------------------------------------------------------------
Min -0.3% -0.8%
Max +0.0% +0.1%
Geometric Mean -0.0% -0.0%
Fixes #10069.
-------------------------
Metric Increase:
T9233
-------------------------
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/coreSyn/CoreUnfold.hs | 13 | ||||
-rw-r--r-- | compiler/stranal/WorkWrap.hs | 31 |
2 files changed, 37 insertions, 7 deletions
diff --git a/compiler/coreSyn/CoreUnfold.hs b/compiler/coreSyn/CoreUnfold.hs index 3ac35c9848..e55e12487b 100644 --- a/compiler/coreSyn/CoreUnfold.hs +++ b/compiler/coreSyn/CoreUnfold.hs @@ -1118,13 +1118,14 @@ smallEnoughToInline _ _ ---------------- certainlyWillInline :: DynFlags -> IdInfo -> Maybe Unfolding --- Sees if the unfolding is pretty certain to inline --- If so, return a *stable* unfolding for it, that will always inline +-- ^ Sees if the unfolding is pretty certain to inline. +-- If so, return a *stable* unfolding for it, that will always inline. certainlyWillInline dflags fn_info = case unfoldingInfo fn_info of CoreUnfolding { uf_tmpl = e, uf_guidance = g } - | loop_breaker -> Nothing -- Won't inline, so try w/w - | otherwise -> do_cunf e g -- Depends on size, so look at that + | loop_breaker -> Nothing -- Won't inline, so try w/w + | noinline -> Nothing -- See Note [Worker-wrapper for NOINLINE functions] + | otherwise -> do_cunf e g -- Depends on size, so look at that DFunUnfolding {} -> Just fn_unf -- Don't w/w DFuns; it never makes sense -- to do so, and even if it is currently a @@ -1134,6 +1135,7 @@ certainlyWillInline dflags fn_info where loop_breaker = isStrongLoopBreaker (occInfo fn_info) + noinline = inlinePragmaSpec (inlinePragInfo fn_info) == NoInline fn_unf = unfoldingInfo fn_info do_cunf :: CoreExpr -> UnfoldingGuidance -> Maybe Unfolding @@ -1148,9 +1150,6 @@ certainlyWillInline dflags fn_info -- See Note [certainlyWillInline: INLINABLE] do_cunf expr (UnfIfGoodArgs { ug_size = size, ug_args = args }) | not (null args) -- See Note [certainlyWillInline: be careful of thunks] - , case inlinePragmaSpec (inlinePragInfo fn_info) of - NoInline -> False -- NOINLINE; do not say certainlyWillInline! - _ -> True -- INLINE, INLINABLE, or nothing , not (isBottomingSig (strictnessInfo fn_info)) -- Do not unconditionally inline a bottoming functions even if -- it seems smallish. We've carefully lifted it out to top level, diff --git a/compiler/stranal/WorkWrap.hs b/compiler/stranal/WorkWrap.hs index 34cfd64ecd..8f34b3b2ec 100644 --- a/compiler/stranal/WorkWrap.hs +++ b/compiler/stranal/WorkWrap.hs @@ -242,6 +242,37 @@ NOINLINE pragma to the worker. (See Trac #13143 for a real-world example.) +It is crucial that we do this for *all* NOINLINE functions. Trac #10069 +demonstrates what happens when we promise to w/w a (NOINLINE) leaf function, but +fail to deliver: + + data C = C Int# Int# + + {-# NOINLINE c1 #-} + c1 :: C -> Int# + c1 (C _ n) = n + + {-# NOINLINE fc #-} + fc :: C -> Int# + fc c = 2 *# c1 c + +Failing to w/w `c1`, but still w/wing `fc` leads to the following code: + + c1 :: C -> Int# + c1 (C _ n) = n + + $wfc :: Int# -> Int# + $wfc n = let c = C 0# n in 2 #* c1 c + + fc :: C -> Int# + fc (C _ n) = $wfc n + +Yikes! The reboxed `C` in `$wfc` can't cancel out, so we are in a bad place. +This generalises to any function that derives its strictness signature from +its callees, so we have to make sure that when a function announces particular +strictness properties, we have to w/w them accordingly, even if it means +splitting a NOINLINE function. + Note [Worker activation] ~~~~~~~~~~~~~~~~~~~~~~~~ Follows on from Note [Worker-wrapper for INLINABLE functions] |