summaryrefslogtreecommitdiff
path: root/compiler/stranal
diff options
context:
space:
mode:
authorSebastian Graf <sebastian.graf@kit.edu>2019-02-19 13:52:11 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2019-03-07 20:44:08 -0500
commit1675d40afe07b9c414eaa37d85819f37f8420118 (patch)
tree0e0fe32fdf1a70a90e2c531a89b0a16b07fbad20 /compiler/stranal
parent068b7e983f4a0b35f453aa5e609998efd0c3f334 (diff)
downloadhaskell-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/stranal')
-rw-r--r--compiler/stranal/WorkWrap.hs31
1 files changed, 31 insertions, 0 deletions
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]