[project @ 2000-10-25 13:51:50 by simonpj]
[ghc-hetmet.git] / ghc / compiler / simplCore / FloatOut.lhs
index 9ab7221..2d593e0 100644 (file)
@@ -1,43 +1,45 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
 \section[FloatOut]{Float bindings outwards (towards the top level)}
 
 ``Long-distance'' floating of bindings towards the top level.
 
 \begin{code}
-#include "HsVersions.h"
-
 module FloatOut ( floatOutwards ) where
 
-IMPORT_Trace           -- ToDo: rm (debugging)
-import Pretty
-import Outputable
+#include "HsVersions.h"
 
-import PlainCore
+import CoreSyn
+import CoreUtils       ( mkSCC )
 
-import BasicLit                ( BasicLit(..), PrimKind )
-import CmdLineOpts     ( GlobalSwitch(..) )
+import CmdLineOpts     ( DynFlags, DynFlag(..), dopt )
+import ErrUtils                ( dumpIfSet_dyn )
 import CostCentre      ( dupifyCC, CostCentre )
-import SetLevels
-import Id              ( eqId )
-import IdEnv
-import Maybes          ( Maybe(..), catMaybes, maybeToBool )
-import SplitUniq
-import Util
+import Id              ( Id )
+import VarEnv
+import CoreLint                ( beginPass, endPass )
+import SetLevels       ( setLevels,
+                         Level(..), tOP_LEVEL, ltMajLvl, ltLvl, isTopLvl
+                       )
+import UniqSupply       ( UniqSupply )
+import List            ( partition )
+import Outputable
 \end{code}
 
 Random comments
 ~~~~~~~~~~~~~~~
-At the moment we never float a binding out to between two adjacent lambdas.  For
-example:
+
+At the moment we never float a binding out to between two adjacent
+lambdas.  For example:
+
 @
        \x y -> let t = x+x in ...
 ===>
        \x -> let t = x+x in \y -> ...
 @
-Reason: this is less efficient in the case where the original lambda is
-never partially applied.
+Reason: this is less efficient in the case where the original lambda
+is never partially applied.
 
 But there's a case I've seen where this might not be true.  Consider:
 @
@@ -51,25 +53,17 @@ It turns out that this generates a subexpression of the form
 @
        \deq x ys -> let eq = eqFromEqDict deq in ...
 @
-which might usefully be separated to
+vwhich might usefully be separated to
 @
        \deq -> let eq = eqFromEqDict deq in \xy -> ...
 @
 Well, maybe.  We don't do this at the moment.
 
-
 \begin{code}
-type LevelledExpr  = CoreExpr   (Id, Level) Id
-type LevelledBind  = CoreBinding (Id, Level) Id
-type FloatingBind  = (Level, Floater)
-type FloatingBinds = [FloatingBind]
-
-data Floater = LetFloater     PlainCoreBinding
-
-            | CaseFloater   (PlainCoreExpr -> PlainCoreExpr)
-                               -- Give me a right-hand side of the
-                               -- (usually single) alternative, and
-                               -- I'll build the case
+type LevelledExpr  = TaggedExpr Level
+type LevelledBind  = TaggedBind Level
+type FloatBind     = (Level, CoreBind)
+type FloatBinds    = [FloatBind]
 \end{code}
 
 %************************************************************************
@@ -79,40 +73,48 @@ data Floater = LetFloater     PlainCoreBinding
 %************************************************************************
 
 \begin{code}
