Remove the (very) old strictness analyser
[ghc-hetmet.git] / compiler / simplCore / SimplCore.lhs
index 2fd1026..beb1ed0 100644 (file)
@@ -4,37 +4,48 @@
 \section[SimplCore]{Driver for simplifying @Core@ programs}
 
 \begin{code}
 \section[SimplCore]{Driver for simplifying @Core@ programs}
 
 \begin{code}
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
 module SimplCore ( core2core, simplifyExpr ) where
 
 #include "HsVersions.h"
 
 import DynFlags                ( CoreToDo(..), SimplifierSwitch(..),
                          SimplifierMode(..), DynFlags, DynFlag(..), dopt,
 module SimplCore ( core2core, simplifyExpr ) where
 
 #include "HsVersions.h"
 
 import DynFlags                ( CoreToDo(..), SimplifierSwitch(..),
                          SimplifierMode(..), DynFlags, DynFlag(..), dopt,
-                         getCoreToDo )
+                         getCoreToDo, shouldDumpSimplPhase )
 import CoreSyn
 import CoreSyn
-import HscTypes                ( HscEnv(..), ModGuts(..), ExternalPackageState(..),
-                         Dependencies( dep_mods ), 
-                         hscEPS, hptRules )
+import CoreSubst
+import HscTypes
 import CSE             ( cseProgram )
 import Rules           ( RuleBase, emptyRuleBase, mkRuleBase, unionRuleBase,
 import CSE             ( cseProgram )
 import Rules           ( RuleBase, emptyRuleBase, mkRuleBase, unionRuleBase,
-                         extendRuleBaseList, pprRuleBase, ruleCheckProgram,
+                         extendRuleBaseList, pprRuleBase, pprRulesForUser,
+                         ruleCheckProgram, rulesOfBinds,
                          addSpecInfo, addIdSpecialisations )
 import PprCore         ( pprCoreBindings, pprCoreExpr, pprRules )
 import OccurAnal       ( occurAnalysePgm, occurAnalyseExpr )
                          addSpecInfo, addIdSpecialisations )
 import PprCore         ( pprCoreBindings, pprCoreExpr, pprRules )
 import OccurAnal       ( occurAnalysePgm, occurAnalyseExpr )
-import IdInfo          ( setNewStrictnessInfo, newStrictnessInfo, 
-                         setWorkerInfo, workerInfo,
-                         setInlinePragInfo, inlinePragInfo,
-                         setSpecInfo, specInfo, specInfoRules )
+import IdInfo
 import CoreUtils       ( coreBindsSize )
 import Simplify                ( simplTopBinds, simplExpr )
 import CoreUtils       ( coreBindsSize )
 import Simplify                ( simplTopBinds, simplExpr )
-import SimplEnv                ( SimplEnv, simplBinders, mkSimplEnv, setInScopeSet )
+import SimplUtils      ( simplEnvForGHCi, simplEnvForRules )
+import SimplEnv
 import SimplMonad
 import SimplMonad
-import ErrUtils                ( dumpIfSet, dumpIfSet_dyn, showPass )
-import CoreLint                ( endPass )
+import CoreMonad
+import qualified ErrUtils as Err 
+import CoreLint
+import CoreMonad       ( endPass )
 import FloatIn         ( floatInwards )
 import FloatOut                ( floatOutwards )
 import FloatIn         ( floatInwards )
 import FloatOut                ( floatOutwards )
-import Id              ( Id, modifyIdInfo, idInfo, isExportedId, isLocalId,
-                         idSpecialisation, idName )
+import FamInstEnv
+import Id
+import DataCon
+import TyCon           ( tyConDataCons )
+import Class           ( classSelIds )
+import BasicTypes       ( CompilerPhase, isActive, isDefaultInlinePragma )
 import VarSet
 import VarEnv
 import NameEnv         ( lookupNameEnv )
 import VarSet
 import VarEnv
 import NameEnv         ( lookupNameEnv )
@@ -44,16 +55,16 @@ import Specialise   ( specProgram)
 import SpecConstr      ( specConstrProgram)
 import DmdAnal         ( dmdAnalPgm )
 import WorkWrap                ( wwTopBinds )
 import SpecConstr      ( specConstrProgram)
 import DmdAnal         ( dmdAnalPgm )
 import WorkWrap                ( wwTopBinds )
-#ifdef OLD_STRICTNESS
-import StrictAnal      ( saBinds )
-import CprAnalyse       ( cprAnalyse )
-#endif
+import Vectorise        ( vectorise )
+import FastString
+import Util
 
 import UniqSupply      ( UniqSupply, mkSplitUniqSupply, splitUniqSupply )
 
 import UniqSupply      ( UniqSupply, mkSplitUniqSupply, splitUniqSupply )
-import IO              ( hPutStr, stderr )
 import Outputable
 import Outputable
-import List            ( partition )
-import Maybes          ( orElse )
+import Control.Monad
+import Data.List
+import System.IO
+import Maybes
 \end{code}
 
 %************************************************************************
 \end{code}
 
 %************************************************************************
@@ -67,136 +78,211 @@ core2core :: HscEnv
          -> ModGuts
          -> IO ModGuts
 
          -> ModGuts
          -> IO ModGuts
 
