Also simplify expressions of the DEFAULT alternative of case expressions
[matthijs/master-project/cλash.git] / clash / CLasH / Normalize.hs
index 11212f943df0678a4b9cef09fb52657ba06bc2dd..89f21c00ef0ecf83661a8a6248b5ae6b758d69d4 100644 (file)
@@ -158,7 +158,7 @@ castsimpl c expr = return expr
 -- By not inlining any other reference, we also prevent looping problems
 -- with funextract and inlinedict.
 inlinetoplevel :: Transform
-inlinetoplevel (LetBinding:_) expr | not (is_fun expr) =
+inlinetoplevel c expr | not (null c) && is_letbinding_ctx (head c) && not (is_fun expr) =
   case collectArgs expr of
        (Var f, args) -> do
          body_maybe <- needsInline f
@@ -216,12 +216,12 @@ needsInline f = do
 -- body consisting of a bunch of nested lambdas containing a
 -- non-function value (e.g., a complete application).
 eta :: Transform
-eta (AppFirst:_) expr = return expr
+eta c expr | not (null c) && is_appfirst_ctx (head c) = return expr
 -- Also don't apply to arguments, since this can cause loops with
 -- funextract. This isn't the proper solution, but due to an
 -- implementation bug in notappargs, this is how it used to work so far.
-eta (AppSecond:_) expr = return expr
-eta c expr | is_fun expr && not (is_lam expr) = do
+           | not (null c) && is_appsecond_ctx (head c) = return expr
+           | is_fun expr && not (is_lam expr) = do
  let arg_ty = (fst . Type.splitFunTy . CoreUtils.exprType) expr
  id <- Trans.lift $ mkInternalVar "param" arg_ty
  change (Lam id (App expr (Var id)))
@@ -296,7 +296,7 @@ letflat c expr = return expr
 -- Extract the return value from the body of the top level lambdas (of
 -- which ther could be zero), unless it is a let expression (in which
 -- case the next clause applies).
-retvalsimpl c expr | all (== LambdaBody) c && not (is_lam expr) && not (is_let expr) = do
+retvalsimpl c expr | all is_lambdabody_ctx c && not (is_lam expr) && not (is_let expr) = do
   local_var <- Trans.lift $ is_local_var expr
   repr <- isRepr expr
   if not local_var && repr
@@ -308,7 +308,7 @@ retvalsimpl c expr | all (== LambdaBody) c && not (is_lam expr) && not (is_let e
 -- Extract the return value from the body of a let expression, which is
 -- itself the body of the top level lambdas (of which there could be
 -- zero).
-retvalsimpl c expr@(Let (Rec binds) body) | all (== LambdaBody) c = do
+retvalsimpl c expr@(Let (Rec binds) body) | all is_lambdabody_ctx c = do
   -- Don't extract values that are already a local variable, to prevent
   -- loops with ourselves.
   local_var <- Trans.lift $ is_local_var body
@@ -489,7 +489,23 @@ casesimpl c expr@(Case scrut bndr ty alts) | not bndr_used = do
   -- Wilden the binders of one alt, producing a list of bindings as a
   -- sideeffect.
   doalt :: CoreAlt -> TransformMonad ([(CoreBndr, CoreExpr)], CoreAlt)
-  doalt (con, bndrs, expr) = do
+  doalt (LitAlt _, _, _) = error $ "Don't know how to handle LitAlt in case expression: " ++ pprString expr
+  doalt alt@(DEFAULT, [], expr) = do
+    local_var <- Trans.lift $ is_local_var expr
+    repr <- isRepr expr
+    (exprbinding_maybe, expr') <- if (not local_var) && repr
+      then do
+        id <- Trans.lift $ mkBinderFor expr "caseval"
+        -- We don't flag a change here, since casevalsimpl will do that above
+        -- based on Just we return here.
+        return (Just (id, expr), Var id)
+      else
+        -- Don't simplify anything else
+        return (Nothing, expr)
+    let newalt = (DEFAULT, [], expr')
+    let bindings = Maybe.catMaybes [exprbinding_maybe]
+    return (bindings, newalt)
+  doalt (DataAlt dc, bndrs, expr) = do
     -- Make each binder wild, if possible
     bndrs_res <- Monad.zipWithM dobndr bndrs [0..]
     let (newbndrs, bindings_maybe) = unzip bndrs_res
@@ -499,7 +515,7 @@ casesimpl c expr@(Case scrut bndr ty alts) | not bndr_used = do
     let uses_bndrs = not $ VarSet.isEmptyVarSet $ CoreFVs.exprSomeFreeVars (`elem` newbndrs) expr
     (exprbinding_maybe, expr') <- doexpr expr uses_bndrs
     -- Create a new alternative
-    let newalt = (con, newbndrs, expr')
+    let newalt = (DataAlt dc, newbndrs, expr')
     let bindings = Maybe.catMaybes (bindings_maybe ++ [exprbinding_maybe])
     return (bindings, newalt)
     where
@@ -521,7 +537,8 @@ casesimpl c expr@(Case scrut bndr ty alts) | not bndr_used = do
         -- inlinenonrep).
         if (not wild) && repr
           then do
-            caseexpr <- Trans.lift $ mkSelCase scrut i
+            let dc_i = datacon_index (CoreUtils.exprType scrut) dc
+            caseexpr <- Trans.lift $ mkSelCase scrut dc_i i
             -- Create a new binder that will actually capture a value in this
             -- case statement, and return it.
             return (wildbndrs!!i, Just (b, caseexpr))
@@ -793,7 +810,7 @@ inlinenonrepresult context expr | not (is_applicable expr) && not (has_free_tyva
                   res_bndr <- Trans.lift $ mkBinderFor newapp "res"
                   -- Create extractor case expressions to extract each of the
                   -- free variables from the tuple.
-                  sel_cases <- Trans.lift $ mapM (mkSelCase (Var res_bndr)) [0..n_free_vars-1]
+                  sel_cases <- Trans.lift $ mapM (mkSelCase (Var res_bndr) 0) [0..n_free_vars-1]
 
                   -- Bind the res_bndr to the result of the new application
                   -- and each of the free variables to the corresponding