diff options
author | Joachim Breitner <mail@joachim-breitner.de> | 2015-11-06 14:04:08 +0100 |
---|---|---|
committer | Joachim Breitner <mail@joachim-breitner.de> | 2015-11-06 15:31:55 +0100 |
commit | a58eeb7febd67c93dab82de7049ef1dcdecd34e9 (patch) | |
tree | bf4a585b5b603436ec16ed242ecb20b13ef9d561 | |
parent | 10647d4e2e8e3b5eb5486bd6aafbe17cda139577 (diff) | |
download | haskell-a58eeb7febd67c93dab82de7049ef1dcdecd34e9.tar.gz |
Call Arity: In "e x", the result of "x" is not shared
in contrast to "e (f x)", where CorePrep will turn it into "let y = f x
in e x". So in
let f = ...
in e (f x)
we know that f is called at most once, but in
let f = ...
in e f
we do not know that.
Previously Call Arity would assume that in "e x", "x" is evaluated at
most once. This rarely would make a difference (the argument "x" is
analized with an incoming arity of 0, so no eta-expansion would be done
anyways), but of course this should still be fixed.
This fixes #11064.
Note the corresponding code dmdTransformThunkDmd in DmdAnal.
-rw-r--r-- | compiler/simplCore/CallArity.hs | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/compiler/simplCore/CallArity.hs b/compiler/simplCore/CallArity.hs index c2a5ad0cae..bd997c3676 100644 --- a/compiler/simplCore/CallArity.hs +++ b/compiler/simplCore/CallArity.hs @@ -15,7 +15,7 @@ import BasicTypes import CoreSyn import Id import CoreArity ( typeArity ) -import CoreUtils ( exprIsHNF ) +import CoreUtils ( exprIsHNF, exprIsTrivial ) --import Outputable import UnVarGraph import Demand @@ -149,10 +149,15 @@ The interesting cases of the analysis: * Case alternatives alt₁,alt₂,...: Only one can be execuded, so Return (alt₁ ∪ alt₂ ∪...) - * App e₁ e₂ (and analogously Case scrut alts): - We get the results from both sides. Additionally, anything called by e₁ can - possibly be called with anything from e₂. + * App e₁ e₂ (and analogously Case scrut alts), with non-trivial e₂: + We get the results from both sides, with the argument evaluted at most once. + Additionally, anything called by e₁ can possibly be called with anything + from e₂. Return: C(e₁) ∪ C(e₂) ∪ (fv e₁) × (fv e₂) + * App e₁ x: + As this is already in A-normal form, CorePrep will not separately lambda + bind (and hence share) x. So we conservatively assume multiple calls to x here + Return: C(e₁) ∪ (fv e₁) × {x} ∪ {(x,x)} * Let v = rhs in body: In addition to the results from the subexpressions, add all co-calls from everything that the body calls together with v to everthing that is called @@ -472,7 +477,12 @@ callArityAnal arity int (App e1 e2) where (ae1, e1') = callArityAnal (arity + 1) int e1 (ae2, e2') = callArityAnal 0 int e2 - final_ae = ae1 `both` ae2 + -- If the argument is trivial (e.g. a variable), then it will _not_ be + -- let-bound in the Core to STG transformation (CorePrep actually), + -- so no sharing will happen here, and we have to assume many calls. + ae2' | exprIsTrivial e2 = calledMultipleTimes ae2 + | otherwise = ae2 + final_ae = ae1 `both` ae2' -- Case expression. callArityAnal arity int (Case scrut bndr ty alts) |