[commit: ghc] master: Call Arity: In "e x", the result of "x" is not shared (a58eeb7)

git at git.haskell.org git at git.haskell.org
Fri Nov 6 14:38:39 UTC 2015


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/a58eeb7febd67c93dab82de7049ef1dcdecd34e9/ghc

>---------------------------------------------------------------

commit a58eeb7febd67c93dab82de7049ef1dcdecd34e9
Author: Joachim Breitner <mail at joachim-breitner.de>
Date:   Fri Nov 6 14:04:08 2015 +0100

    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.


>---------------------------------------------------------------

a58eeb7febd67c93dab82de7049ef1dcdecd34e9
 compiler/simplCore/CallArity.hs | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/compiler/simplCore/CallArity.hs b/compiler/simplCore/CallArity.hs
index c2a5ad0..bd997c3 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)



More information about the ghc-commits mailing list