diff options
author | Andreas Klebinger <klebinger.andreas@gmx.at> | 2022-06-16 11:51:20 +0200 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-08-04 13:57:25 -0400 |
commit | fb529caedbe45160b41a20f28e21ee0ec372b05a (patch) | |
tree | 84c22904206710404ad181b4a978a7faa1a0c67e | |
parent | b99819bdaa11881f0b0bec29ef6274a8c8e565a0 (diff) | |
download | haskell-fb529caedbe45160b41a20f28e21ee0ec372b05a.tar.gz |
Add a note about about W/W for unlifting strict arguments
This fixes #21236.
-rw-r--r-- | compiler/GHC/Core/Opt/WorkWrap/Utils.hs | 47 | ||||
-rw-r--r-- | compiler/GHC/Driver/Session.hs | 2 |
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 0c6aa2def5..ea903b5664 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, |