#include "HsVersions.h"
import CoreSyn
+import CoreUtils ( mkSCC )
-import CmdLineOpts ( opt_D_verbose_core2core, opt_D_dump_simpl_stats )
-import ErrUtils ( dumpIfSet )
+import CmdLineOpts ( DynFlags, DynFlag(..) )
+import ErrUtils ( dumpIfSet_dyn )
import CostCentre ( dupifyCC, CostCentre )
import Id ( Id )
-import Const ( isWHNFCon )
import VarEnv
-import CoreLint ( beginPass, endPass )
-import PprCore
+import CoreLint ( showPass, endPass )
import SetLevels ( setLevels,
Level(..), tOP_LEVEL, ltMajLvl, ltLvl, isTopLvl
)
-import BasicTypes ( Unused )
-import Var ( TyVar )
import UniqSupply ( UniqSupply )
import List ( partition )
import Outputable
%************************************************************************
\begin{code}
-floatOutwards :: UniqSupply -> [CoreBind] -> IO [CoreBind]
+floatOutwards :: DynFlags
+ -> Bool -- True <=> float lambdas to top level
+ -> UniqSupply
+ -> [CoreBind] -> IO [CoreBind]
-floatOutwards us pgm
+floatOutwards dflags float_lams us pgm
= do {
- beginPass "Float out";
+ showPass dflags float_msg ;
- let { annotated_w_levels = setLevels pgm us ;
+ let { annotated_w_levels = setLevels float_lams pgm us ;
(fss, binds_s') = unzip (map floatTopBind annotated_w_levels)
} ;
- dumpIfSet opt_D_verbose_core2core "Levels added:"
+ 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 opt_D_dump_simpl_stats "FloatOut stats:"
+ 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 "Float out"
- opt_D_verbose_core2core {- no specific flag for dumping float-out -}
- (concat binds_s')
+ endPass dflags float_msg Opt_D_verbose_core2core (concat binds_s')
+ {- no specific flag for dumping float-out -}
}
+ where
+ float_msg | float_lams = "Float out (floating lambdas too)"
+ | otherwise = "Float out (not floating lambdas)"
floatTopBind bind@(NonRec _ _)
= case (floatBind emptyVarEnv tOP_LEVEL bind) of { (fs, floats, bind', _) ->
-> (FloatStats, FloatBinds, CoreBind, IdEnv Level)
floatBind env lvl (NonRec (name,level) rhs)
- = case (floatExpr env level rhs) of { (fs, rhs_floats, rhs') ->
-
- -- A good dumping point
- case (partitionByMajorLevel level rhs_floats) of { (rhs_floats', heres) ->
-
- (fs, rhs_floats',
- NonRec name (install heres rhs'),
+ = case (floatRhs env level rhs) of { (fs, rhs_floats, rhs') ->
+ (fs, rhs_floats,
+ NonRec name rhs',
extendVarEnv env name level)
- }}
+ }
floatBind env lvl bind@(Rec pairs)
= case (unzip3 (map do_pair pairs)) of { (fss, rhss_floats, new_pairs) ->
bind_level = getBindLevel bind
do_pair ((name, level), rhs)
- = case (floatExpr new_env level rhs) of { (fs, rhs_floats, rhs') ->
-
- -- A good dumping point
- case (partitionByMajorLevel level rhs_floats) of { (rhs_floats', heres) ->
-
- (fs, rhs_floats', (name, install heres rhs'))
- }}
+ = case (floatRhs new_env level rhs) of { (fs, rhs_floats, rhs') ->
+ (fs, rhs_floats, (name, rhs'))
+ }
\end{code}
%************************************************************************
%************************************************************************
\begin{code}
-floatExpr :: IdEnv Level
- -> Level
- -> LevelledExpr
- -> (FloatStats, FloatBinds, CoreExpr)
+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 lvl (Con con as)
- = case floatList (floatExpr env lvl) as of { (stats, floats, as') ->
- (stats, floats, Con con as') }
+floatExpr env _ (Lit lit) = (zeroStats, [], Lit lit)
floatExpr env lvl (App e a)
= case (floatExpr env lvl e) of { (fse, floats_e, e') ->
- case (floatExpr env lvl a) of { (fsa, floats_a, a') ->
+ 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)
= [ (level, ann_bind floater) | (level, floater) <- defn_groups ]
where
ann_bind (NonRec binder rhs)
- = NonRec binder (ann_rhs rhs)
+ = NonRec binder (mkSCC dupd_cc rhs)
ann_bind (Rec pairs)
- = Rec [(binder, ann_rhs rhs) | (binder, rhs) <- pairs]
-
- ann_rhs (Lam arg e) = Lam arg (ann_rhs e)
- ann_rhs rhs@(Con con _) | isWHNFCon con = rhs -- no point in scc'ing WHNF data
- ann_rhs rhs = Note (SCC dupd_cc) rhs
-
- -- Note: Nested SCC's are preserved for the benefit of
- -- cost centre stack profiling (Durham)
+ = 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') ->
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