summaryrefslogtreecommitdiff
path: root/compiler/GHC/Types/Demand.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Types/Demand.hs')
-rw-r--r--compiler/GHC/Types/Demand.hs49
1 files changed, 44 insertions, 5 deletions
diff --git a/compiler/GHC/Types/Demand.hs b/compiler/GHC/Types/Demand.hs
index c4e25a1a47..2dc89cb175 100644
--- a/compiler/GHC/Types/Demand.hs
+++ b/compiler/GHC/Types/Demand.hs
@@ -716,7 +716,7 @@ These two SubDemands:
are semantically equivalent, but we do not turn the former into
the latter, for a regrettable-subtle reason. Consider
f p1@(x,y) = (y,x)
- g h p2@(_,_) = h p
+ g h p2@(_,_) = h p2
We want to unbox @p1@ of @f@, but not @p2@ of @g@, because @g@ only uses
@p2@ boxed and we'd have to rebox. So we give @p1@ demand LP(L,L) and @p2@
demand @L@ to inform 'GHC.Core.Opt.WorkWrap.Utils.wantToUnboxArg', which will
@@ -729,7 +729,7 @@ little bit of boxity analysis. Not very nice.
Note [L should win]
~~~~~~~~~~~~~~~~~~~
Both in 'lubSubDmd' and 'plusSubDmd' we want @L `plusSubDmd` LP(..))@ to be @L@.
-Why? Because U carries the implication the whole thing is used, box and all,
+Why? Because L carries the implication the whole thing is used, box and all,
so we don't want to w/w it, cf. Note [Don't optimise LP(L,L,...) to L].
If we use it both boxed and unboxed, then we are definitely using the box,
and so we are quite likely to pay a reboxing cost. So we make U win here.
@@ -751,6 +751,31 @@ Compare with: (C) making L win for plus, but LP(..) win for lub
Max +0.1% +1.0% +21.0% +21.0% +0.5%
Geometric Mean +0.0% +0.0% -0.0% -0.1% -0.1%
+Note [Turn LP(A) into LP(M) in signatures]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider T19407:
+
+ data Huge = Huge Bool () ... () -- think: DynFlags
+ data T = T { h :: Huge, n :: Int }
+ f t@(T h _) = g h t
+ g (H b _ ... _) t = if b then 1 else n t
+
+The body of `g` puts (approx.) demand `LP(A,1)` on `t`. But we better not put
+that demand in `g`'s signature! If we do, then `f` puts demand
+`SP(1P(1L,A,..),ML)` on `t` and we get
+
+ f (T (H b _ ... _) n) = $wf b n
+ $wf b n = $wg b (T (H b x ... x) n)
+ $wg = ...
+
+Massive reboxing in `$wf`! Solution: The signature of `g` should better say
+`LP(M,1)`, then `f`'s signature says `SP(1P(1L,M,..),ML)` and `h` will not be
+reboxed because passing all fields of `h` to `$wf` would run beyond the arg
+limit in W/W. Which in turn means that `f` will not be W/W'd *at all*!
+So this solution is quite unsatisfying as then `f`'s signature lies, probably
+incurring reboxing at its call sites... I can think of no fix other than a =
+proper boxity analysis.
+
Note [Computing one-shot info]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider a call
@@ -1436,11 +1461,25 @@ newtype DmdSig
deriving Eq
-- | Turns a 'DmdType' computed for the particular 'Arity' into a 'DmdSig'
--- unleashable at that arity. See Note [Understanding DmdType and DmdSig]
+-- unleashable at that arity. See Note [Understanding DmdType and DmdSig].
mkDmdSigForArity :: Arity -> DmdType -> DmdSig
mkDmdSigForArity arity dmd_ty@(DmdType fvs args div)
- | arity < dmdTypeDepth dmd_ty = DmdSig (DmdType fvs (take arity args) div)
- | otherwise = DmdSig (etaExpandDmdType arity dmd_ty)
+ | arity < dmdTypeDepth dmd_ty = DmdSig dmd_ty'
+ | otherwise = DmdSig (etaExpandDmdType arity dmd_ty')
+ where
+ -- See Note [Turn LP(A) into LP(M) in signatures]
+ args' = map forgetAbsentInLazyProd args
+ !dmd_ty' = DmdType fvs (take arity args') div
+
+forgetAbsentInLazyProd :: Demand -> Demand
+forgetAbsentInLazyProd (n :* Prod ds)
+ | isStrict n = n :* Prod (map forgetAbsentInLazyProd ds)
+ | otherwise = n :* Prod (map abs_to_once ds)
+ where
+ abs_to_once d@(n :* _)
+ | isAbs n = polyDmd C_01
+ | otherwise = d
+forgetAbsentInLazyProd d = d
mkClosedDmdSig :: [Demand] -> Divergence -> DmdSig
mkClosedDmdSig ds res = mkDmdSigForArity (length ds) (DmdType emptyDmdEnv ds res)