-floatOutwards :: (GlobalSwitch -> Bool)         -- access to all global cmd-line opts
-             -> SplitUniqSupply
-             -> PlainCoreProgram 
-             -> PlainCoreProgram
-
-floatOutwards sw_chker us pgm
-  = case (setLevels pgm sw_chker us) of { annotated_w_levels ->
-
-    case unzip3 (map (floatTopBind sw_chker) annotated_w_levels)
-               of { (fcs, lcs, final_toplev_binds_s) ->
-
-    (if sw_chker D_verbose_core2core
-     then pprTrace "Levels added:\n" (ppr PprDebug annotated_w_levels)
-     else id
-    )
-    ( if  sw_chker D_simplifier_stats
-      then pprTrace "FloatOut stats: " (ppBesides [
-               ppInt (sum fcs), ppStr " Lets floated out of ",
-               ppInt (sum lcs), ppStr " Lambdas"])
-      else id
-    )
-    concat final_toplev_binds_s
-    }}
+floatOutwards :: DynFlags
+             -> Bool           -- True <=> float lambdas to top level
+             -> UniqSupply 
+             -> [CoreBind] -> IO [CoreBind]
+
+floatOutwards dflags float_lams us pgm
+  = do {
+       beginPass dflags float_msg ;
+
+       let { annotated_w_levels = setLevels float_lams pgm us ;
+             (fss, binds_s')    = unzip (map floatTopBind annotated_w_levels)
+           } ;
 
-floatTopBind sw bind@(CoNonRec _ _)
-  = case (floatBind sw nullIdEnv tOP_LEVEL bind) of { (fc,lc, floats, bind', _) ->
-    (fc,lc, floatsToBinds floats ++ [bind'])
+       dumpIfSet_dyn dflags Opt_D_verbose_core2core "Levels added:"
+                 (vcat (map ppr annotated_w_levels));
+
+       let { (tlets, ntlets, lams) = get_stats (sum_stats fss) };
+
+       dumpIfSet_dyn dflags Opt_D_dump_simpl_stats "FloatOut stats:"
+               (hcat [ int tlets,  ptext SLIT(" Lets floated to top level; "),
+                       int ntlets, ptext SLIT(" Lets floated elsewhere; from "),
+                       int lams,   ptext SLIT(" Lambda groups")]);
+
+       endPass dflags float_msg
+               (dopt Opt_D_verbose_core2core dflags)
+                       {- no specific flag for dumping float-out -} 
+               (concat binds_s')
     }
+  where
+    float_msg | float_lams = "Float out (floating lambdas too)"
+             | otherwise  = "Float out (not floating lambdas)"
 
-floatTopBind sw bind@(CoRec _)
-  = case (floatBind sw nullIdEnv tOP_LEVEL bind) of { (fc,lc, floats, CoRec pairs', _) ->
+floatTopBind bind@(NonRec _ _)
+  = case (floatBind emptyVarEnv tOP_LEVEL bind) of { (fs, floats, bind', _) ->
+    (fs, floatsToBinds floats ++ [bind'])
+    }
+
+floatTopBind bind@(Rec _)
+  = case (floatBind emptyVarEnv tOP_LEVEL bind) of { (fs, floats, Rec pairs', _) ->
        -- Actually floats will be empty
     --false:ASSERT(null floats)
-    (fc,lc, [CoRec (floatsToBindPairs floats ++ pairs')])
+    (fs, [Rec (floatsToBindPairs floats ++ pairs')])
     }
 \end{code}
 
@@ -124,30 +126,27 @@ floatTopBind sw bind@(CoRec _)
 
 
 \begin{code}
-floatBind :: (GlobalSwitch -> Bool) 
-         -> IdEnv Level
+floatBind :: IdEnv Level
          -> Level
          -> LevelledBind
-         -> (Int,Int, FloatingBinds, PlainCoreBinding, IdEnv Level)
-
-floatBind sw env lvl (CoNonRec (name,level) rhs)
-  = case (floatExpr sw env level rhs) of { (fc,lc, rhs_floats, rhs') ->
+         -> (FloatStats, FloatBinds, CoreBind, IdEnv Level)
 
-       -- A good dumping point
-    case (partitionByMajorLevel level rhs_floats)      of { (rhs_floats', heres) ->
+floatBind env lvl (NonRec (name,level) rhs)
+  = case (floatRhs env level rhs) of { (fs, rhs_floats, rhs') ->
+    (fs, rhs_floats,
+     NonRec name rhs',
+     extendVarEnv env name level)
+    }
 
-    (fc,lc, rhs_floats',CoNonRec name (install heres rhs'), addOneToIdEnv env name level)
-    }}
-    
-floatBind sw env lvl bind@(CoRec pairs)
-  = case (unzip4 (map do_pair pairs)) of { (fcs,lcs, rhss_floats, new_pairs) ->
+floatBind env lvl bind@(Rec pairs)
+  = case (unzip3 (map do_pair pairs)) of { (fss, rhss_floats, new_pairs) ->
 
     if not (isTopLvl bind_level) then
        -- Standard case
-       (sum fcs,sum lcs, concat rhss_floats, CoRec new_pairs, new_env)
+       (sum_stats fss, concat rhss_floats, Rec new_pairs, new_env)
     else
-       {- In a recursive binding, destined for the top level (only), 
-          the rhs floats may contain 
+       {- In a recursive binding, destined for the top level (only),
+          the rhs floats may contain
           references to the bound things.  For example
 
                f = ...(let v = ...f... in b) ...
@@ -157,28 +156,25 @@ floatBind sw env lvl bind@(CoRec pairs)
                v = ...f...
                f = ... b ...
 
-          and hence we must (pessimistically) make all the floats recursive 
+          and hence we must (pessimistically) make all the floats recursive
           with the top binding.  Later dependency analysis will unravel it.
        -}
 
-       (sum fcs,sum lcs, [], 
-        CoRec (new_pairs ++ floatsToBindPairs (concat rhss_floats)),
+       (sum_stats fss,
+        [],
+        Rec (new_pairs ++ floatsToBindPairs (concat rhss_floats)),
         new_env)
 
     }
   where
-    new_env = growIdEnvList env (map fst pairs)
+    new_env = extendVarEnvList env (map fst pairs)
 
     bind_level = getBindLevel bind
 
     do_pair ((name, level), rhs)
-      = case (floatExpr sw new_env level rhs) of { (fc,lc, rhs_floats, rhs') ->
-
-               -- A good dumping point
-       case (partitionByMajorLevel level rhs_floats)   of { (rhs_floats', heres) ->
-
-       (fc,lc, rhs_floats', (name, install heres rhs'))
-       }}
+      = case (floatRhs new_env level rhs) of { (fs, rhs_floats, rhs') ->
+       (fs, rhs_floats, (name, rhs'))
+       }
 \end{code}
 
 %************************************************************************
@@ -188,213 +184,196 @@ floatBind sw env lvl bind@(CoRec pairs)
 %************************************************************************
 
 \begin{code}
-floatExpr :: (GlobalSwitch -> Bool) 
-         -> IdEnv Level
-         -> Level 
-         -> LevelledExpr
-         -> (Int,Int, FloatingBinds, PlainCoreExpr)
-
-floatExpr sw env _ (CoVar v)        = (0,0, [], CoVar v)
-
-floatExpr sw env _ (CoLit l)     = (0,0, [], CoLit l)
-
-floatExpr sw env _ (CoPrim op ty as) = (0,0, [], CoPrim op ty as)
-floatExpr sw env _ (CoCon con ty as) = (0,0, [], CoCon con ty as)
-
-floatExpr sw env lvl (CoApp e a)
-  = case (floatExpr sw env lvl e) of { (fc,lc, floating_defns, e') ->
-    (fc,lc, floating_defns, CoApp e' a) }
-    
-floatExpr sw env lvl (CoTyApp e ty)
-  = case (floatExpr sw env lvl e) of { (fc,lc, floating_defns, e') ->
-    (fc,lc, floating_defns, CoTyApp e' ty) }
-
-floatExpr sw env lvl (CoTyLam tv e)
-  = let
-       incd_lvl = incMinorLvl lvl
-    in
-    case (floatExpr sw env incd_lvl e) of { (fc,lc, floats, e') ->
+floatExpr, floatRhs
+        :: IdEnv Level
+        -> Level
+        -> LevelledExpr
+        -> (FloatStats, FloatBinds, CoreExpr)
+
+floatRhs env lvl arg
+  = case (floatExpr env lvl arg) of { (fsa, floats, arg') ->
+    case (partitionByMajorLevel lvl floats) of { (floats', heres) ->
+       -- Dump bindings that aren't going to escape from a lambda
+       -- This is to avoid floating the x binding out of
+       --      f (let x = e in b)
+       -- unnecessarily.  It even causes a bug to do so if we have
+       --      y = writeArr# a n (let x = e in b)
+       -- because the y binding is an expr-ok-for-speculation one.
+    (fsa, floats', install heres arg') }}
+
+floatExpr env _ (Var v)             = (zeroStats, [], Var v)
+floatExpr env _ (Type ty)    = (zeroStats, [], Type ty)
+floatExpr env _ (Lit lit)    = (zeroStats, [], Lit lit)
+         
+floatExpr env lvl (App e a)
+  = case (floatExpr env lvl e) of { (fse, floats_e, e') ->
+    case (floatRhs env lvl a) of { (fsa, floats_a, a') ->
+    (fse `add_stats` fsa, floats_e ++ floats_a, App e' a') }}
+
+floatExpr env lvl (Lam (tv,incd_lvl) e)
+  | isTyVar tv
+  = case (floatExpr env incd_lvl e) of { (fs, floats, e') ->
 
        -- Dump any bindings which absolutely cannot go any further
     case (partitionByLevel incd_lvl floats)    of { (floats', heres) ->
 
-    (fc,lc, floats', CoTyLam tv (install heres e'))
+    (fs, floats', Lam tv (install heres e'))
     }}
 
-floatExpr sw env lvl (CoLam args@((_,incd_lvl):_) rhs)
-  = let
-       args'    = map fst args
-       new_env  = growIdEnvList env args
+floatExpr env lvl (Lam (arg,incd_lvl) rhs)
+  = ASSERT( isId arg )
+    let
+       new_env  = extendVarEnv env arg incd_lvl
     in
-    case (floatExpr sw new_env incd_lvl rhs) of { (fc,lc, floats, rhs') ->
+    case (floatExpr new_env incd_lvl rhs) of { (fs, floats, rhs') ->
 
        -- Dump any bindings which absolutely cannot go any further
     case (partitionByLevel incd_lvl floats)    of { (floats', heres) ->
 
-    (fc +  length floats', lc + 1,
-     floats', mkCoLam args' (install heres rhs'))
+    (add_to_stats fs floats',
+     floats',
+     Lam arg (install heres rhs'))
     }}
 
-floatExpr sw env lvl (CoSCC cc expr)
-  = case (floatExpr sw env lvl expr)    of { (fc,lc, floating_defns, expr') ->
+floatExpr env lvl (Note note@(SCC cc) expr)
+  = case (floatExpr env lvl expr)    of { (fs, floating_defns, expr') ->
     let
-       -- annotate bindings floated outwards past an scc expression
+       -- Annotate bindings floated outwards past an scc expression
        -- with the cc.  We mark that cc as "duplicated", though.
 
        annotated_defns = annotate (dupifyCC cc) floating_defns
     in
-    (fc,lc, annotated_defns, CoSCC cc expr') }
+    (fs, annotated_defns, Note note expr') }
   where
-    annotate :: CostCentre -> FloatingBinds -> FloatingBinds
+    annotate :: CostCentre -> FloatBinds -> FloatBinds
 
     annotate dupd_cc defn_groups
       = [ (level, ann_bind floater) | (level, floater) <- defn_groups ]
       where
-       ann_bind (LetFloater (CoNonRec binder rhs)) 
-         = LetFloater (CoNonRec binder (ann_rhs rhs))
-
-       ann_bind (LetFloater (CoRec pairs))
-         = LetFloater (CoRec [(binder, ann_rhs rhs) | (binder, rhs) <- pairs])
+       ann_bind (NonRec binder rhs)
+         = NonRec binder (mkSCC dupd_cc rhs)
+
+       ann_bind (Rec pairs)
+         = Rec [(binder, mkSCC dupd_cc rhs) | (binder, rhs) <- pairs]
+
+-- At one time I tried the effect of not float anything out of an InlineMe,
+-- but it sometimes works badly.  For example, consider PrelArr.done.  It
+-- has the form        __inline (\d. e)
+-- where e doesn't mention d.  If we float this to 
+--     __inline (let x = e in \d. x)
+-- things are bad.  The inliner doesn't even inline it because it doesn't look
+-- like a head-normal form.  So it seems a lesser evil to let things float.
+-- In SetLevels we do set the context to (Level 0 0) when we get to an InlineMe
+-- which discourages floating out.
+
+floatExpr env lvl (Note note expr)     -- Other than SCCs
+  = case (floatExpr env lvl expr)    of { (fs, floating_defns, expr') ->
+    (fs, floating_defns, Note note expr') }
+
+floatExpr env lvl (Let bind body)
+  = case (floatBind env     lvl bind) of { (fsb, rhs_floats, bind', new_env) ->
+    case (floatExpr new_env lvl body) of { (fse, body_floats, body') ->
+    (add_stats fsb fse,
+     rhs_floats ++ [(bind_lvl, bind')] ++ body_floats,
+     body')
+    }}
+  where
+    bind_lvl = getBindLevel bind
 
-       ann_bind (CaseFloater fn) = CaseFloater ( \ rhs -> CoSCC dupd_cc (fn rhs) )
+floatExpr env lvl (Case scrut (case_bndr, case_lvl) alts)
+  = case floatExpr env lvl scrut       of { (fse, fde, scrut') ->
+    case floatList float_alt alts      of { (fsa, fda, alts')  ->
+    (add_stats fse fsa, fda ++ fde, Case scrut' case_bndr alts')
+    }}
+  where
+      alts_env = extendVarEnv env case_bndr case_lvl
 
-       ann_rhs (CoLam   args e) = CoLam   args (ann_rhs e)
-       ann_rhs (CoTyLam tv   e) = CoTyLam tv   (ann_rhs e)
-       ann_rhs rhs@(CoCon _ _ _)= rhs  -- no point in scc'ing WHNF data
-       ann_rhs rhs              = CoSCC dupd_cc rhs
+      partition_fn = partitionByMajorLevel
 
-       -- Note: Nested SCC's are preserved for the benefit of
-       --       cost centre stack profiling (Durham)
+      float_alt (con, bs, rhs)
+       = let
+             bs' = map fst bs
+             new_env = extendVarEnvList alts_env bs
+         in
+         case (floatExpr new_env case_lvl rhs)         of { (fs, rhs_floats, rhs') ->
+         case (partition_fn case_lvl rhs_floats)       of { (rhs_floats', heres) ->
+         (fs, rhs_floats', (con, bs', install heres rhs')) }}
 
-floatExpr sw env lvl (CoLet bind body)
-  = case (floatBind sw env     lvl bind) of { (fcb,lcb, rhs_floats, bind', new_env) ->
-    case (floatExpr sw new_env lvl body) of { (fce,lce, body_floats, body') ->
-    (fcb + fce, lcb + lce,
-     rhs_floats ++ [(bind_lvl, LetFloater bind')] ++ body_floats, body')
-    }}
-  where
-    bind_lvl = getBindLevel bind
 
-floatExpr sw env lvl (CoCase scrut alts)
-  = case (floatExpr sw env lvl scrut) of { (fce,lce, fde, scrut') ->
+floatList :: (a -> (FloatStats, FloatBinds, b)) -> [a] -> (FloatStats, FloatBinds, [b])
+floatList f [] = (zeroStats, [], [])
+floatList f (a:as) = case f a           of { (fs_a,  binds_a,  b)  ->
+                    case floatList f as of { (fs_as, binds_as, bs) ->
+                    (fs_a `add_stats` fs_as, binds_a ++ binds_as, b:bs) }}
+\end{code}
 
-    case (scrut', float_alts alts) of 
+%************************************************************************
+%*                                                                     *
+\subsection{Utility bits for floating stats}
+%*                                                                     *
+%************************************************************************
 
-{-     CASE-FLOATING DROPPED FOR NOW.  (SLPJ 7/2/94)
+I didn't implement this with unboxed numbers.  I don't want to be too
+strict in this stuff, as it is rarely turned on.  (WDP 95/09)
 
-       (CoVar scrut_var, (fda, CoAlgAlts [(con,bs,rhs')] CoNoDefault)) 
-               | scrut_var_lvl `ltMajLvl` lvl ->
+\begin{code}
+data FloatStats
+  = FlS        Int  -- Number of top-floats * lambda groups they've been past
+       Int  -- Number of non-top-floats * lambda groups they've been past
+       Int  -- Number of lambda (groups) seen
 
-               -- Candidate for case floater; scrutinising a variable; it can
-               -- escape outside a lambda; there's only one alternative.
-               (fda ++ fde ++ [case_floater], rhs')
+get_stats (FlS a b c) = (a, b, c)
 
-               where
-               case_floater = (scrut_var_lvl, CaseFloater fn)
-               fn body = CoCase scrut' (CoAlgAlts [(con,bs,body)] CoNoDefault)
-               scrut_var_lvl = case lookupIdEnv env scrut_var of
-                                 Nothing  -> Level 0 0
-                                 Just lvl -> unTopify lvl
+zeroStats = FlS 0 0 0
 
- END OF CASE FLOATING DROPPED          -}
+sum_stats xs = foldr add_stats zeroStats xs
 
-       (_, (fca,lca, fda, alts')) -> 
+add_stats (FlS a1 b1 c1) (FlS a2 b2 c2)
+  = FlS (a1 + a2) (b1 + b2) (c1 + c2)
 
-               (fce + fca, lce + lca, fda ++ fde, CoCase scrut' alts') 
-    }
+add_to_stats (FlS a b c) floats
+  = FlS (a + length top_floats) (b + length other_floats) (c + 1)
   where
-      incd_lvl = incMinorLvl lvl
+    (top_floats, other_floats) = partition to_very_top floats
 
-      partition_fn = partitionByMajorLevel
-
-{-     OMITTED
-       We don't want to be too keen about floating lets out of case alternatives
-       because they may benefit from seeing the evaluation done by the case.
-       
-       The main reason for doing this is to allocate in fewer larger blocks
-       but that's really an STG-level issue.
-
-                       case alts of
-                               -- Just one alternative, then dump only
-                               -- what *has* to be dumped
-                       CoAlgAlts  [_] CoNoDefault         -> partitionByLevel
-                       CoAlgAlts  []  (CoBindDefault _ _) -> partitionByLevel
-                       CoPrimAlts [_] CoNoDefault         -> partitionByLevel
-                       CoPrimAlts []  (CoBindDefault _ _) -> partitionByLevel
-
-                               -- If there's more than one alternative, then
-                               -- this is a dumping point
-                       other                              -> partitionByMajorLevel
--}
-
-      float_alts (CoAlgAlts alts deflt)
-       = case (float_deflt  deflt)              of { (fcd,lcd,   fdd,  deflt') ->
-         case (unzip4 (map float_alg_alt alts)) of { (fcas,lcas, fdas, alts') ->
-         (fcd + sum fcas, lcd + sum lcas,
-          concat fdas ++ fdd, CoAlgAlts alts' deflt') }}
-
-      float_alts (CoPrimAlts alts deflt)
-       = case (float_deflt deflt)                of { (fcd,lcd,   fdd, deflt') ->
-         case (unzip4 (map float_prim_alt alts)) of { (fcas,lcas, fdas, alts') ->
-         (fcd + sum fcas, lcd + sum lcas,
-          concat fdas ++ fdd, CoPrimAlts alts' deflt') }}
-
-      -------------
-      float_alg_alt (con, bs, rhs)
-       = let
-             bs' = map fst bs
-             new_env = growIdEnvList env bs
-         in
-         case (floatExpr sw new_env incd_lvl rhs)      of { (fc,lc, rhs_floats, rhs') ->
-         case (partition_fn incd_lvl rhs_floats)       of { (rhs_floats', heres) ->
-         (fc, lc, rhs_floats', (con, bs', install heres rhs'))
-         }}
-
-      --------------
-      float_prim_alt (lit, rhs)
-       = case (floatExpr sw env incd_lvl rhs)          of { (fc,lc, rhs_floats, rhs') ->
-         case (partition_fn incd_lvl rhs_floats)       of { (rhs_floats', heres) ->
-         (fc,lc, rhs_floats', (lit, install heres rhs'))
-         }}
-
-      --------------
-      float_deflt CoNoDefault = (0,0, [], CoNoDefault)
-
-      float_deflt (CoBindDefault (b,lvl) rhs)
-       = case (floatExpr sw new_env lvl rhs)           of { (fc,lc, rhs_floats, rhs') ->
-         case (partition_fn incd_lvl rhs_floats)       of { (rhs_floats', heres) ->
-         (fc,lc, rhs_floats', CoBindDefault b (install heres rhs'))
-         }}
-       where
-         new_env = addOneToIdEnv env b lvl        
+    to_very_top (my_lvl, _) = isTopLvl my_lvl
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
-\subsection[FloatOut-utils]{Utility bits for floating}
+\subsection{Utility bits for floating}
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
-getBindLevel (CoNonRec (_, lvl) _)      = lvl
-getBindLevel (CoRec (((_,lvl), _) : _)) = lvl
+getBindLevel (NonRec (_, lvl) _)      = lvl
+getBindLevel (Rec (((_,lvl), _) : _)) = lvl
 \end{code}
 
 \begin{code}
 partitionByMajorLevel, partitionByLevel
        :: Level                -- Partitioning level
 
-       -> FloatingBinds        -- Defns to be divided into 2 piles...
+       -> FloatBinds           -- Defns to be divided into 2 piles...
 
-       -> (FloatingBinds,      -- Defns  with level strictly < partition level,
-           FloatingBinds)      -- The rest
+       -> (FloatBinds, -- Defns  with level strictly < partition level,
+           FloatBinds) -- The rest
 
 
-partitionByMajorLevel ctxt_lvl defns 
+partitionByMajorLevel ctxt_lvl defns
   = partition float_further defns
   where
-    float_further (my_lvl, _) = my_lvl `ltMajLvl` ctxt_lvl ||
-                               isTopLvl my_lvl
+       -- Float it if we escape a value lambda, 
+       -- or if we get to the top level
+    float_further (my_lvl, bind) = my_lvl `ltMajLvl` ctxt_lvl || isTopLvl my_lvl
+       -- The isTopLvl part says that if we can get to the top level, say "yes" anyway
+       -- This means that 
+       --      x = f e
+       -- transforms to 
+       --    lvl = e
+       --    x = f lvl
+       -- which is as it should be
 
 partitionByLevel ctxt_lvl defns
   = partition float_further defns
@@ -403,25 +382,20 @@ partitionByLevel ctxt_lvl defns
 \end{code}
 
 \begin{code}
-floatsToBinds :: FloatingBinds -> [PlainCoreBinding]
-floatsToBinds floats = map get_bind floats
-                    where
-                      get_bind (_, LetFloater bind) = bind
-                      get_bind (_, CaseFloater _)   = panic "floatsToBinds"
+floatsToBinds :: FloatBinds -> [CoreBind]
+floatsToBinds floats = map snd floats
 
-floatsToBindPairs :: FloatingBinds -> [(Id,PlainCoreExpr)]
+floatsToBindPairs :: FloatBinds -> [(Id,CoreExpr)]
 
 floatsToBindPairs floats = concat (map mk_pairs floats)
   where
-   mk_pairs (_, LetFloater (CoRec pairs))         = pairs
-   mk_pairs (_, LetFloater (CoNonRec binder rhs)) = [(binder,rhs)]
-   mk_pairs (_, CaseFloater _)                           = panic "floatsToBindPairs"
+   mk_pairs (_, Rec pairs)         = pairs
+   mk_pairs (_, NonRec binder rhs) = [(binder,rhs)]
 
-install :: FloatingBinds -> PlainCoreExpr -> PlainCoreExpr
+install :: FloatBinds -> CoreExpr -> CoreExpr
 
 install defn_groups expr
   = foldr install_group expr defn_groups
   where
-    install_group (_, LetFloater defns) body = CoLet defns body
-    install_group (_, CaseFloater fn)   body = fn body
+    install_group (_, defns) body = Let defns body
 \end{code}