summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core/Opt/DmdAnal.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Core/Opt/DmdAnal.hs')
-rw-r--r--compiler/GHC/Core/Opt/DmdAnal.hs69
1 files changed, 44 insertions, 25 deletions
diff --git a/compiler/GHC/Core/Opt/DmdAnal.hs b/compiler/GHC/Core/Opt/DmdAnal.hs
index c3fd09c6e0..966535897a 100644
--- a/compiler/GHC/Core/Opt/DmdAnal.hs
+++ b/compiler/GHC/Core/Opt/DmdAnal.hs
@@ -956,16 +956,15 @@ dmdAnalRhsSig top_lvl rec_flag env let_dmd id rhs
= -- pprTrace "dmdAnalRhsSig" (ppr id $$ ppr let_dmd $$ ppr rhs_dmds $$ ppr sig $$ ppr lazy_fv) $
(final_env, lazy_fv, final_id, final_rhs)
where
- rhs_arity = idArity id
- -- See Note [Demand signatures are computed for a threshold demand based on idArity]
+ threshold_arity = thresholdArity id rhs
- rhs_dmd = mkCalledOnceDmds rhs_arity body_dmd
+ rhs_dmd = mkCalledOnceDmds threshold_arity body_dmd
body_dmd
| isJoinId id
-- See Note [Demand analysis for join points]
-- See Note [Invariants on join points] invariant 2b, in GHC.Core
- -- rhs_arity matches the join arity of the join point
+ -- threshold_arity matches the join arity of the join point
-- See Note [Unboxed demand on function bodies returning small products]
= unboxedWhenSmall env rec_flag (resultType_maybe id) let_dmd
| otherwise
@@ -975,10 +974,10 @@ dmdAnalRhsSig top_lvl rec_flag env let_dmd id rhs
WithDmdType rhs_dmd_ty rhs' = dmdAnal env rhs_dmd rhs
DmdType rhs_fv rhs_dmds rhs_div = rhs_dmd_ty
-- See Note [Boxity for bottoming functions]
- (final_rhs_dmds, final_rhs) = finaliseArgBoxities env id rhs_arity rhs' rhs_div
+ (final_rhs_dmds, final_rhs) = finaliseArgBoxities env id threshold_arity rhs' rhs_div
`orElse` (rhs_dmds, rhs')
- sig = mkDmdSigForArity rhs_arity (DmdType sig_fv final_rhs_dmds rhs_div)
+ sig = mkDmdSigForArity threshold_arity (DmdType sig_fv final_rhs_dmds rhs_div)
final_id = id `setIdDmdSig` sig
!final_env = extendAnalEnv top_lvl env final_id sig
@@ -1005,6 +1004,13 @@ dmdAnalRhsSig top_lvl rec_flag env let_dmd id rhs
-- See Note [Lazy and unleashable free variables]
!(!lazy_fv, !sig_fv) = partitionVarEnv isWeakDmd rhs_fv2
+thresholdArity :: Id -> CoreExpr -> Arity
+-- See Note [Demand signatures are computed for a threshold arity based on idArity]
+thresholdArity fn rhs
+ = case isJoinId_maybe fn of
+ Just join_arity -> count isId $ fst $ collectNBinders join_arity rhs
+ Nothing -> idArity fn
+
-- | The result type after applying 'idArity' many arguments. Returns 'Nothing'
-- when the type doesn't have exactly 'idArity' many arrows.
resultType_maybe :: Id -> Maybe Type
@@ -1137,28 +1143,40 @@ meaning one absent argument, returns bottom. That seems odd because
there's a \y inside. But it's right because when consumed in a C1(L)
context the RHS of the join point is indeed bottom.
-Note [Demand signatures are computed for a threshold demand based on idArity]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We compute demand signatures assuming idArity incoming arguments to approximate
-behavior for when we have a call site with at least that many arguments. idArity
-is /at least/ the number of manifest lambdas, but might be higher for PAPs and
-trivial RHS (see Note [Demand analysis for trivial right-hand sides]).
+Note [Demand signatures are computed for a threshold arity based on idArity]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Given a binding { f = rhs }, we compute a "theshold arity", and do demand
+analysis based on a call with that many value arguments.
-Because idArity of a function varies independently of its cardinality
-properties (cf. Note [idArity varies independently of dmdTypeDepth]), we
-implicitly encode the arity for when a demand signature is sound to unleash
-in its 'dmdTypeDepth' (cf. Note [Understanding DmdType and DmdSig] in
-GHC.Types.Demand). It is unsound to unleash a demand signature when the
-incoming number of arguments is less than that.
-See Note [What are demand signatures?] in GHC.Types.Demand for more details
-on soundness.
+The threshold we use is
-Why idArity arguments? Because that's a conservative estimate of how many
-arguments we must feed a function before it does anything interesting with them.
-Also it elegantly subsumes the trivial RHS and PAP case.
+* Ordinary bindings: idArity f.
+ Why idArity arguments? Because that's a conservative estimate of how many
+ arguments we must feed a function before it does anything interesting with
+ them. Also it elegantly subsumes the trivial RHS and PAP case.
-There might be functions for which we might want to analyse for more incoming
-arguments than idArity. Example:
+ idArity is /at least/ the number of manifest lambdas, but might be higher for
+ PAPs and trivial RHS (see Note [Demand analysis for trivial right-hand sides]).
+
+* Join points: the value-binder subset of the JoinArity. This can
+ be less than the number of visible lambdas; e.g.
+ join j x = \y. blah
+ in ...(jump j 2)....(jump j 3)....
+ We know that j will never be applied to more than 1 arg (its join
+ arity, and we don't eta-expand join points, so here a threshold
+ of 1 is the best we can do.
+
+Note that the idArity of a function varies independently of its cardinality
+properties (cf. Note [idArity varies independently of dmdTypeDepth]), so we
+implicitly encode the arity for when a demand signature is sound to unleash
+in its 'dmdTypeDepth', not in its idArity (cf. Note [Understanding DmdType
+and DmdSig] in GHC.Types.Demand). It is unsound to unleash a demand
+signature when the incoming number of arguments is less than that. See
+GHC.Types.Demand Note [What are demand signatures?] for more details on
+soundness.
+
+Note that there might, in principle, be functions for which we might want to
+analyse for more incoming arguments than idArity. Example:
f x =
if expensive
@@ -1175,6 +1193,7 @@ strictness info for `y` (and more precise info on `x`) and possibly CPR
information, but
* We would no longer be able to unleash the signature at unary call sites
+
* Performing the worker/wrapper split based on this information would be
implicitly eta-expanding `f`, playing fast and loose with divergence and
even being unsound in the presence of newtypes, so we refrain from doing so.