[project @ 1997-01-06 21:08:42 by simonpj]
[ghc-hetmet.git] / ghc / compiler / simplCore / Simplify.lhs
index f1ac5d8..75537f0 100644 (file)
@@ -21,14 +21,16 @@ import CoreSyn
 import CoreUtils       ( coreExprType, nonErrorRHSs, maybeErrorApp,
                          unTagBinders, squashableDictishCcExpr
                        )
-import Id              ( idType, idWantsToBeINLINEd,
+import Id              ( idType, idWantsToBeINLINEd, addIdArity, 
                          getIdDemandInfo, addIdDemandInfo,
                          GenId{-instance NamedThing-}
                        )
-import IdInfo          ( willBeDemanded, DemandInfo )
+import Name            ( isExported )
+import IdInfo          ( willBeDemanded, noDemandInfo, DemandInfo, ArityInfo(..),
+                         atLeastArity, unknownArity )
 import Literal         ( isNoRepLit )
 import Maybes          ( maybeToBool )
-import Name            ( isLocallyDefined )
+--import Name          ( isExported )
 import PprStyle                ( PprStyle(..) )
 import PprType         ( GenType{-instance Outputable-} )
 import Pretty          ( ppAbove )
@@ -42,7 +44,7 @@ import Type           ( mkTyVarTy, mkTyVarTys, mkAppTy,
                          splitFunTy, getFunTy_maybe, eqTy
                        )
 import TysWiredIn      ( realWorldStateTy )
-import Util            ( isSingleton, zipEqual, panic, pprPanic, assertPanic )
+import Util            ( isSingleton, zipEqual, zipWithEqual, panic, pprPanic, assertPanic )
 \end{code}
 
 The controlling flags, and what they do
@@ -193,8 +195,8 @@ simplTopBinds env [] = returnSmpl []
 simplTopBinds env (NonRec binder@(in_id,occ_info) rhs : binds)
   =    -- No cloning necessary at top level
        -- Process the binding
-    simplRhsExpr env binder rhs        `thenSmpl` \ rhs' ->
-    completeNonRec True env binder rhs'        `thenSmpl` \ (new_env, binds1') ->
+    simplRhsExpr env binder rhs                                `thenSmpl` \ (rhs',arity) ->
+    completeNonRec env binder (in_id `withArity` arity) rhs'   `thenSmpl` \ (new_env, binds1') ->
 
        -- Process the other bindings
     simplTopBinds new_env binds        `thenSmpl` \ binds2' ->
@@ -322,23 +324,12 @@ simplExpr env (Lam (TyBinder tyvar) body) (TyArg ty : args)
     simplExpr (extendTyEnv env tyvar ty) body args
 
 simplExpr env tylam@(Lam (TyBinder tyvar) body) []
