diff options
author | Sebastian Graf <sebastian.graf@kit.edu> | 2020-10-30 17:20:37 +0100 |
---|---|---|
committer | Sebastian Graf <sebastian.graf@kit.edu> | 2020-11-20 09:48:01 +0100 |
commit | c90df9e3b0d7551e2de1e1571ad358e91f625ccc (patch) | |
tree | 17387b83d903a5495eaa5d55431e6b807e079326 /compiler/GHC/Core/Opt | |
parent | 802e9180dd9a9a88c4e8869f0de1048e1edd6343 (diff) | |
download | haskell-wip/T18885.tar.gz |
Demand: Nested strict product demands (#18885)wip/T18885
Fixing #18903 gives us enough expressiveness to tackle #18885, where we
have
```hs
f :: Int -> Int
f y =
let x
| expensive y == 1 = (expensive (y+1), expensive (y+2))
| otherwise = (expensive (y+3), expensive (y+4))
in case () of
_ | expensive (y+5) == 42 -> fst x
_ | expensive (y+6) == 41 -> fst x + snd x
_ | otherwise -> 0
```
Here, we used to give `x` demand `1P(1P(U),1P(U))`. The outer `1`
is because `x` is used lazily and the inner `1`s are redundant with
that fact. That leaves some expressiveness on the table. After this
change, we infer `1P(SP(U),1P(U))`, meaning that *whenever we evaluate
`x`*, we evaluate its first component strictly, effectively making
strictness product demands apply *relatively*. Usage product demands
still apply absolutely, though.
More details on how we could exploit the new language in
`Note [Absent sub-demands]`.
Fixes #18885.
There's a single remaining regression in `T9630`, which increases +16%
in residency but decreases slightly in total allocations. I checked
the heap profile, which doesn't suggest any obvious regressions.
Ticky doesn't point to the reason either, because total allocations
actually improved. I think it's OK to just accept it.
Metric Increase:
T9630
Diffstat (limited to 'compiler/GHC/Core/Opt')
-rw-r--r-- | compiler/GHC/Core/Opt/DmdAnal.hs | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/compiler/GHC/Core/Opt/DmdAnal.hs b/compiler/GHC/Core/Opt/DmdAnal.hs index 4869fb1fa9..ae8aab18a8 100644 --- a/compiler/GHC/Core/Opt/DmdAnal.hs +++ b/compiler/GHC/Core/Opt/DmdAnal.hs @@ -233,9 +233,10 @@ dmdAnal' env dmd (Case scrut case_bndr ty [(alt, bndrs, rhs)]) (rhs_ty, rhs') = dmdAnal env dmd rhs (alt_ty1, dmds) = findBndrsDmds env rhs_ty bndrs (alt_ty2, case_bndr_dmd) = findBndrDmd env False alt_ty1 case_bndr - -- Evaluation cardinality on the case binder is irrelevant and a no-op. - -- What matters is its nested sub-demand! - (_ :* case_bndr_sd) = case_bndr_dmd + -- The peelDmd below will lazify the relative sub-demands if the + -- case_bndr_dmd had lazy evaluation cardinality. + -- See Note [Absent sub-demand] in GHC.Types.Demand + case_bndr_sd = peelDmd case_bndr_dmd -- Compute demand on the scrutinee (bndrs', scrut_sd) | DataAlt _ <- alt @@ -388,9 +389,10 @@ dmdAnalSumAlt :: AnalEnv -> SubDemand -> Id -> Alt Var -> (DmdType, Alt Var) dmdAnalSumAlt env dmd case_bndr (con,bndrs,rhs) | (rhs_ty, rhs') <- dmdAnal env dmd rhs , (alt_ty, dmds) <- findBndrsDmds env rhs_ty bndrs - , let (_ :* case_bndr_sd) = findIdDemand alt_ty case_bndr + , let case_bndr_dmd = findIdDemand alt_ty case_bndr -- See Note [Demand on scrutinee of a product case] - id_dmds = addCaseBndrDmd case_bndr_sd dmds + -- See Note [Absent sub-demand] in GHC.Types.Demand + id_dmds = addCaseBndrDmd (peelDmd case_bndr_dmd) dmds = (alt_ty, (con, setBndrsDemandInfo bndrs id_dmds, rhs')) {- |