summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoachim Breitner <mail@joachim-breitner.de>2015-11-06 14:04:08 +0100
committerBen Gamari <ben@smart-cactus.org>2015-11-08 13:13:05 +0100
commit1b1fab88483c4863ebb6944a3ffe10abdcf109a5 (patch)
treeb87b92d5e3b97335d384d146f72233a290db7ae9
parent7f8fc1c9db5bef2dea05e001488d5bc7c8b38575 (diff)
downloadhaskell-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.hs23
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)