-core2core hsc_env guts
-  = do
-        let dflags = hsc_dflags hsc_env
-           core_todos = getCoreToDo dflags
+core2core hsc_env guts = do
+    let dflags = hsc_dflags hsc_env
+
+    us <- mkSplitUniqSupply 's'
+    let (cp_us, ru_us) = splitUniqSupply us
+
+    -- COMPUTE THE ANNOTATIONS TO USE
+    ann_env <- prepareAnnotations hsc_env (Just guts)
 
 
-       us <- mkSplitUniqSupply 's'
-       let (cp_us, ru_us) = splitUniqSupply us
+    -- COMPUTE THE RULE BASE TO USE
+    (hpt_rule_base, guts1) <- prepareRules hsc_env guts ru_us
 
 
-               -- COMPUTE THE RULE BASE TO USE
-       (imp_rule_base, guts') <- prepareRules hsc_env guts ru_us
+    -- Get the module out of the current HscEnv so we can retrieve it from the monad.
+    -- This is very convienent for the users of the monad (e.g. plugins do not have to
+    -- consume the ModGuts to find the module) but somewhat ugly because mg_module may
+    -- _theoretically_ be changed during the Core pipeline (it's part of ModGuts), which
+    -- would mean our cached value would go out of date.
+    let mod = mg_module guts
+    (guts2, stats) <- runCoreM hsc_env ann_env hpt_rule_base cp_us mod $ do
+        -- FIND BUILT-IN PASSES
+        let builtin_core_todos = getCoreToDo dflags
 
 
-               -- DO THE BUSINESS
-       (stats, guts'') <- doCorePasses hsc_env imp_rule_base cp_us
-                                       (zeroSimplCount dflags) 
-                                       guts' core_todos
+        -- DO THE BUSINESS
+        doCorePasses builtin_core_todos guts1
 
 
-       dumpIfSet_dyn dflags Opt_D_dump_simpl_stats
-                 "Grand total simplifier statistics"
-                 (pprSimplCount stats)
+    Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_stats
+        "Grand total simplifier statistics"
+        (pprSimplCount stats)
 
 
-       return guts''
+    return guts2
 
 
 
 
+type CorePass = CoreToDo
+
 simplifyExpr :: DynFlags -- includes spec of what core-to-core passes to do
             -> CoreExpr
             -> IO CoreExpr
 -- simplifyExpr is called by the driver to simplify an
 -- expression typed in at the interactive prompt
 simplifyExpr :: DynFlags -- includes spec of what core-to-core passes to do
             -> CoreExpr
             -> IO CoreExpr
 -- simplifyExpr is called by the driver to simplify an
 -- expression typed in at the interactive prompt
+--
+-- Also used by Template Haskell
 simplifyExpr dflags expr
   = do {
 simplifyExpr dflags expr
   = do {
-       ; showPass dflags "Simplify"
+       ; Err.showPass dflags "Simplify"
 
        ; us <-  mkSplitUniqSupply 's'
 
 
        ; us <-  mkSplitUniqSupply 's'
 
-       ; let (expr', _counts) = initSmpl dflags us $
-                                simplExprGently gentleSimplEnv expr
+       ; let (expr', _counts) = initSmpl dflags emptyRuleBase emptyFamInstEnvs us $
+                                simplExprGently simplEnvForGHCi expr
 
 
-       ; dumpIfSet_dyn dflags Opt_D_dump_simpl "Simplified expression"
+       ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl "Simplified expression"
                        (pprCoreExpr expr')
 
        ; return expr'
        }
 
                        (pprCoreExpr expr')
 
        ; return expr'
        }
 
-gentleSimplEnv :: SimplEnv
-gentleSimplEnv = mkSimplEnv SimplGently 
-                           (isAmongSimpl [])
-                           emptyRuleBase
-
-doCorePasses :: HscEnv
-             -> RuleBase        -- the imported main rule base
-             -> UniqSupply      -- uniques
-            -> SimplCount      -- simplifier stats
-             -> ModGuts                -- local binds in (with rules attached)
-             -> [CoreToDo]      -- which passes to do
-             -> IO (SimplCount, ModGuts)
-
-doCorePasses hsc_env rb us stats guts []
-  = return (stats, guts)
-
-doCorePasses hsc_env rb us stats guts (to_do : to_dos) 
-  = do
-       let (us1, us2) = splitUniqSupply us
-       (stats1, guts1) <- doCorePass to_do hsc_env us1 rb guts
-       doCorePasses hsc_env rb us2 (stats `plusSimplCount` stats1) guts1 to_dos
-
-doCorePass (CoreDoSimplify mode sws)   = _scc_ "Simplify"      simplifyPgm mode sws
-doCorePass CoreCSE                    = _scc_ "CommonSubExpr" trBinds  cseProgram
-doCorePass CoreLiberateCase           = _scc_ "LiberateCase"  trBinds  liberateCase
-doCorePass CoreDoFloatInwards          = _scc_ "FloatInwards"  trBinds  floatInwards
-doCorePass (CoreDoFloatOutwards f)     = _scc_ "FloatOutwards" trBindsU (floatOutwards f)
-doCorePass CoreDoStaticArgs           = _scc_ "StaticArgs"    trBinds  doStaticArgs
-doCorePass CoreDoStrictness           = _scc_ "Stranal"       trBinds  dmdAnalPgm
-doCorePass CoreDoWorkerWrapper         = _scc_ "WorkWrap"      trBindsU wwTopBinds
-doCorePass CoreDoSpecialising          = _scc_ "Specialise"    trBindsU specProgram
-doCorePass CoreDoSpecConstr           = _scc_ "SpecConstr"    trBindsU specConstrProgram
-doCorePass CoreDoGlomBinds            = trBinds glomBinds
-doCorePass CoreDoPrintCore            = observe printCore
-doCorePass (CoreDoRuleCheck phase pat) = observe (ruleCheck phase pat)
-doCorePass CoreDoNothing              = observe (\ _ _ -> return ())
-#ifdef OLD_STRICTNESS                 
-doCorePass CoreDoOldStrictness        = _scc_ "OldStrictness" trBinds doOldStrictness
-#endif
-
-#ifdef OLD_STRICTNESS
-doOldStrictness dfs binds
-  = do binds1 <- saBinds dfs binds
-       binds2 <- cprAnalyse dfs binds1
-       return binds2
-#endif
-
-printCore _ binds = dumpIfSet True "Print Core" (pprCoreBindings binds)
-
-ruleCheck phase pat dflags binds = do showPass dflags "RuleCheck"
-                                     printDump (ruleCheckProgram phase pat binds)
-
--- Most passes return no stats and don't change rules
-trBinds :: (DynFlags -> [CoreBind] -> IO [CoreBind])
-       -> HscEnv -> UniqSupply -> RuleBase -> ModGuts
-       -> IO (SimplCount, ModGuts)
-trBinds do_pass hsc_env us rb guts
-  = do { binds' <- do_pass dflags (mg_binds guts)
-       ; return (zeroSimplCount dflags, guts { mg_binds = binds' }) }
-  where
-    dflags = hsc_dflags hsc_env
-
-trBindsU :: (DynFlags -> UniqSupply -> [CoreBind] -> IO [CoreBind])
-       -> HscEnv -> UniqSupply -> RuleBase -> ModGuts
-       -> IO (SimplCount, ModGuts)
-trBindsU do_pass hsc_env us rb guts
-  = do { binds' <- do_pass dflags us (mg_binds guts)
-       ; return (zeroSimplCount dflags, guts { mg_binds = binds' }) }
-  where
-    dflags = hsc_dflags hsc_env
+doCorePasses :: [CorePass] -> ModGuts -> CoreM ModGuts
+doCorePasses passes guts = foldM (flip doCorePass) guts passes
 
 
--- Observer passes just peek; don't modify the bindings at all
-observe :: (DynFlags -> [CoreBind] -> IO a)
-       -> HscEnv -> UniqSupply -> RuleBase -> ModGuts
-       -> IO (SimplCount, ModGuts)
-observe do_pass hsc_env us rb guts 
-  = do { binds <- do_pass dflags (mg_binds guts)
-       ; return (zeroSimplCount dflags, guts) }
-  where
-    dflags = hsc_dflags hsc_env
+doCorePass :: CorePass -> ModGuts -> CoreM ModGuts
+doCorePass (CoreDoSimplify mode sws) = {-# SCC "Simplify" #-}
+                                       simplifyPgm mode sws
+
+doCorePass CoreCSE                   = {-# SCC "CommonSubExpr" #-}   
+                                      describePass "Common sub-expression" Opt_D_dump_cse $ 
+                                      doPass cseProgram
+
+doCorePass CoreLiberateCase          = {-# SCC "LiberateCase" #-}
+                                      describePass "Liberate case" Opt_D_verbose_core2core $ 
+                                       doPassD liberateCase
+
+doCorePass CoreDoFloatInwards        = {-# SCC "FloatInwards" #-}
+                                       describePass "Float inwards" Opt_D_verbose_core2core $ 
+                                       doPass floatInwards
+
+doCorePass (CoreDoFloatOutwards f)   = {-# SCC "FloatOutwards" #-}
+                                       describePassD (text "Float out" <+> parens (ppr f)) 
+                                                     Opt_D_verbose_core2core $ 
+                                       doPassDUM (floatOutwards f)
+
+doCorePass CoreDoStaticArgs          = {-# SCC "StaticArgs" #-}
+                                       describePass "Static argument" Opt_D_verbose_core2core $ 
+                                       doPassU doStaticArgs
+
+doCorePass CoreDoStrictness          = {-# SCC "Stranal" #-}
+                                       describePass "Demand analysis" Opt_D_dump_stranal $
+                                       doPassDM dmdAnalPgm
+
+doCorePass CoreDoWorkerWrapper       = {-# SCC "WorkWrap" #-}
+                                       describePass "Worker Wrapper binds" Opt_D_dump_worker_wrapper $
+                                       doPassU wwTopBinds
+
+doCorePass CoreDoSpecialising        = {-# SCC "Specialise" #-}
+                                       describePassR "Specialise" Opt_D_dump_spec $ 
+                                       doPassU specProgram
+
+doCorePass CoreDoSpecConstr          = {-# SCC "SpecConstr" #-}
+                                       describePassR "SpecConstr" Opt_D_dump_spec $
+                                       specConstrProgram
+
+doCorePass (CoreDoVectorisation be)  = {-# SCC "Vectorise" #-}
+                                       describePass "Vectorisation" Opt_D_dump_vect $ 
+                                       vectorise be
+
+doCorePass CoreDoGlomBinds              = dontDescribePass $ doPassDM  glomBinds
+doCorePass CoreDoPrintCore              = dontDescribePass $ observe   printCore
+doCorePass (CoreDoRuleCheck phase pat)  = dontDescribePass $ ruleCheck phase pat
+
+doCorePass CoreDoNothing                = return
+doCorePass (CoreDoPasses passes)        = doCorePasses passes
 \end{code}
 
 \end{code}
 
+%************************************************************************
+%*                                                                     *
+\subsection{Core pass combinators}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+
+dontDescribePass :: (ModGuts -> CoreM ModGuts) -> ModGuts -> CoreM ModGuts
+dontDescribePass = ($)
+
+describePass :: String -> DynFlag -> (ModGuts -> CoreM ModGuts) -> ModGuts -> CoreM ModGuts
+describePass name dflag pass guts = do
+    dflags <- getDynFlags
+    
+    liftIO $ Err.showPass dflags name
+    guts' <- pass guts
+    liftIO $ endPass dflags name dflag (mg_binds guts') (mg_rules guts')
+
+    return guts'
+
+describePassD :: SDoc -> DynFlag -> (ModGuts -> CoreM ModGuts) -> ModGuts -> CoreM ModGuts
+describePassD doc = describePass (showSDoc doc)
+
+describePassR :: String -> DynFlag -> (ModGuts -> CoreM ModGuts) -> ModGuts -> CoreM ModGuts
+describePassR name dflag pass guts = do
+    guts' <- describePass name dflag pass guts
+    dumpIfSet_dyn Opt_D_dump_rules "Top-level specialisations"
+                (pprRulesForUser (rulesOfBinds (mg_binds guts')))
+    return guts'
+
+printCore _ binds = Err.dumpIfSet True "Print Core" (pprCoreBindings binds)
+
+ruleCheck :: CompilerPhase -> String -> ModGuts -> CoreM ModGuts
+ruleCheck current_phase pat guts = do
+    let is_active = isActive current_phase
+    rb <- getRuleBase
+    dflags <- getDynFlags
+    liftIO $ Err.showPass dflags "RuleCheck"
+    liftIO $ printDump (ruleCheckProgram is_active pat rb (mg_binds guts))
+    return guts
+
+
+doPassDMS :: (DynFlags -> [CoreBind] -> IO (SimplCount, [CoreBind])) -> ModGuts -> CoreM ModGuts
+doPassDMS do_pass = doPassM $ \binds -> do
+    dflags <- getDynFlags
+    liftIOWithCount $ do_pass dflags binds
+
+doPassDUM :: (DynFlags -> UniqSupply -> [CoreBind] -> IO [CoreBind]) -> ModGuts -> CoreM ModGuts
+doPassDUM do_pass = doPassM $ \binds -> do
+    dflags <- getDynFlags
+    us     <- getUniqueSupplyM
+    liftIO $ do_pass dflags us binds
+
+doPassDM :: (DynFlags -> [CoreBind] -> IO [CoreBind]) -> ModGuts -> CoreM ModGuts
+doPassDM do_pass = doPassDUM (\dflags -> const (do_pass dflags))
+
+doPassD :: (DynFlags -> [CoreBind] -> [CoreBind]) -> ModGuts -> CoreM ModGuts
+doPassD do_pass = doPassDM (\dflags -> return . do_pass dflags)
+
+doPassDU :: (DynFlags -> UniqSupply -> [CoreBind] -> [CoreBind]) -> ModGuts -> CoreM ModGuts
+doPassDU do_pass = doPassDUM (\dflags us -> return . do_pass dflags us)
+
+doPassU :: (UniqSupply -> [CoreBind] -> [CoreBind]) -> ModGuts -> CoreM ModGuts
+doPassU do_pass = doPassDU (const do_pass)
+
+-- Most passes return no stats and don't change rules: these combinators
+-- let us lift them to the full blown ModGuts+CoreM world
+doPassM :: Monad m => ([CoreBind] -> m [CoreBind]) -> ModGuts -> m ModGuts
+doPassM bind_f guts = do
+    binds' <- bind_f (mg_binds guts)
+    return (guts { mg_binds = binds' })
+
+doPassMG :: Monad m => (ModGuts -> m [CoreBind]) -> ModGuts -> m ModGuts
+doPassMG bind_f guts = do
+    binds' <- bind_f guts
+    return (guts { mg_binds = binds' })
+
+doPass :: ([CoreBind] -> [CoreBind]) -> ModGuts -> CoreM ModGuts
+doPass bind_f guts = return $ guts { mg_binds = bind_f (mg_binds guts) }
+
+-- Observer passes just peek; don't modify the bindings at all
+observe :: (DynFlags -> [CoreBind] -> IO a) -> ModGuts -> CoreM ModGuts
+observe do_pass = doPassM $ \binds -> do
+    dflags <- getDynFlags
+    liftIO $ do_pass dflags binds
+    return binds
+\end{code}
 
 
 %************************************************************************
 %*                                                                     *
 
 
 %************************************************************************
 %*                                                                     *
-\subsection{Dealing with rules}
+       Dealing with rules
 %*                                                                     *
 %************************************************************************
 
 %*                                                                     *
 %************************************************************************
 
@@ -215,89 +301,103 @@ prepareRules :: HscEnv
 
                    ModGuts)            -- Modified fields are 
                                        --      (a) Bindings have rules attached,
 
                    ModGuts)            -- Modified fields are 
                                        --      (a) Bindings have rules attached,
+                                       --              and INLINE rules simplified
                                        --      (b) Rules are now just orphan rules
 
 prepareRules hsc_env@(HscEnv { hsc_dflags = dflags, hsc_HPT = hpt })
                                        --      (b) Rules are now just orphan rules
 
 prepareRules hsc_env@(HscEnv { hsc_dflags = dflags, hsc_HPT = hpt })
-            guts@(ModGuts { mg_binds = binds, mg_deps = deps, mg_rules = local_rules })
+            guts@(ModGuts { mg_binds = binds, mg_deps = deps 
+                          , mg_rules = local_rules, mg_rdr_env = rdr_env })
             us 
             us 
-  = do { let   -- Simplify the local rules; boringly, we need to make an in-scope set
+  = do { us <- mkSplitUniqSupply 'w'
+
+       ; let   -- Simplify the local rules; boringly, we need to make an in-scope set
                -- from the local binders, to avoid warnings from Simplify.simplVar
              local_ids        = mkInScopeSet (mkVarSet (bindersOfBinds binds))
                -- from the local binders, to avoid warnings from Simplify.simplVar
              local_ids        = mkInScopeSet (mkVarSet (bindersOfBinds binds))
-             env              = setInScopeSet gentleSimplEnv local_ids 
-             (better_rules,_) = initSmpl dflags us (mapSmpl (simplRule env) local_rules)
-             home_pkg_rules   = hptRules hsc_env (dep_mods deps)
-
-               -- Find the rules for locally-defined Ids; then we can attach them
-               -- to the binders in the top-level bindings
-               -- 
-               -- Reason
-               --      - It makes the rules easier to look up
-               --      - It means that transformation rules and specialisations for
-               --        locally defined Ids are handled uniformly
-               --      - It keeps alive things that are referred to only from a rule
-               --        (the occurrence analyser knows about rules attached to Ids)
-               --      - It makes sure that, when we apply a rule, the free vars
-               --        of the RHS are more likely to be in scope
-               --      - The imported rules are carried in the in-scope set
-               --        which is extended on each iteration by the new wave of
-               --        local binders; any rules which aren't on the binding will
-               --        thereby get dropped
-             (rules_for_locals, rules_for_imps) = partition isLocalRule better_rules
-             local_rule_base = extendRuleBaseList emptyRuleBase rules_for_locals
-             binds_w_rules   = updateBinders local_rule_base binds
-
-             hpt_rule_base = mkRuleBase home_pkg_rules
-             imp_rule_base = extendRuleBaseList hpt_rule_base rules_for_imps
-
-       ; dumpIfSet_dyn dflags Opt_D_dump_rules "Transformation rules"
-               (vcat [text "Local rules", pprRules better_rules,
-                      text "",
-                      text "Imported rules", pprRuleBase imp_rule_base])
-
-       ; return (imp_rule_base, guts { mg_binds = binds_w_rules, 
+             env              = setInScopeSet simplEnvForRules local_ids 
+             (simpl_rules, _) = initSmpl dflags emptyRuleBase emptyFamInstEnvs us $
+                                mapM (simplRule env) local_rules
+
+       ; let (rules_for_locals, rules_for_imps) = partition isLocalRule simpl_rules
+
+             home_pkg_rules = hptRules hsc_env (dep_mods deps)
+             hpt_rule_base  = mkRuleBase home_pkg_rules
+             binds_w_rules  = updateBinders rules_for_locals binds
+
+
+       ; Err.dumpIfSet_dyn dflags Opt_D_dump_rules "Transformation rules"
+               (withPprStyle (mkUserStyle (mkPrintUnqualified dflags rdr_env) AllTheWay) $
+                vcat [text "Local rules", pprRules simpl_rules,
+                      blankLine,
+                      text "Imported rules", pprRuleBase hpt_rule_base])
+
+       ; return (hpt_rule_base, guts { mg_binds = binds_w_rules, 
                                        mg_rules = rules_for_imps })
     }
 
                                        mg_rules = rules_for_imps })
     }
 
-updateBinders :: RuleBase -> [CoreBind] -> [CoreBind]
-updateBinders local_rules binds
-  = map update_bndrs binds
+-- Note [Attach rules to local ids]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-- Find the rules for locally-defined Ids; then we can attach them
+-- to the binders in the top-level bindings
+-- 
+-- Reason
+--     - It makes the rules easier to look up
+--     - It means that transformation rules and specialisations for
+--       locally defined Ids are handled uniformly
+--     - It keeps alive things that are referred to only from a rule
+--       (the occurrence analyser knows about rules attached to Ids)
+--     - It makes sure that, when we apply a rule, the free vars
+--       of the RHS are more likely to be in scope
+--     - The imported rules are carried in the in-scope set
+--       which is extended on each iteration by the new wave of
+--       local binders; any rules which aren't on the binding will
+--       thereby get dropped
+
+updateBinders :: [CoreRule] -> [CoreBind] -> [CoreBind]
+updateBinders rules_for_locals binds
+  = map update_bind binds
   where
   where
-    update_bndrs (NonRec b r) = NonRec (update_bndr b) r
-    update_bndrs (Rec prs)    = Rec [(update_bndr b, r) | (b,r) <- prs]
-
-    update_bndr bndr = case lookupNameEnv local_rules (idName bndr) of
-                         Nothing    -> bndr
-                         Just rules -> bndr `addIdSpecialisations` rules
-                               -- The binder might have some existing rules,
-                               -- arising from specialisation pragmas
+    local_rules = extendRuleBaseList emptyRuleBase rules_for_locals
+
+    update_bind (NonRec b r) = NonRec (add_rules b) r
+    update_bind (Rec prs)    = Rec (mapFst add_rules prs)
+
+       -- See Note [Attach rules to local ids]
+       -- NB: the binder might have some existing rules,
+       -- arising from specialisation pragmas
+    add_rules bndr
+       | Just rules <- lookupNameEnv local_rules (idName bndr)
+       = bndr `addIdSpecialisations` rules
+       | otherwise
+       = bndr
 \end{code}
 
 \end{code}
 
-
-We must do some gentle simplification on the template (but not the RHS)
-of each rule.  The case that forced me to add this was the fold/build rule,
+Note [Simplifying the left-hand side of a RULE]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We must do some gentle simplification on the lhs (template) of each
+rule.  The case that forced me to add this was the fold/build rule,
 which without simplification looked like:
        fold k z (build (/\a. g a))  ==>  ...
 This doesn't match unless you do eta reduction on the build argument.
 which without simplification looked like:
        fold k z (build (/\a. g a))  ==>  ...
 This doesn't match unless you do eta reduction on the build argument.
+Similarly for a LHS like
+       augment g (build h) 
+we do not want to get
+       augment (\a. g a) (build h)
+otherwise we don't match when given an argument like
+       augment (\a. h a a) (build h)
+
+The simplifier does indeed do eta reduction (it's in
+Simplify.completeLam) but only if -O is on.
 
 \begin{code}
 
 \begin{code}
+simplRule :: SimplEnv -> CoreRule -> SimplM CoreRule
 simplRule env rule@(BuiltinRule {})
 simplRule env rule@(BuiltinRule {})
-  = returnSmpl rule
+  = return rule
 simplRule env rule@(Rule { ru_bndrs = bndrs, ru_args = args, ru_rhs = rhs })
 simplRule env rule@(Rule { ru_bndrs = bndrs, ru_args = args, ru_rhs = rhs })
-  = simplBinders env bndrs             `thenSmpl` \ (env, bndrs') -> 
-    mapSmpl (simplExprGently env) args `thenSmpl` \ args' ->
-    simplExprGently env rhs            `thenSmpl` \ rhs' ->
-    returnSmpl (rule { ru_bndrs = bndrs', ru_args = args', ru_rhs = rhs' })
-
--- It's important that simplExprGently does eta reduction.
--- For example, in a rule like:
---     augment g (build h) 
--- we do not want to get
---     augment (\a. g a) (build h)
--- otherwise we don't match when given an argument like
---     (\a. h a a)
---
--- The simplifier does indeed do eta reduction (it's in
--- Simplify.completeLam) but only if -O is on.
+  = do (env, bndrs') <- simplBinders env bndrs
+       args' <- mapM (simplExprGently env) args
+       rhs' <- simplExprGently env rhs
+       return (rule { ru_bndrs = bndrs', ru_args = args'
+                    , ru_rhs = occurAnalyseExpr rhs' })
 \end{code}
 
 \begin{code}
 \end{code}
 
 \begin{code}
@@ -308,13 +408,19 @@ simplExprGently :: SimplEnv -> CoreExpr -> SimplM CoreExpr
 --     alone leaves tons of crud.
 -- Used (a) for user expressions typed in at the interactive prompt
 --     (b) the LHS and RHS of a RULE
 --     alone leaves tons of crud.
 -- Used (a) for user expressions typed in at the interactive prompt
 --     (b) the LHS and RHS of a RULE
+--     (c) Template Haskell splices
 --
 -- The name 'Gently' suggests that the SimplifierMode is SimplGently,
 -- and in fact that is so.... but the 'Gently' in simplExprGently doesn't
 -- enforce that; it just simplifies the expression twice
 
 --
 -- The name 'Gently' suggests that the SimplifierMode is SimplGently,
 -- and in fact that is so.... but the 'Gently' in simplExprGently doesn't
 -- enforce that; it just simplifies the expression twice
 
-simplExprGently env expr
-  = simplExpr env (occurAnalyseExpr expr)      `thenSmpl` \ expr1 ->
+-- It's important that simplExprGently does eta reduction; see
+-- Note [Simplifying the left-hand side of a RULE] above.  The
+-- simplifier does indeed do eta reduction (it's in Simplify.completeLam)
+-- but only if -O is on.
+
+simplExprGently env expr = do
+    expr1 <- simplExpr env (occurAnalyseExpr expr)
     simplExpr env (occurAnalyseExpr expr1)
 \end{code}
 
     simplExpr env (occurAnalyseExpr expr1)
 \end{code}
 
@@ -353,7 +459,7 @@ glomBinds :: DynFlags -> [CoreBind] -> IO [CoreBind]
 -- analyser as free in f.
 
 glomBinds dflags binds
 -- analyser as free in f.
 
 glomBinds dflags binds
-  = do { showPass dflags "GlomBinds" ;
+  = do { Err.showPass dflags "GlomBinds" ;
         let { recd_binds = [Rec (flattenBinds binds)] } ;
         return recd_binds }
        -- Not much point in printing the result... 
         let { recd_binds = [Rec (flattenBinds binds)] } ;
         return recd_binds }
        -- Not much point in printing the result... 
@@ -368,66 +474,74 @@ glomBinds dflags binds
 %************************************************************************
 
 \begin{code}
 %************************************************************************
 
 \begin{code}
-simplifyPgm :: SimplifierMode
-           -> [SimplifierSwitch]
-           -> HscEnv
-           -> UniqSupply
-           -> RuleBase
-           -> ModGuts
-           -> IO (SimplCount, ModGuts)  -- New bindings
-
-simplifyPgm mode switches hsc_env us imp_rule_base guts
+simplifyPgm :: SimplifierMode -> [SimplifierSwitch] -> ModGuts -> CoreM ModGuts
+simplifyPgm mode switches
+  = describePassD doc Opt_D_dump_simpl_phases $ \guts -> 
+    do { hsc_env <- getHscEnv
+       ; us <- getUniqueSupplyM
+       ; rb <- getRuleBase
+       ; liftIOWithCount $  
+                simplifyPgmIO mode switches hsc_env us rb guts }
+  where
+    doc = ptext (sLit "Simplifier Phase") <+> text (showPpr mode) 
+
+simplifyPgmIO :: SimplifierMode
+             -> [SimplifierSwitch]
+             -> HscEnv
+             -> UniqSupply
+             -> RuleBase
+             -> ModGuts
+             -> IO (SimplCount, ModGuts)  -- New bindings
+
+simplifyPgmIO mode switches hsc_env us hpt_rule_base 
+              guts@(ModGuts { mg_binds = binds, mg_rules = rules
+                            , mg_fam_inst_env = fam_inst_env })
   = do {
   = do {
-       showPass dflags "Simplify";
-
-       (termination_msg, it_count, counts_out, binds') 
-          <- do_iteration us 1 (zeroSimplCount dflags) (mg_binds guts) ;
+       (termination_msg, it_count, counts_out, guts') 
+          <- do_iteration us 1 (zeroSimplCount dflags) binds rules ;
 
 
-       dumpIfSet (dopt Opt_D_verbose_core2core dflags 
-                   && dopt Opt_D_dump_simpl_stats dflags)
-                 "Simplifier statistics"
+       Err.dumpIfSet (dump_phase && dopt Opt_D_dump_simpl_stats dflags)
+                 "Simplifier statistics for following pass"
                  (vcat [text termination_msg <+> text "after" <+> ppr it_count <+> text "iterations",
                  (vcat [text termination_msg <+> text "after" <+> ppr it_count <+> text "iterations",
-                        text "",
+                        blankLine,
                         pprSimplCount counts_out]);
 
                         pprSimplCount counts_out]);
 
-       endPass dflags ("Simplify phase " ++ phase_info ++ " done") Opt_D_verbose_core2core binds';
-
-       return (counts_out, guts { mg_binds = binds' })
+       return (counts_out, guts')
     }
   where
     }
   where
-    dflags        = hsc_dflags hsc_env
-    phase_info    = case mode of
-                         SimplGently  -> "gentle"
-                         SimplPhase n -> show n
+    dflags              = hsc_dflags hsc_env
+    dump_phase          = shouldDumpSimplPhase dflags mode
                   
     sw_chkr       = isAmongSimpl switches
     max_iterations = intSwitchSet sw_chkr MaxSimplifierIterations `orElse` 2
  
                   
     sw_chkr       = isAmongSimpl switches
     max_iterations = intSwitchSet sw_chkr MaxSimplifierIterations `orElse` 2
  
-    do_iteration us iteration_no counts binds
+    do_iteration :: UniqSupply
+                 -> Int                -- Counts iterations
+                -> SimplCount  -- Logs optimisations performed
+                -> [CoreBind]  -- Bindings in
+                -> [CoreRule]  -- and orphan rules
+                -> IO (String, Int, SimplCount, ModGuts)
+
+    do_iteration us iteration_no counts binds rules
        -- iteration_no is the number of the iteration we are
        -- about to begin, with '1' for the first
       | iteration_no > max_iterations  -- Stop if we've run out of iterations
        -- iteration_no is the number of the iteration we are
        -- about to begin, with '1' for the first
       | iteration_no > max_iterations  -- Stop if we've run out of iterations
-      = do {
-#ifdef DEBUG
-           if  max_iterations > 2 then
-               hPutStr stderr ("NOTE: Simplifier still going after " ++ 
-                               show max_iterations ++ 
-                               " iterations; bailing out.\n")
-           else 
-               return ();
-#endif
+      =  WARN(debugIsOn && (max_iterations > 2),
+                text ("Simplifier still going after " ++
+                               show max_iterations ++
+                               " iterations; bailing out.  Size = " ++ show (coreBindsSize binds) ++ "\n" ))
                -- Subtract 1 from iteration_no to get the
                -- number of iterations we actually completed
                -- Subtract 1 from iteration_no to get the
                -- number of iterations we actually completed
-           return ("Simplifier baled out", iteration_no - 1, counts, binds)
-       }
+           return ("Simplifier bailed out", iteration_no - 1, counts, 
+                    guts { mg_binds = binds, mg_rules = rules })
 
       -- Try and force thunks off the binds; significantly reduces
       -- space usage, especially with -O.  JRS, 000620.
       | let sz = coreBindsSize binds in sz == sz
       = do {
                -- Occurrence analysis
 
       -- Try and force thunks off the binds; significantly reduces
       -- space usage, especially with -O.  JRS, 000620.
       | let sz = coreBindsSize binds in sz == sz
       = do {
                -- Occurrence analysis
-          let { tagged_binds = _scc_ "OccAnal" occurAnalysePgm binds } ;
-          dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis"
+          let { tagged_binds = {-# SCC "OccAnal" #-} occurAnalysePgm binds rules } ;
+          Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis"
                     (pprCoreBindings tagged_binds);
 
                -- Get any new rules, and extend the rule base
                     (pprCoreBindings tagged_binds);
 
                -- Get any new rules, and extend the rule base
@@ -436,8 +550,12 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts
                -- behind the scenes.  Otherwise there's a danger we'll simply
                -- miss the rules for Ids hidden inside imported inlinings
           eps <- hscEPS hsc_env ;
                -- behind the scenes.  Otherwise there's a danger we'll simply
                -- miss the rules for Ids hidden inside imported inlinings
           eps <- hscEPS hsc_env ;
-          let  { rule_base' = unionRuleBase imp_rule_base (eps_rule_base eps)
-               ; simpl_env  = mkSimplEnv mode sw_chkr rule_base' } ;
+          let  { rule_base1 = unionRuleBase hpt_rule_base (eps_rule_base eps)
+               ; rule_base2 = extendRuleBaseList rule_base1 rules
+               ; simpl_env  = mkSimplEnv sw_chkr mode
+               ; simpl_binds = {-# SCC "SimplTopBinds" #-} 
+                               simplTopBinds simpl_env tagged_binds
+               ; fam_envs = (eps_fam_inst_env eps, fam_inst_env) } ;
           
                -- Simplify the program
                -- We do this with a *case* not a *let* because lazy pattern
           
                -- Simplify the program
                -- We do this with a *case* not a *let* because lazy pattern
@@ -450,19 +568,18 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts
                --      case t of {(_,counts') -> if counts'=0 then ... }
                -- So the conditional didn't force counts', because the
                -- selection got duplicated.  Sigh!
                --      case t of {(_,counts') -> if counts'=0 then ... }
                -- So the conditional didn't force counts', because the
                -- selection got duplicated.  Sigh!
-          case initSmpl dflags us1 (_scc_ "SimplTopBinds" simplTopBinds simpl_env tagged_binds) of {
-               (binds', counts') -> do {
+          case initSmpl dflags rule_base2 fam_envs us1 simpl_binds of {
+               (env1, counts1) -> do {
 
 
-          let  { all_counts = counts `plusSimplCount` counts'
-               ; herald     = "Simplifier phase " ++ phase_info ++ 
-                             ", iteration " ++ show iteration_no ++
-                             " out of " ++ show max_iterations
+          let  { all_counts = counts `plusSimplCount` counts1
+               ; binds1 = getFloats env1
+                ; rules1 = substRulesForImportedIds (mkCoreSubst env1) rules
                } ;
 
                -- Stop if nothing happened; don't dump output
                } ;
 
                -- Stop if nothing happened; don't dump output
-          if isZeroSimplCount counts' then
-               return ("Simplifier reached fixed point", iteration_no, 
-                       all_counts, binds')
+          if isZeroSimplCount counts1 then
+               return ("Simplifier reached fixed point", iteration_no, all_counts,
+                       guts { mg_binds = binds1, mg_rules = rules1 })
           else do {
                -- Short out indirections
                -- We do this *after* at least one run of the simplifier 
           else do {
                -- Short out indirections
                -- We do this *after* at least one run of the simplifier 
@@ -472,18 +589,30 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts
                --
                -- ToDo: alas, this means that indirection-shorting does not happen at all
                --       if the simplifier does nothing (not common, I know, but unsavoury)
                --
                -- ToDo: alas, this means that indirection-shorting does not happen at all
                --       if the simplifier does nothing (not common, I know, but unsavoury)
-          let { binds'' = _scc_ "ZapInd" shortOutIndirections binds' } ;
+          let { binds2 = {-# SCC "ZapInd" #-} shortOutIndirections binds1 } ;
 
                -- Dump the result of this iteration
 
                -- Dump the result of this iteration
-          dumpIfSet_dyn dflags Opt_D_dump_simpl_iterations herald
-                        (pprSimplCount counts') ;
-          endPass dflags herald Opt_D_dump_simpl_iterations binds'' ;
+          end_iteration dflags mode iteration_no max_iterations counts1 binds2 rules1 ;
 
                -- Loop
 
                -- Loop
-          do_iteration us2 (iteration_no + 1) all_counts binds''
+          do_iteration us2 (iteration_no + 1) all_counts binds2 rules1
        }  } } }
       where
          (us1, us2) = splitUniqSupply us
        }  } } }
       where
          (us1, us2) = splitUniqSupply us
+
+-------------------
+end_iteration :: DynFlags -> SimplifierMode -> Int -> Int 
+             -> SimplCount -> [CoreBind] -> [CoreRule] -> IO ()
+-- Same as endIteration but with simplifier counts
+end_iteration dflags mode iteration_no max_iterations counts binds rules
+  = do { Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_iterations pass_name
+                            (pprSimplCount counts) ;
+
+       ; endIteration dflags pass_name Opt_D_dump_simpl_iterations binds rules }
+  where
+    pass_name = "Simplifier mode " ++ showPpr mode ++ 
+               ", iteration " ++ show iteration_no ++
+               " out of " ++ show max_iterations
 \end{code}
 
 
 \end{code}
 
 
@@ -510,23 +639,21 @@ 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.
 
 makes strictness information propagate better.  This used to happen in
 the final phase, but it's tidier to do it here.
 
+Note [Transferring IdInfo]
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+We want to propagage any useful IdInfo on x_local to x_exported.
+
 STRICTNESS: if we have done strictness analysis, we want the strictness info on
 x_local to transfer to x_exported.  Hence the copyIdInfo call.
 
 RULES: we want to *add* any RULES for x_local to x_exported.
 
 STRICTNESS: if we have done strictness analysis, we want the strictness info on
 x_local to transfer to x_exported.  Hence the copyIdInfo call.
 
 RULES: we want to *add* any RULES for x_local to x_exported.
 
-Note [Rules and indirection-zapping]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Problem: what if x_exported has a RULE that mentions something in ...bindings...?
-Then the things mentioned can be out of scope!  Solution
- a) Make sure that in this pass the usage-info from x_exported is 
-       available for ...bindings...
- b) If there are any such RULES, rec-ify the entire top-level. 
-    It'll get sorted out next time round
 
 
-Messing up the rules
-~~~~~~~~~~~~~~~~~~~~
-The example that went bad on me at one stage was this one:
+Note [Messing up the exported Id's RULES]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We must be careful about discarding (obviously) or even merging the
+RULES on the exported Id. The example that went bad on me at one stage
+was this one:
        
     iterate :: (a -> a) -> a -> [a]
        [Exported]
        
     iterate :: (a -> a) -> a -> [a]
        [Exported]
@@ -559,13 +686,28 @@ And now we get an infinite loop in the rule system
                    -> iterateFB (:) f x
                    -> iterate f x
 
                    -> iterateFB (:) f x
                    -> iterate f x
 
-Tiresome old solution: 
-       don't do shorting out if f has rewrite rules (see shortableIdInfo)
-
-New solution (I think): 
+Old "solution": 
        use rule switching-off pragmas to get rid 
        of iterateList in the first place
 
        use rule switching-off pragmas to get rid 
        of iterateList in the first place
 
+But in principle the user *might* want rules that only apply to the Id
+he says.  And inline pragmas are similar
+   {-# NOINLINE f #-}
+   f = local
+   local = <stuff>
+Then we do not want to get rid of the NOINLINE.
+
+Hence hasShortableIdinfo.
+
+
+Note [Rules and indirection-zapping]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Problem: what if x_exported has a RULE that mentions something in ...bindings...?
+Then the things mentioned can be out of scope!  Solution
+ a) Make sure that in this pass the usage-info from x_exported is 
+       available for ...bindings...
+ b) If there are any such RULES, rec-ify the entire top-level. 
+    It'll get sorted out next time round
 
 Other remarks
 ~~~~~~~~~~~~~
 
 Other remarks
 ~~~~~~~~~~~~~
@@ -636,6 +778,7 @@ makeIndEnv binds
     add_pair (exported_id, rhs) env
        = env
                        
     add_pair (exported_id, rhs) env
        = env
                        
+-----------------
 shortMeOut ind_env exported_id local_id
 -- 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
 shortMeOut ind_env exported_id local_id
 -- 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
@@ -650,23 +793,27 @@ shortMeOut ind_env exported_id local_id
    
        not (local_id `elemVarEnv` ind_env)     -- Only if not already substituted for
     then
    
        not (local_id `elemVarEnv` ind_env)     -- Only if not already substituted for
     then
-       True
-
-{- No longer needed
-       if isEmptySpecInfo (specInfo (idInfo exported_id))      -- Only if no rules
-       then True       -- See note on "Messing up rules"
-       else 
-#ifdef DEBUG 
-          pprTrace "shortMeOut:" (ppr exported_id)
-#endif
-                                                False
--}
+       if hasShortableIdInfo exported_id
+       then True       -- See Note [Messing up the exported Id's IdInfo]
+       else WARN( True, ptext (sLit "Not shorting out:") <+> ppr exported_id )
+             False
     else
     else
-       False
+        False
 
 
+-----------------
+hasShortableIdInfo :: Id -> Bool
+-- True if there is no user-attached IdInfo on exported_id,
+-- so we can safely discard it
+-- See Note [Messing up the exported Id's IdInfo]
+hasShortableIdInfo id
+  =  isEmptySpecInfo (specInfo info)
+  && isDefaultInlinePragma (inlinePragInfo info)
+  where
+     info = idInfo id
 
 -----------------
 transferIdInfo :: Id -> Id -> Id
 
 -----------------
 transferIdInfo :: Id -> Id -> Id
+-- See Note [Transferring IdInfo]
 -- If we have
 --     lcl_id = e; exp_id = lcl_id
 -- and lcl_id has useful IdInfo, we don't want to discard it by going
 -- If we have
 --     lcl_id = e; exp_id = lcl_id
 -- and lcl_id has useful IdInfo, we don't want to discard it by going
@@ -677,9 +824,12 @@ transferIdInfo exported_id local_id
   = modifyIdInfo transfer exported_id
   where
     local_info = idInfo local_id
   = modifyIdInfo transfer exported_id
   where
     local_info = idInfo local_id
-    transfer exp_info = exp_info `setNewStrictnessInfo` newStrictnessInfo local_info
-                                `setWorkerInfo`        workerInfo local_info
+    transfer exp_info = exp_info `setStrictnessInfo` strictnessInfo local_info
+                                `setUnfoldingInfo`     unfoldingInfo local_info
                                 `setInlinePragInfo`    inlinePragInfo local_info
                                 `setInlinePragInfo`    inlinePragInfo local_info
-                                `setSpecInfo`          addSpecInfo (specInfo exp_info)
-                                                                   (specInfo local_info)
+                                `setSpecInfo`          addSpecInfo (specInfo exp_info) new_info
+    new_info = setSpecInfoHead (idName exported_id) 
+                              (specInfo local_info)
+       -- Remember to set the function-name field of the
+       -- rules as we transfer them from one function to another
 \end{code}
 \end{code}