Merge branch 'cλash' of http://git.stderr.nl/matthijs/projects/master-project
[matthijs/master-project/cλash.git] / cλash / CLasH / Normalize.hs
index 18010cf56e0cfeebfd0da111e4e53f66c400edcc..85760bebd7e63026fc8f7ff815615c0123252a91 100644 (file)
@@ -115,6 +115,36 @@ castsimpl expr = return expr
 -- Perform this transform everywhere
 castsimpltop = everywhere ("castsimpl", castsimpl)
 
+
+--------------------------------
+-- Lambda simplication
+--------------------------------
+-- Ensure that a lambda always evaluates to a let expressions or a simple
+-- variable reference.
+lambdasimpl, lambdasimpltop :: Transform
+-- Don't simplify a lambda that evaluates to let, since this is already
+-- normal form (and would cause infinite loops).
+lambdasimpl expr@(Lam _ (Let _ _)) = return expr
+-- Put the of a lambda in its own binding, but not when the expression is
+-- already a local variable, or not representable (to prevent loops with
+-- inlinenonrep).
+lambdasimpl expr@(Lam bndr res) = do
+  repr <- isRepr res
+  local_var <- Trans.lift $ is_local_var res
+  if not local_var && repr
+    then do
+      id <- Trans.lift $ mkBinderFor res "res"
+      change $ Lam bndr (Let (NonRec id res) (Var id))
+    else
+      -- If the result is already a local var or not representable, don't
+      -- extract it.
+      return expr
+
+-- Leave all other expressions unchanged
+lambdasimpl expr = return expr
+-- Perform this transform everywhere
+lambdasimpltop = everywhere ("lambdasimpl", lambdasimpl)
+
 --------------------------------
 -- let derecursification
 --------------------------------
@@ -123,15 +153,12 @@ letderec expr@(Let (Rec binds) res) = case liftable of
   -- Nothing is liftable, just return
   [] -> return expr
   -- Something can be lifted, generate a new let expression
-  _ -> change $ MkCore.mkCoreLets newbinds res
+  _ -> change $ mkNonRecLets liftable (Let (Rec nonliftable) res)
   where
     -- Make a list of all the binders bound in this recursive let
     bndrs = map fst binds
     -- See which bindings are liftable
     (liftable, nonliftable) = List.partition canlift binds
-    -- Create nonrec bindings for each liftable binding and a single recursive
-    -- binding for all others
-    newbinds = (map (uncurry NonRec) liftable) ++ [Rec nonliftable]
     -- Any expression that does not use any of the binders in this recursive let
     -- can be lifted into a nonrec let. It can't use its own binder either,
     -- since that would mean the binding is self-recursive and should be in a
@@ -185,6 +212,17 @@ letflat expr = return expr
 -- Perform this transform everywhere
 letflattop = everywhere ("letflat", letflat)
 
+--------------------------------
+-- empty let removal
+--------------------------------
+-- Remove empty (recursive) lets
+letremove, letremovetop :: Transform
+letremove (Let (Rec []) res) = change $ res
+-- Leave all other expressions unchanged
+letremove expr = return expr
+-- Perform this transform everywhere
+letremovetop = everywhere ("letremove", letremove)
+
 --------------------------------
 -- Simple let binding removal
 --------------------------------
@@ -196,12 +234,13 @@ letremovesimpletop = everywhere ("letremovesimple", inlinebind (\(b, e) -> Trans
 -- Unused let binding removal
 --------------------------------
 letremoveunused, letremoveunusedtop :: Transform
-letremoveunused expr@(Let (Rec binds) res) = do
+letremoveunused expr@(Let _ _) = do
   -- Filter out all unused binds.
   let binds' = filter dobind binds
   -- Only set the changed flag if binds got removed
-  changeif (length binds' /= length binds) (Let (Rec binds') res)
+  changeif (length binds' /= length binds) (mkNonRecLets binds' res)
     where
+      (binds, res) = flattenLets expr
       bound_exprs = map snd binds
       -- For each bind check if the bind is used by res or any of the bound
       -- expressions
@@ -217,9 +256,10 @@ letremoveunusedtop = everywhere ("letremoveunused", letremoveunused)
 -- TODO: We would very much like to use GHC's CSE module for this, but that
 -- doesn't track if something changed or not, so we can't use it properly.
 letmerge, letmergetop :: Transform
-letmerge expr@(Let (Rec binds) res) = do
+letmerge expr@(Let _ _) = do
+  let (binds, res) = flattenLets expr
   binds' <- domerge binds
-  return (Let (Rec binds') res)
+  return $ mkNonRecLets binds' res
   where
     domerge :: [(CoreBndr, CoreExpr)] -> TransformMonad [(CoreBndr, CoreExpr)]
     domerge [] = return []
@@ -299,7 +339,7 @@ casesimpl expr@(Case scrut b ty alts) = do
   (bindingss, alts') <- (Monad.liftM unzip) $ mapM doalt alts
   let bindings = concat bindingss
   -- Replace the case with a let with bindings and a case
-  let newlet = (Let (Rec bindings) (Case scrut b ty alts'))
+  let newlet = mkNonRecLets bindings (Case scrut b ty alts')
   -- If there are no non-wild binders, or this case is already a simple
   -- selector (i.e., a single alt with exactly one binding), already a simple
   -- selector altan no bindings (i.e., no wild binders in the original case),
@@ -556,7 +596,7 @@ funextracttop = everywhere ("funextract", funextract)
 
 
 -- What transforms to run?
-transforms = [argproptop, funextracttop, etatop, betatop, castproptop, letremovesimpletop, letderectop, letsimpltop, letflattop, scrutsimpltop, casesimpltop, caseremovetop, inlinenonreptop, appsimpltop, letmergetop, letremoveunusedtop, castsimpltop]
+transforms = [argproptop, funextracttop, etatop, betatop, castproptop, letremovesimpletop, letderectop, letremovetop, letsimpltop, letflattop, scrutsimpltop, casesimpltop, caseremovetop, inlinenonreptop, appsimpltop, letmergetop, letremoveunusedtop, castsimpltop, lambdasimpltop]
 
 -- | Returns the normalized version of the given function.
 getNormalized ::
@@ -609,18 +649,3 @@ splitNormalized expr = (args, binds, res)
     res = case resexpr of 
       (Var x) -> x
       _ -> error $ "Normalize.splitNormalized: Not in normal form: " ++ pprString expr ++ "\n"
-
--- | Flattens nested lets into a single list of bindings. The expression
---   passed does not have to be a let expression, if it isn't an empty list of
---   bindings is returned.
-flattenLets ::
-  CoreExpr -- ^ The expression to flatten.
-  -> ([Binding], CoreExpr) -- ^ The bindings and resulting expression.
-flattenLets (Let binds expr) = 
-  (bindings ++ bindings', expr')
-  where
-    -- Recursively flatten the contained expression
-    (bindings', expr') =flattenLets expr
-    -- Flatten our own bindings to remove the Rec / NonRec constructors
-    bindings = CoreSyn.flattenBinds [binds]
-flattenLets expr = ([], expr)