[project @ 2000-12-11 12:15:15 by simonmar]
[ghc-hetmet.git] / ghc / compiler / simplCore / OccurAnal.lhs
index 5a7fd19..3dff2de 100644 (file)
@@ -12,38 +12,34 @@ core expression with (hopefully) improved usage information.
 
 \begin{code}
 module OccurAnal (
-       occurAnalyseBinds, occurAnalyseExpr, occurAnalyseGlobalExpr,
-       markBinderInsideLambda, tagBinders,
-       UsageDetails
+       occurAnalyseBinds, occurAnalyseGlobalExpr, occurAnalyseRule
     ) where
 
 #include "HsVersions.h"
 
 import BinderInfo
-import CmdLineOpts     ( SimplifierSwitch(..) )
 import CoreSyn
 import CoreFVs         ( idRuleVars )
 import CoreUtils       ( exprIsTrivial )
-import Literal         ( Literal(..) )
-import Id              ( isSpecPragmaId, isDataConId, isOneShotLambda, setOneShotLambda, 
+import Id              ( isDataConId, isOneShotLambda, setOneShotLambda, 
                          idOccInfo, setIdOccInfo,
                          isExportedId, modifyIdInfo, idInfo,
-                         idSpecialisation, 
+                         idSpecialisation, isLocalId,
                          idType, idUnique, Id
                        )
-import IdInfo          ( OccInfo(..), insideLam, copyIdInfo )
+import IdInfo          ( OccInfo(..), shortableIdInfo, copyIdInfo )
 
 import VarSet
 import VarEnv
 
-import ThinAir         ( noRepStrIds, noRepIntegerIds )
-import Name            ( isLocallyDefined )
 import Type            ( splitFunTy_maybe, splitForAllTys )
 import Maybes          ( maybeToBool )
 import Digraph         ( stronglyConnCompR, SCC(..) )
-import Unique          ( u2i, buildIdKey, foldrIdKey, runSTRepIdKey, augmentIdKey )
+import PrelNames       ( buildIdKey, foldrIdKey, runSTRepIdKey, augmentIdKey )
+import Unique          ( u2i )
 import UniqFM          ( keysUFM )  
-import Util            ( zipWithEqual, mapAndUnzip, count )
+import Util            ( zipWithEqual, mapAndUnzip )
+import FastTypes
 import Outputable
 \end{code}
 
@@ -72,6 +68,15 @@ occurAnalyseGlobalExpr expr
   =    -- Top level expr, so no interesting free vars, and
        -- discard occurence info returned
     snd (occurAnalyseExpr (\_ -> False) expr)
+
+occurAnalyseRule :: CoreRule -> CoreRule
+occurAnalyseRule rule@(BuiltinRule _) = rule
+occurAnalyseRule (Rule str tpl_vars tpl_args rhs)
+               -- Add occ info to tpl_vars, rhs
+  = Rule str tpl_vars' tpl_args rhs'
+  where
+    (rhs_uds, rhs') = occurAnalyseExpr isLocalId rhs
+    (_, tpl_vars')  = tagBinders rhs_uds tpl_vars
 \end{code}
 
 
@@ -83,22 +88,20 @@ occurAnalyseGlobalExpr expr
 
 In @occAnalTop@ we do indirection-shorting.  That is, if we have this:
 
-       loc = <expression>
+       x_local = <expression>
        ...
-       exp = loc
+       x_exported = loc
 
 where exp is exported, and loc is not, then we replace it with this:
 
-       loc = exp
-       exp = <expression>
+       x_local = x_exported
+       x_exported = <expression>
        ...
 
-Without this we never get rid of the exp = loc thing.
-This save a gratuitous jump
-(from \tr{x_exported} to \tr{x_local}), and makes strictness
-information propagate better.
-This used to happen in the final phase, but it's tidier to do it here.
-
+Without this we never get rid of the x_exported = x_local thing.  This
+save a gratuitous jump (from \tr{x_exported} to \tr{x_local}), and
+makes strictness information propagate better.  This used to happen in
+the final phase, but it's tidier to do it here.
 
 If more than one exported thing is equal to a local thing (i.e., the
 local thing really is shared), then we do one only:
@@ -140,7 +143,10 @@ occurAnalyseBinds binds
     go :: OccEnv -> [CoreBind]
        -> (UsageDetails,       -- Occurrence info
           IdEnv Id,            -- Indirection elimination info
-          [CoreBind])
+                               --   Maps local-id -> exported-id, but it embodies
+                               --   bindings of the form exported-id = local-id in
+                               --   the argument to go
+          [CoreBind])          -- Occ-analysed bindings, less the exported-id=local-id ones
 
     go env [] = (emptyDetails, emptyVarEnv, [])
 
@@ -166,9 +172,9 @@ occurAnalyseBinds binds
                   ind_env' = extendVarEnv ind_env local_id exported_id
 
            other ->    -- Ho ho! The normal case
-                  (final_usage, ind_env, new_binds ++ binds')
+                    (final_usage, ind_env, new_binds ++ binds')
                   
-initialTopEnv = OccEnv isLocallyDefined        -- Anything local is interesting
+initialTopEnv = OccEnv isLocalId       -- Anything local is interesting
                       emptyVarSet
                       []
 
@@ -182,27 +188,34 @@ zapBind ind_env (Rec pairs)
 
 zapBind ind_env bind = bind
 
-zap ind_env pair@(bndr,rhs)
-  = case lookupVarEnv ind_env bndr of
+zap ind_env pair@(local_id,rhs)
+  = case lookupVarEnv ind_env local_id of
        Nothing          -> [pair]
-       Just exported_id -> [(bndr, Var exported_id),
-                            (exported_id_w_info, rhs)]
-                        where
-                          exported_id_w_info = modifyIdInfo (copyIdInfo (idInfo bndr)) exported_id
-                               -- See notes with copyIdInfo about propagating IdInfo from
-                               -- one to t'other
+       Just exported_id -> [(local_id, Var exported_id),
+                            (exported_id', rhs)]
+                        where
+                           exported_id' = modifyIdInfo (copyIdInfo (idInfo local_id)) exported_id
                        
 shortMeOut ind_env exported_id local_id
-  = isExportedId exported_id &&                -- Only if this is exported
-
-    isLocallyDefined local_id &&       -- Only if this one is defined in this
-                                       --      module, so that we *can* change its
-                                       --      binding to be the exported thing!
-
-    not (isExportedId local_id) &&     -- Only if this one is not itself exported,
-                                       --      since the transformation will nuke it
-
-    not (local_id `elemVarEnv` ind_env)                -- Only if not already substituted for
+-- The if-then-else stuff is just so I can get a pprTrace to see
+-- how often I don't get shorting out becuase of IdInfo stuff
+  = if isExportedId exported_id &&             -- Only if this is exported
+
+       isLocalId local_id &&                   -- Only if this one is defined in this
+                                               --      module, so that we *can* change its
+                                               --      binding to be the exported thing!
+
+       not (isExportedId local_id) &&          -- Only if this one is not itself exported,
+                                               --      since the transformation will nuke it
+   
+       not (local_id `elemVarEnv` ind_env)     -- Only if not already substituted for
+    then
+       if shortableIdInfo (idInfo exported_id)         -- Only if its IdInfo is 'shortable'
+                                                       -- (see the defn of IdInfo.shortableIdInfo
+       then True
+       else pprTrace "shortMeOut:" (ppr exported_id) False
+    else
+       False
 \end{code}
 
 
@@ -282,8 +295,6 @@ It isn't easy to do a perfect job in one blow.  Consider
 occAnalBind env (Rec pairs) body_usage
   = foldr (_scc_ "occAnalBind.dofinal" do_final_bind) (body_usage, []) sccs
   where
-    pp_item (_, bndr, _)     = ppr bndr
-
     binders = map fst pairs
     rhs_env = env `addNewCands` binders
 
@@ -300,7 +311,7 @@ occAnalBind env (Rec pairs) body_usage
     ---- stuff for dependency analysis of binds -------------------------------
     edges :: [Node Details1]
     edges = _scc_ "occAnalBind.assoc"
-           [ (details, IBOX(u2i (idUnique id)), edges_from rhs_usage)
+           [ (details, iBox (u2i (idUnique id)), edges_from rhs_usage)
            | details@(id, rhs_usage, rhs) <- analysed_pairs
            ]
 
@@ -447,13 +458,24 @@ reOrderRec env (CyclicSCC (bind : binds))
          
     score :: Node Details2 -> Int      -- Higher score => less likely to be picked as loop breaker
     score ((bndr, rhs), _, _)
-       | exprIsTrivial rhs && 
-         not (isExportedId bndr)  = 3          -- Practically certain to be inlined
-       | inlineCandidate bndr rhs = 3          -- Likely to be inlined
-       | not_fun_ty (idType bndr) = 2          -- Data types help with cases
+       | exprIsTrivial rhs        = 4  -- Practically certain to be inlined
+               -- Used to have also: && not (isExportedId bndr)
+               -- But I found this sometimes cost an extra iteration when we have
+               --      rec { d = (a,b); a = ...df...; b = ...df...; df = d }
+               -- where df is the exported dictionary. Then df makes a really
+               -- bad choice for loop breaker
+         
+       | not_fun_ty (idType bndr) = 3  -- Data types help with cases
+               -- This used to have a lower score than inlineCandidate, but
+               -- it's *really* helpful if dictionaries get inlined fast,
+               -- so I'm experimenting with giving higher priority to data-typed things
+
+       | inlineCandidate bndr rhs = 2  -- Likely to be inlined
+
        | not (isEmptyCoreRules (idSpecialisation bndr)) = 1
                -- Avoid things with specialisations; we'd like
                -- to take advantage of them in the subsequent bindings
+
        | otherwise = 0
 
     inlineCandidate :: Id -> CoreExpr -> Bool
@@ -609,8 +631,8 @@ occAnal env expr@(Lam _ _)
     (really_final_usage,
      mkLams tagged_binders body') }
   where
-    (binders, body)    = collectBinders expr
-    (linear, env_body, binders') = oneShotGroup env binders
+    (binders, body)       = collectBinders expr
+    (linear, env_body, _) = oneShotGroup env binders
 
 occAnal env (Case scrut bndr alts)
   = case mapAndUnzip (occAnalAlt alt_env) alts of { (alts_usage_s, alts')   -> 
@@ -807,8 +829,6 @@ addOneOcc usage id info
 
 emptyDetails = (emptyVarEnv :: UsageDetails)
 
-unitDetails id info = (unitVarEnv id info :: UsageDetails)
-
 usedIn :: Id -> UsageDetails -> Bool
 v `usedIn` details =  isExportedId v || v `elemVarEnv` details
 
@@ -854,15 +874,5 @@ setBinderOcc usage bndr
                 Nothing   -> IAmDead
                 Just info -> binderInfoToOccInfo info
 
-markBinderInsideLambda :: CoreBndr -> CoreBndr
-markBinderInsideLambda bndr
-  | isTyVar bndr
-  = bndr
-
-  | otherwise
-  = case idOccInfo bndr of
-       OneOcc _ once -> bndr `setIdOccInfo` OneOcc insideLam once
-       other         -> bndr
-
 funOccZero = funOccurrence 0
 \end{code}