[commit: ghc] cardinality: one-shot lambdas at RHS of non-rec let-bindings (00b55e3)

Ilya Sergey <[email protected]>
Newsgroups gmane.comp.lang.haskell.cvs.ghc
Message-ID <[email protected]>
Repository : ssh://darcs.haskell.org//srv/darcs/ghc

On branch  : cardinality

http://hackage.haskell.org/trac/ghc/changeset/00b55e3c2ac97dea83d7bc060b0a235f0ee625a6

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

commit 00b55e3c2ac97dea83d7bc060b0a235f0ee625a6
Author: Ilya Sergey <[email protected]>
Date:   Sat Sep 29 18:44:20 2012 +0200

    one-shot lambdas at RHS of non-rec let-bindings

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

 compiler/stranal/DmdAnal.lhs |   62 ++++++++++++++++++++++++++++++++++++++---
 1 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/compiler/stranal/DmdAnal.lhs b/compiler/stranal/DmdAnal.lhs
index 2f3f405..90536e7 100644
--- a/compiler/stranal/DmdAnal.lhs
+++ b/compiler/stranal/DmdAnal.lhs
@@ -280,6 +280,11 @@ dmdAnal _ env dmd (Let (NonRec id rhs) body)
         -- Add unleashed cardinality demands 
         unleashed_fv               = unleash_card_dmds (id2, id_dmd)
         body_ty3                   = addNewFVs body_ty2 unleashed_fv                      
+        
+        -- Annotate top-level lambdas at RHS basing on the aggregated demand info
+        -- See Note [Annotatig lambdas at right-hand side] 
+        usage_dmd                  = absd id_dmd
+        annotated_rhs              = annotate_rhs_lambdas usage_dmd rhs'    
     in
 	-- If the actual demand is better than the vanilla call
 	-- demand, you might think that we might do better to re-analyse 
@@ -293,7 +298,7 @@ dmdAnal _ env dmd (Let (NonRec id rhs) body)
 	-- In practice, all the times the actual demand on id2 is more than
 	-- the vanilla call demand seem to be due to (b).  So we don't
 	-- bother to re-analyse the RHS.
-    (body_ty3, Let (NonRec id2 rhs') body')                    
+    (body_ty3, Let (NonRec id2 annotated_rhs) body')                    
 
 dmdAnal _ env dmd (Let (Rec pairs) body)
   = let
@@ -313,6 +318,13 @@ dmdAnal _ env dmd (Let (Rec pairs) body)
 		-- But we do need to remove the binders from the result demand env
         unleashed_envs       = map unleash_card_dmds var_dmds       
         body_ty3             = foldl addNewFVs body_ty2 unleashed_envs
+
+        -- -- Annotate top-level lambdas at RHS basing on the aggregated demand info
+        -- -- See Note [Annotatig lambdas at right-hand side] 
+        -- (vars', bndrs')      = unzip pairs'
+        -- usage_dmds           = map (absd . snd) var_dmds
+        -- ann_bndrs            = zipWith annotate_rhs_lambdas usage_dmds bndrs'
+        -- ann_pairs            = zip vars' ann_bndrs 
     in
     (body_ty3,  Let (Rec pairs') body')
 
@@ -349,6 +361,27 @@ dmdAnalAlt env dmd (con,bndrs,rhs)
     in	
     (final_alt_ty, (con, bndrs', rhs'))
 
+annotate_rhs_lambdas :: AbsDmd -> CoreExpr -> CoreExpr
+annotate_rhs_lambdas dmd lam@(Lam var body)
+  | isTyVar var
+  = let 
+        body' = annotate_rhs_lambdas dmd body
+     in (Lam var body')  
+
+  | UCall Many dmd' <- dmd
+  = let 
+        body' = annotate_rhs_lambdas dmd' body
+     in (Lam var body')
+
+  | UCall One dmd' <- dmd
+  = let 
+        var'  = setOneShotLambda var
+        body' = annotate_rhs_lambdas dmd' body
+     in (Lam var' body')
+  | otherwise
+  = lam
+annotate_rhs_lambdas _ e = e
+
 \end{code}
 
 Note [Aggregated demand for cardinality]
@@ -422,6 +455,23 @@ lambda expression somewhere, e.g.
 build g = g (:) []
 build (\x y -> x () y) -- this lambda is one-shot
 
+Note [Annotatig lambdas at right-hand side]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Let us take a look at the following exmaple:
+
+g f = let x = 100
+          h = \y -> f x y
+       in h 5
+
+One can see that |h| is called just once, therefore the RHS of h can
+be annotated as a one-shot lambda. This is done by the function
+annotate_rhs_lambdas *a posteriori*, i.e., basing on the aggregated
+usage demand on |h| from the boye of |let|-expression (which is C1(U))
+in this case. 
+
+In other words, for locally-bound lambdas we can infer
+one-shotness. 
+
 
 Note [Analyzing with lazy demand and lambdas]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -740,20 +790,22 @@ is <L,A>).
 -- Recursive bindings are automaticaly marked as used
 unleash_card_dmds :: (Var, Demand) -> DmdEnv
 unleash_card_dmds (id, id_dmd)
-  | Abs <- absd id_dmd
+  | Abs <- usage_dmd
     -- do not unleash anything for absent demands
     = emptyDmdEnv
   | otherwise 
     = let StrictSig (DmdType fv _ _) = idStrictness id
           arity		             = idArity id
-          threshold_dmd              = mkThresholdDmd arity 
-          -- we are dealing only with usage, therefore 
+          threshold_dmd              = absd $ mkThresholdDmd arity 
+          -- we are dealing only with usage, therefore the
           -- stricntess component in 'fv' should be set to L
           lazified_fv                = deferEnv fv            
-          unleashed_fv               = if id_dmd `pre` threshold_dmd
+          unleashed_fv               = if usage_dmd `pre` threshold_dmd
                                        then lazified_fv
                                        else markAsUsedEnv lazified_fv
        in unleashed_fv
+  where
+    usage_dmd = absd id_dmd 
 
 annotateBndr :: DmdType -> Var -> (DmdType, (Var, Demand))
 -- The returned env has the var deleted
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.