diff options
author | Joachim Breitner <mail@joachim-breitner.de> | 2015-11-06 14:04:08 +0100 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2015-11-08 13:13:05 +0100 |
commit | 1b1fab88483c4863ebb6944a3ffe10abdcf109a5 (patch) | |
tree | b87b92d5e3b97335d384d146f72233a290db7ae9 | |
parent | 7f8fc1c9db5bef2dea05e001488d5bc7c8b38575 (diff) | |
download | haskell-1b1fab88483c4863ebb6944a3ffe10abdcf109a5.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 | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/compiler/simplCore/CallArity.hs b/compiler/simplCore/CallArity.hs index c606ece9ea..1601dad3e6 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 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 @@ -355,7 +360,7 @@ t1) in the follwing code: t2 = if ... then go 1 else ... in go 0 -Detecting this would reqiure finding out what variables are only ever called +Detecting this would require finding out what variables are only ever called from thunks. While this is certainly possible, we yet have to see this to be relevant in the wild. @@ -472,8 +477,12 @@ callArityAnal arity int (App e1 e2) where (ae1, e1') = callArityAnal (arity + 1) int e1 (ae2, e2') = callArityAnal 0 int e2 - -- See Note [Case and App: Which side to take?] - 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) |