summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Klebinger <klebinger.andreas@gmx.at>2022-06-16 11:51:20 +0200
committerAndreas Klebinger <klebinger.andreas@gmx.at>2022-08-03 17:34:51 +0200
commit683d4faadcf0780478ac6c57ab8e0c5cc2235820 (patch)
treeae26ad67ad2f324ab8163e7921231e6a7eb6f6fc
parent97655ad88c42003bc5eeb5c026754b005229800c (diff)
downloadhaskell-wip/andreask/ww_unlift_note.tar.gz
Add a note about about W/W for unlifting strict argumentswip/andreask/ww_unlift_note
This fixes #21236.
-rw-r--r--compiler/GHC/Core/Opt/WorkWrap/Utils.hs47
-rw-r--r--compiler/GHC/Driver/Session.hs2
2 files changed, 48 insertions, 1 deletions
diff --git a/compiler/GHC/Core/Opt/WorkWrap/Utils.hs b/compiler/GHC/Core/Opt/WorkWrap/Utils.hs
index d3f3928f7a..ab664c494b 100644
--- a/compiler/GHC/Core/Opt/WorkWrap/Utils.hs
+++ b/compiler/GHC/Core/Opt/WorkWrap/Utils.hs
@@ -784,6 +784,53 @@ before calling the partially applied function. But this would be neither a small
stick with A) and a flag for B) for now.
See also Note [Tag Inference] and Note [CBV Function Ids]
+
+Note [Worker/wrapper for strict arguments]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+ f x = case x of
+ [] -> blah
+ (y:ys) -> f ys
+
+Clearly `f` is strict, but its argument is not a product type, so by default
+we don't worker/wrapper it. But it is arguably valuable to do so. We could
+do this:
+
+ f x = case x of xx { DEFAULT -> $wf xx }
+ $wf xx = case xx of
+ [] -> blah
+ (y:ys) -> f ys
+
+Now the worker `$wf` knows that its argument `xx` will be evaluated
+and properly tagged, so the code for the `case xx` does not need to do
+an "eval" (see `GHC.StgToCmm.Expr.cgCase`). A call (f (a:as)) will
+have the wrapper inlined, and will drop the `case x`, so no eval
+happens at all.
+
+The worker `$wf` is a CBV function (see `Note [CBV Function Ids]`
+in GHC.Types.Id.Info) and the code generator guarantees that every
+call to `$wf` has a properly tagged argument (see `GHC.Stg.InferTags.Rewrite`).
+
+Is this a win? Not always:
+* It can cause slight codesize increases. This is since we push evals to every
+ call sites which there might be many. And the evals will only disappear at
+ call sites where we already known that the argument is evaluated.
+
+* It will also cause many more functions to get a worker/wrapper split
+ which can play badly with rules (see Ticket #20364). In particular
+ if you depend on rules firing on functions marked as NOINLINE
+ without marking use sites of these functions as INLINE or INLINEABLE
+ then things will break.
+ But if you want a function to match in a RULE, it is /in any case/ good practice to
+ have a `INLINE[1]` or `NOINLNE[1]` pragma, to ensure that it doesn't inline until
+ the rule has had a chance to fire.
+
+So there is a flag, `-fworker-wrapper-cbv`, to control whether we do
+w/w on strict arguments (internally `Opt_WorkerWrapperUnlift`). The
+flag is off by default. The choice is made in
+GHC.Core.Opt.WorkWrape.Utils.wwForUnlifting
+
+See also `Note [WW for calling convention]` in GHC.Core.Opt.WorkWrap.Utils
-}
{-
diff --git a/compiler/GHC/Driver/Session.hs b/compiler/GHC/Driver/Session.hs
index 43f58884fc..83a61d6e4d 100644
--- a/compiler/GHC/Driver/Session.hs
+++ b/compiler/GHC/Driver/Session.hs
@@ -3469,7 +3469,7 @@ fFlagsDeps = [
flagSpec "unbox-strict-fields" Opt_UnboxStrictFields,
flagSpec "version-macros" Opt_VersionMacros,
flagSpec "worker-wrapper" Opt_WorkerWrapper,
- flagSpec "worker-wrapper-cbv" Opt_WorkerWrapperUnlift,
+ flagSpec "worker-wrapper-cbv" Opt_WorkerWrapperUnlift, -- See Note [Worker/wrapper for strict arguments]
flagSpec "solve-constant-dicts" Opt_SolveConstantDicts,
flagSpec "catch-nonexhaustive-cases" Opt_CatchNonexhaustiveCases,
flagSpec "alignment-sanitisation" Opt_AlignmentSanitisation,