Bottom extraction: float out bottoming expressions to top level
[ghc-hetmet.git] / compiler / simplCore / SimplUtils.lhs
index 972c0e5..56d2795 100644 (file)
@@ -10,7 +10,7 @@ module SimplUtils (
 
        -- Inlining,
        preInlineUnconditionally, postInlineUnconditionally, 
-       activeInline, activeRule, 
+       activeUnfolding, activeUnfInRule, activeRule, 
         simplEnvForGHCi, simplEnvForRules, updModeForInlineRules,
 
        -- The continuation type
@@ -40,7 +40,7 @@ import CoreUnfold
 import Name
 import Id
 import Var     ( isCoVar )
-import NewDemand
+import Demand
 import SimplMonad
 import Type    hiding( substTy )
 import Coercion ( coercionKind )
@@ -334,7 +334,7 @@ mkArgInfo fun rules n_val_args call_cont
     vanilla_discounts, arg_discounts :: [Int]
     vanilla_discounts = repeat 0
     arg_discounts = case idUnfolding fun of
-                       CoreUnfolding {uf_guidance = UnfoldIfGoodArgs {ug_args = discounts}}
+                       CoreUnfolding {uf_guidance = UnfIfGoodArgs {ug_args = discounts}}
                              -> discounts ++ vanilla_discounts
                        _     -> vanilla_discounts
 
@@ -342,7 +342,7 @@ mkArgInfo fun rules n_val_args call_cont
     vanilla_stricts  = repeat False
 
     arg_stricts
-      = case splitStrictSig (idNewStrictness fun) of
+      = case splitStrictSig (idStrictness fun) of
          (demands, result_info)
                | not (demands `lengthExceeds` n_val_args)
                ->      -- Enough args, use the strictness given.
@@ -635,11 +635,18 @@ let-float if you inline windowToViewport
 However, as usual for Gentle mode, do not inline things that are
 inactive in the intial stages.  See Note [Gentle mode].
 
+Note [Top-level botomming Ids]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Don't inline top-level Ids that are bottoming, even if they are used just
+once, because FloatOut has gone to some trouble to extract them out.
+Inlining them won't make the program run faster!
+
 \begin{code}
 preInlineUnconditionally :: SimplEnv -> TopLevelFlag -> InId -> InExpr -> Bool
 preInlineUnconditionally env top_lvl bndr rhs
-  | not active                    = False
-  | opt_SimplNoPreInlining = False
+  | not active                                      = False
+  | isTopLevel top_lvl && isBottomingId bndr = False   -- Note [Top-level bottoming Ids]
+  | opt_SimplNoPreInlining                   = False
   | otherwise = case idOccInfo bndr of
                  IAmDead                    -> True    -- Happens in ((\x.1) v)
                  OneOcc in_lam True int_cxt -> try_once in_lam int_cxt
@@ -651,12 +658,11 @@ preInlineUnconditionally env top_lvl bndr rhs
                        -- See Note [pre/postInlineUnconditionally in gentle mode]
                   SimplPhase n _ -> isActive n act
     act = idInlineActivation bndr
-
     try_once in_lam int_cxt    -- There's one textual occurrence
        | not in_lam = isNotTopLevel top_lvl || early_phase
        | otherwise  = int_cxt && canInlineInLam rhs
 
--- Be very careful before inlining inside a lambda, becuase (a) we must not 
+-- Be very careful before inlining inside a lambda, because (a) we must not 
 -- invalidate occurrence information, and (b) we want to avoid pushing a
 -- single allocation (here) into multiple allocations (inside lambda).  
 -- Inlining a *function* with a single *saturated* call would be ok, mind you.
@@ -739,12 +745,13 @@ postInlineUnconditionally
     -> Unfolding
     -> Bool
 postInlineUnconditionally env top_lvl bndr occ_info rhs unfolding
-  | not active            = False
-  | isLoopBreaker occ_info = False     -- If it's a loop-breaker of any kind, don't inline
+  | not active                 = False
+  | isLoopBreaker occ_info      = False        -- If it's a loop-breaker of any kind, don't inline
                                        -- because it might be referred to "earlier"
-  | isExportedId bndr      = False
-  | isInlineRule unfolding = False     -- Note [InlineRule and postInlineUnconditionally]
-  | exprIsTrivial rhs     = True
+  | isExportedId bndr           = False
+  | isStableUnfolding unfolding = False        -- Note [InlineRule and postInlineUnconditionally]
+  | exprIsTrivial rhs          = True
+  | isTopLevel top_lvl          = False        -- Note [Top level and postInlineUnconditionally]
   | otherwise
   = case occ_info of
        -- The point of examining occ_info here is that for *non-values* 
@@ -757,7 +764,8 @@ postInlineUnconditionally env top_lvl bndr occ_info rhs unfolding
        --      case v of
        --         True  -> case x of ...
        --         False -> case x of ...
-       -- I'm not sure how important this is in practice
+       -- This is very important in practice; e.g. wheel-seive1 doubles 
+       -- in allocation if you miss this out
       OneOcc in_lam _one_br int_cxt    -- OneOcc => no code-duplication issue
        ->     smallEnoughToInline unfolding    -- Small enough to dup
                        -- ToDo: consider discount on smallEnoughToInline if int_cxt is true
@@ -770,8 +778,8 @@ postInlineUnconditionally env top_lvl bndr occ_info rhs unfolding
                        -- PRINCIPLE: when we've already simplified an expression once, 
                        -- make sure that we only inline it if it's reasonably small.
 
-          &&  ((isNotTopLevel top_lvl && not in_lam) || 
-                       -- But outside a lambda, we want to be reasonably aggressive
+           && (not in_lam || 
+                       -- Outside a lambda, we want to be reasonably aggressive
                        -- about inlining into multiple branches of case
                        -- e.g. let x = <non-value> 
                        --      in case y of { C1 -> ..x..; C2 -> ..x..; C3 -> ... } 
@@ -810,27 +818,56 @@ postInlineUnconditionally env top_lvl bndr occ_info rhs unfolding
                   SimplPhase n _ -> isActive n act
     act = idInlineActivation bndr
 
-activeInline :: SimplEnv -> OutId -> Bool
-activeInline env id
-  | isNonRuleLoopBreaker (idOccInfo id)          -- Things with an INLINE pragma may have 
-                                         -- an unfolding *and* be a loop breaker
-  = False                                -- (maybe the knot is not yet untied)
-  | otherwise
+activeUnfolding :: SimplEnv -> IdUnfoldingFun
+activeUnfolding env
   = case getMode env of
-      SimplGently { sm_inline = inlining_on } 
-         -> inlining_on && isEarlyActive act
-       -- See Note [Gentle mode]
-
-       -- NB: we used to have a second exception, for data con wrappers.
-       -- On the grounds that we use gentle mode for rule LHSs, and 
-       -- they match better when data con wrappers are inlined.
-       -- But that only really applies to the trivial wrappers (like (:)),
-       -- and they are now constructed as Compulsory unfoldings (in MkId)
-       -- so they'll happen anyway.
-
-      SimplPhase n _ -> isActive n act
+      SimplGently { sm_inline = False } -> active_unfolding_minimal
+      SimplGently { sm_inline = True  } -> active_unfolding_gentle
+      SimplPhase n _                    -> active_unfolding n
+
+activeUnfInRule :: SimplEnv -> IdUnfoldingFun
+-- When matching in RULE, we want to "look through" an unfolding
+-- if *rules* are on, even if *inlinings* are not.  A notable example
+-- is DFuns, which really we want to match in rules like (op dfun)
+-- in gentle mode.
+activeUnfInRule env
+  = case getMode env of
+      SimplGently { sm_rules = False } -> active_unfolding_minimal
+      SimplGently { sm_rules = True  } -> active_unfolding_gentle
+      SimplPhase n _                   -> active_unfolding n
+
+active_unfolding_minimal :: IdUnfoldingFun
+-- Compuslory unfoldings only
+-- Ignore SimplGently, because we want to inline regardless;
+-- the Id has no top-level binding at all
+--
+-- NB: we used to have a second exception, for data con wrappers.
+-- On the grounds that we use gentle mode for rule LHSs, and 
+-- they match better when data con wrappers are inlined.
+-- But that only really applies to the trivial wrappers (like (:)),
+-- and they are now constructed as Compulsory unfoldings (in MkId)
+-- so they'll happen anyway.
+active_unfolding_minimal id
+  | isCompulsoryUnfolding unf = unf
+  | otherwise                 = NoUnfolding
   where
-    act = idInlineActivation id
+    unf = realIdUnfolding id   -- Never a loop breaker
+
+active_unfolding_gentle :: IdUnfoldingFun
+-- Anything that is early-active
+-- See Note [Gentle mode]
+active_unfolding_gentle id
+  | isEarlyActive (idInlineActivation id) = idUnfolding id
+  | otherwise                             = NoUnfolding
+      -- idUnfolding checks for loop-breakers
+      -- Things with an INLINE pragma may have 
+      -- an unfolding *and* be a loop breaker  
+      -- (maybe the knot is not yet untied)
+
+active_unfolding :: CompilerPhase -> IdUnfoldingFun
+active_unfolding n id
+  | isActive n (idInlineActivation id) = idUnfolding id
+  | otherwise                          = NoUnfolding
 
 activeRule :: DynFlags -> SimplEnv -> Maybe (Activation -> Bool)
 -- Nothing => No rules at all
@@ -845,6 +882,14 @@ activeRule dflags env
       SimplPhase n _ -> Just (isActive n)
 \end{code}
 
+Note [Top level and postInlineUnconditionally]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We don't do postInlineUnconditionally for top-level things (except
+ones that are trivial).  There is no point, because the main goal is
+to get rid of local bindings used in multiple case branches. And
+doing so risks replacing a single global allocation with local allocations.
+
+
 Note [InlineRule and postInlineUnconditionally]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Do not do postInlineUnconditionally if the Id has an InlineRule, otherwise