Float casts out of lambdas
authorsimonpj@microsoft.com <unknown>
Mon, 5 Feb 2007 17:35:44 +0000 (17:35 +0000)
committersimonpj@microsoft.com <unknown>
Mon, 5 Feb 2007 17:35:44 +0000 (17:35 +0000)
See Note [Casts and lambdas] in SimplUtils.  I found this transformation
when staring at some cast-heavy code generated by
Language.Haskell.Lexer.hs in the haskell-src library.

The basic transformation is this:
(\x. e `cast` g1)  -->  (\x.e) `cast` (tx -> g1)
where x:tx.

compiler/simplCore/SimplUtils.lhs

index 6ab117f..acd0830 100644 (file)
@@ -804,6 +804,14 @@ mkLam bndrs body
   = do { dflags <- getDOptsSmpl
        ; mkLam' dflags bndrs body }
   where
+    mkLam' :: DynFlags -> [OutBndr] -> OutExpr -> SimplM OutExpr
+    mkLam' dflags bndrs (Cast body@(Lam _ _) co)
+       -- Note [Casts and lambdas]
+      = do { lam <- mkLam' dflags (bndrs ++ bndrs') body'
+          ; return (mkCoerce (mkPiTypes bndrs co) lam) }
+      where    
+       (bndrs',body') = collectBinders body
+
     mkLam' dflags bndrs body
       | dopt Opt_DoEtaReduction dflags,
         Just etad_lam <- tryEtaReduce bndrs body
@@ -819,6 +827,21 @@ mkLam bndrs body
       = returnSmpl (mkLams bndrs body)
 \end{code}
 
+Note [Casts and lambdas]
+~~~~~~~~~~~~~~~~~~~~~~~~
+Consider 
+       (\x. (\y. e) `cast` g1) `cast` g2
+There is a danger here that the two lambdas look separated, and the 
+full laziness pass might float an expression to between the two.
+
+So this equation in mkLam' floats the g1 out, thus:
+       (\x. e `cast` g1)  -->  (\x.e) `cast` (tx -> g1)
+where x:tx.
+
+In general, this floats casts outside lambdas, where (I hope) they might meet
+and cancel with some other cast.
+
+
 --     c) floating lets out through big lambdas 
 --             [only if all tyvar lambdas, and only if this lambda
 --              is the RHS of a let]