-  = do_tylambdas env [] tylam
-  where
-    do_tylambdas env tyvars' (Lam (TyBinder tyvar) body)
-      =          -- Clone the type variable
-       cloneTyVarSmpl tyvar            `thenSmpl` \ tyvar' ->
-       let
-           new_env = extendTyEnv env tyvar (mkTyVarTy tyvar')
-       in
-       do_tylambdas new_env (tyvar':tyvars') body
-
-    do_tylambdas env tyvars' body
-      =        simplExpr env body []           `thenSmpl` \ body' ->
-       returnSmpl (
-          (if switchIsSet env SimplDoEtaReduction
-          then mkTyLamTryingEta
-          else mkTyLam) (reverse tyvars')  body'
-       )
+  = cloneTyVarSmpl tyvar               `thenSmpl` \ tyvar' ->
+    let
+       new_env = extendTyEnv env tyvar (mkTyVarTy tyvar')
+    in
+    simplExpr new_env body []          `thenSmpl` \ body' ->
+    returnSmpl (Lam (TyBinder tyvar') body')
 
 #ifdef DEBUG
 simplExpr env (Lam (TyBinder _) _) (_ : _)
@@ -378,6 +369,8 @@ simplExpr env expr@(Lam (ValBinder binder) body) orig_args
            new_env = markDangerousOccs env (take n orig_args)
         in
         simplValLam new_env expr 0 {- Guaranteed applied to at least 0 args! -}
+                               `thenSmpl` \ (expr', arity) ->
+       returnSmpl expr'
 
     go n env non_val_lam_expr args             -- The lambda had enough arguments
       = simplExpr env non_val_lam_expr args
@@ -486,13 +479,9 @@ simplRhsExpr
        :: SimplEnv
        -> InBinder
        -> InExpr
-       -> SmplM OutExpr
+       -> SmplM (OutExpr, ArityInfo)
 
 simplRhsExpr env binder@(id,occ_info) rhs
-  | dont_eta_expand rhs
-  = simplExpr rhs_env rhs []
-
-  | otherwise  -- Have a go at eta expansion
   =    -- Deal with the big lambda part
     ASSERT( null uvars )       -- For now
 
@@ -503,17 +492,15 @@ simplRhsExpr env binder@(id,occ_info) rhs
        -- Deal with the little lambda part
        -- Note that we call simplLam even if there are no binders,
        -- in case it can do arity expansion.
-    simplValLam lam_env body (getBinderInfoArity occ_info)     `thenSmpl` \ lambda' ->
+    simplValLam lam_env body (getBinderInfoArity occ_info)     `thenSmpl` \ (lambda', arity) ->
 
        -- Put it back together
-    returnSmpl (
-       (if switchIsSet env SimplDoEtaReduction
-       then mkTyLamTryingEta
-       else mkTyLam) tyvars' lambda'
-    )
+    returnSmpl (mkTyLam tyvars' lambda', arity)
   where
 
-    rhs_env | not (switchIsSet env IgnoreINLINEPragma) &&
+    rhs_env |  -- not (switchIsSet env IgnoreINLINEPragma) &&
+               -- No!  Don't ever inline in a INLINE thing's rhs, because
+               -- doing so will inline a worker straight back into its wrapper!
              idWantsToBeINLINEd id
            = switchOffInlining env
            | otherwise 
@@ -544,25 +531,6 @@ simplRhsExpr env binder@(id,occ_info) rhs
        -- We havn't solved this problem yet!
 
     (uvars, tyvars, body) = collectUsageAndTyBinders rhs
-
-       -- dont_eta_expand prevents eta expansion in silly situations.
-       -- For example, consider the defn
-       --      x = y
-       -- It would be silly to eta expand the "y", because it would just
-       -- get eta-reduced back to y.  Furthermore, if this was a top level defn,
-       -- and x was exported, then the defn won't be eliminated, so this
-       -- silly expand/reduce cycle will happen every time, which makes the
-       -- simplifier loop!.
-       -- The solution is to not even try eta expansion unless the rhs looks
-       -- non-trivial.
-    dont_eta_expand (Lit _)     = True
-    dont_eta_expand (Var _)     = True
-    dont_eta_expand (Con _ _)   = True
-    dont_eta_expand (App f a)
-      | notValArg    a         = dont_eta_expand f
-    dont_eta_expand (Lam x b)
-      | notValBinder x         = dont_eta_expand b
-    dont_eta_expand _          = False
 \end{code}
 
 
@@ -578,7 +546,10 @@ the abstraction will always be applied to at least min_no_of_args.
 \begin{code}
 simplValLam env expr min_no_of_args
   | not (switchIsSet env SimplDoLambdaEtaExpansion) || -- Bale out if eta expansion off
-    null binders                                   ||  -- or it's a thunk
+
+-- We used to disable eta expansion for thunks, but I don't see why.
+--    null binders                                 ||  -- or it's a thunk
+
     null potential_extra_binder_tys                ||  -- or ain't a function
     no_of_extra_binders <= 0                           -- or no extra binders needed
   = cloneIds env binders               `thenSmpl` \ binders' ->
@@ -586,11 +557,7 @@ simplValLam env expr min_no_of_args
        new_env = extendIdEnvWithClones env binders binders'
     in
     simplExpr new_env body []          `thenSmpl` \ body' ->
-    returnSmpl (
-      (if switchIsSet new_env SimplDoEtaReduction
-       then mkValLamTryingEta
-       else mkValLam) binders' body'
-    )
+    returnSmpl (mkValLam binders' body', atLeastArity no_of_binders)
 
   | otherwise                          -- Eta expansion possible
   = tick EtaExpansion                  `thenSmpl_`
@@ -601,13 +568,13 @@ simplValLam env expr min_no_of_args
     newIds extra_binder_tys                            `thenSmpl` \ extra_binders' ->
     simplExpr new_env body (map VarArg extra_binders') `thenSmpl` \ body' ->
     returnSmpl (
-      (if switchIsSet new_env SimplDoEtaReduction
-       then mkValLamTryingEta
-       else mkValLam) (binders' ++ extra_binders') body'
+      mkValLam (binders' ++ extra_binders') body',
+      atLeastArity (no_of_binders + no_of_extra_binders)
     )
 
   where
     (binders,body) = collectValBinders expr
+    no_of_binders  = length binders
     (potential_extra_binder_tys, res_ty)
        = splitFunTy (simplTy env (coreExprType (unTagBinders body)))
        -- Note: it's possible that simplValLam will be applied to something
@@ -619,8 +586,14 @@ simplValLam env expr min_no_of_args
     extra_binder_tys = take no_of_extra_binders potential_extra_binder_tys
 
     no_of_extra_binders =      -- First, use the info about how many args it's
-                               -- always applied to in its scope
-                          (min_no_of_args - length binders)
+                               -- always applied to in its scope; but ignore this
+                               -- if it's a thunk!  To see why we ignore it for thunks,
+                               -- consider     let f = lookup env key in (f 1, f 2)
+                               -- We'd better not eta expand f just because it is 
+                               -- always applied!
+                          (if null binders
+                           then 0 
+                           else min_no_of_args - no_of_binders)
 
                                -- Next, try seeing if there's a lambda hidden inside
                                -- something cheap
@@ -634,7 +607,6 @@ simplValLam env expr min_no_of_args
                           case potential_extra_binder_tys of
                                [ty] | ty `eqTy` realWorldStateTy -> 1
                                other                             -> 0
-
 \end{code}
 
 
@@ -727,6 +699,10 @@ ToDo: check this is OK with andy
 -- Dead code is now discarded by the occurrence analyser,
 
 simplBind env (NonRec binder@(id,occ_info) rhs) body_c body_ty
+  | idWantsToBeINLINEd id
+  = complete_bind env rhs      -- Don't messa bout with floating or let-to-case on
+                               -- INLINE things
+  | otherwise
   = simpl_bind env rhs
   where
     -- Try let-to-case; see notes below about let-to-case
@@ -773,8 +749,10 @@ simplBind env (NonRec binder@(id,occ_info) rhs) body_c body_ty
     simpl_bind env rhs = complete_bind env rhs
  
     complete_bind env rhs
-      = simplRhsExpr env binder rhs            `thenSmpl` \ rhs' ->
-       completeNonRec False env binder rhs'    `thenSmpl` \ (new_env, binds) ->
+      = simplRhsExpr env binder rhs            `thenSmpl` \ (rhs',arity) ->
+       cloneId env binder                      `thenSmpl` \ new_id ->
+       completeNonRec env binder 
+               (new_id `withArity` arity) rhs' `thenSmpl` \ (new_env, binds) ->
         body_c new_env                         `thenSmpl` \ body' ->
         returnSmpl (mkCoLetsAny binds body')
 
@@ -995,6 +973,9 @@ simplBind env (Rec pairs) body_c body_ty
                                              (pairs', body') = do_float body
     do_float other                         = ([], other)
 
+
+-- The env passed to simplRecursiveGroup already has 
+-- bindings that clone the variables of the group.
 simplRecursiveGroup env new_ids pairs 
   =    -- Add unfoldings to the new_ids corresponding to their RHS
     let
@@ -1005,17 +986,33 @@ simplRecursiveGroup env new_ids pairs
                               env new_ids_w_pairs
     in
 
-    mapSmpl (\(binder,rhs) -> simplRhsExpr rhs_env binder rhs) pairs   `thenSmpl` \ new_rhss ->
+    mapSmpl (\(binder,rhs) -> simplRhsExpr rhs_env binder rhs) pairs   `thenSmpl` \ new_rhss_w_arities ->
 
     let
-       new_pairs       = zipEqual "simplRecGp" new_ids new_rhss
+       new_pairs = zipWithEqual "simplRecGp" mk_new_pair new_ids new_rhss_w_arities
+       mk_new_pair id (rhs,arity) = (id `withArity` arity, rhs)
+               -- NB: the new arity isn't used when processing its own
+               -- right hand sides, nor in the subsequent code
+               -- The latter is something of a pity, and not hard to fix; but
+               -- the info will percolate on the next iteration anyway
+
+{-     THE NEXT FEW LINES ARE PLAIN WRONG
        occs_w_new_pairs = zipEqual "simplRecGp" occs new_pairs
        new_env         = foldl add_binding env occs_w_new_pairs
 
        add_binding env (occ_info,(new_id,new_rhs)) 
          = extendEnvGivenBinding env occ_info new_id new_rhs
+
+Here's why it's wrong: consider
+       let f x = ...f x'...
+       in
+       f 3
+
+If the RHS is small we'll inline f in the body of the let, then
+again, then again...URK
+-}
     in
-    returnSmpl (Rec new_pairs, new_env)
+    returnSmpl (Rec new_pairs, rhs_env)
 \end{code}
 
 
@@ -1060,63 +1057,63 @@ x.  That's just what completeLetBinding does.
 
 
 \begin{code}
-       -- Sigh: rather disgusting case for coercions. We want to 
-       -- ensure that all let-bound Coerces have atomic bodies, so
-       -- they can freely be inlined.
-completeNonRec top_level env binder@(_,occ_info) (Coerce coercion ty rhs)
-  = (case rhs of
-       Var v -> returnSmpl (env, [], rhs)
-       Lit l -> returnSmpl (env, [], rhs)
-       other -> newId (coreExprType rhs)                       `thenSmpl` \ inner_id ->
-                completeNonRec top_level env 
-                       (inner_id, dangerousArgOcc) rhs         `thenSmpl` \ (env1, extra_bind) ->
-               -- Dangerous occ because, like constructor args,
-               -- it can be duplicated easily
-               let
-               atomic_rhs = case lookupId env1 inner_id of
-                               LitArg l -> Lit l
-                               VarArg v -> Var v
-               in
-               returnSmpl (env1, extra_bind, atomic_rhs)
-     )                         `thenSmpl` \ (env1, extra_bind, atomic_rhs) ->
-       -- Tiresome to do all this, but we must treat the lit/var cases specially
-       -- or we get a tick for atomic rhs when effectively it's a no-op.
-
-     cloneId env1 binder                                 `thenSmpl` \ new_id ->
-     let 
-       new_rhs = Coerce coercion ty atomic_rhs
-       env2    = extendIdEnvWithClone env1 binder new_id
-       new_env = extendEnvGivenBinding env2 occ_info new_id new_rhs
-     in
-     returnSmpl (new_env, extra_bind ++ [NonRec new_id new_rhs])
-       
-completeNonRec top_level env binder@(id,_) new_rhs
-  -- See if RHS is an atom, or a reusable constructor
-  | maybeToBool maybe_atomic_rhs
-  = let
-       new_env = extendIdEnvWithAtom env binder rhs_atom
-       result_binds | top_level = [NonRec id new_rhs]  -- Don't discard top-level bindings
-                                                       -- (they'll be dropped later if not
-                                                       -- exported and dead)
-                    | otherwise = []
-    in
-    tick atom_tick_type                        `thenSmpl_`
-    returnSmpl (new_env, result_binds)
-  where
-    maybe_atomic_rhs               = exprToAtom env new_rhs
-    Just (rhs_atom, atom_tick_type) = maybe_atomic_rhs
-
-completeNonRec top_level env binder@(old_id,occ_info) new_rhs
-  = (if top_level then
-       returnSmpl old_id               -- Only clone local binders
-     else
-       cloneId env binder
-    )                          `thenSmpl` \ new_id ->
+       -- We want to ensure that all let-bound Coerces have 
+       -- atomic bodies, so they can freely be inlined.
+completeNonRec env binder new_id (Coerce coercion ty rhs)
+  | not (is_atomic rhs)
+  = newId (coreExprType rhs)                           `thenSmpl` \ inner_id ->
+    completeNonRec env 
+                  (inner_id, dangerousArgOcc) inner_id rhs `thenSmpl` \ (env1, binds1) ->
+       -- Dangerous occ because, like constructor args,
+       -- it can be duplicated easily
     let
-        env1    = extendIdEnvWithClone env binder new_id
-       new_env = extendEnvGivenBinding env1 occ_info new_id new_rhs
+       atomic_rhs = case lookupId env1 inner_id of
+                       LitArg l -> Lit l
+                       VarArg v -> Var v
     in
-    returnSmpl (new_env, [NonRec new_id new_rhs])
+    completeNonRec env1 binder new_id
+                  (Coerce coercion ty atomic_rhs)      `thenSmpl` \ (env2, binds2) ->
+
+    returnSmpl (env2, binds1 ++ binds2)
+       
+       -- Right hand sides that are constructors
+       --      let v = C args
+       --      in
+       --- ...(let w = C same-args in ...)...
+       -- Then use v instead of w.      This may save
+       -- re-constructing an existing constructor.
+completeNonRec env binder new_id rhs@(Con con con_args)
+  | switchIsSet env SimplReuseCon && 
+    maybeToBool maybe_existing_con &&
+    not (isExported new_id)            -- Don't bother for exported things
+                                       -- because we won't be able to drop
+                                       -- its binding.
+  = tick ConReused             `thenSmpl_`
+    returnSmpl (extendIdEnvWithAtom env binder (VarArg it), [NonRec new_id rhs])
+  where
+    maybe_existing_con = lookForConstructor env con con_args
+    Just it           = maybe_existing_con
+
+
+       -- Default case
+       -- Check for atomic right-hand sides.
+       -- We used to have a "tick AtomicRhs" in here, but it causes more trouble
+       -- than it's worth.  For a top-level binding a = b, where a is exported,
+       -- we can't drop the binding, so we get repeated AtomicRhs ticks
+completeNonRec env binder@(id,occ_info) new_id new_rhs
+ = returnSmpl (new_env , [NonRec new_id new_rhs])
+ where
+   new_env | is_atomic eta'd_rhs               -- If rhs (after eta reduction) is atomic
+          = extendIdEnvWithAtom env binder the_arg
+
+          | otherwise                          -- Non-atomic
+          = extendEnvGivenBinding (extendIdEnvWithClone env binder new_id)
+                       occ_info new_id new_rhs -- Don't eta if it doesn't eliminate the binding
+
+   eta'd_rhs = etaCoreExpr new_rhs
+   the_arg   = case eta'd_rhs of
+                 Var v -> VarArg v
+                 Lit l -> LitArg l
 \end{code}
 
 %************************************************************************
@@ -1133,31 +1130,6 @@ simplArg env (TyArg  ty)  = TyArg  (simplTy env ty)
 simplArg env (VarArg id)  = lookupId env id
 \end{code}
 
-
-\begin{code}
-exprToAtom env (Var var) 
-  = Just (VarArg var, AtomicRhs)
-
-exprToAtom env (Lit lit) 
-  | not (isNoRepLit lit)
-  = Just (LitArg lit, AtomicRhs)
-
-exprToAtom env (Con con con_args)
-  | switchIsSet env SimplReuseCon
-  -- Look out for
-  --   let v = C args
-  --   in
-  --- ...(let w = C same-args in ...)...
-  -- Then use v instead of w.   This may save
-  -- re-constructing an existing constructor.
-  = case (lookForConstructor env con con_args) of
-                 Nothing  -> Nothing
-                 Just var -> Just (VarArg var, ConReused)
-
-exprToAtom env other
-  = Nothing
-\end{code}
-
 %************************************************************************
 %*                                                                     *
 \subsection[Simplify-quickies]{Some local help functions}
@@ -1175,7 +1147,7 @@ fix_up_demandedness False {- May not be demanded -} (NonRec binder rhs)
 fix_up_demandedness False {- May not be demanded -} (Rec pairs)
    = Rec [(un_demandify binder, rhs) | (binder,rhs) <- pairs]
 
-un_demandify (id, occ_info) = (id `addIdDemandInfo` noInfo, occ_info)
+un_demandify (id, occ_info) = (id `addIdDemandInfo` noDemandInfo, occ_info)
 
 is_cheap_prim_app (Prim op _) = primOpOkForSpeculation op
 is_cheap_prim_app other              = False
@@ -1192,5 +1164,12 @@ computeResultType env expr args
     go ty (a:args) | isValArg a = case (getFunTy_maybe ty) of
                                    Just (_, res_ty) -> go res_ty args
                                    Nothing          -> panic "computeResultType"
+
+var `withArity` UnknownArity = var
+var `withArity` arity       = var `addIdArity` arity
+
+is_atomic (Var v) = True
+is_atomic (Lit l) = not (isNoRepLit l)
+is_atomic other   = False
 \end{code}