Make record selectors into ordinary functions
[ghc-hetmet.git] / compiler / simplCore / SimplCore.lhs
index 744d54b..d6aecc4 100644 (file)
@@ -17,32 +17,35 @@ module SimplCore ( core2core, simplifyExpr ) where
 
 import DynFlags                ( CoreToDo(..), SimplifierSwitch(..),
                          SimplifierMode(..), DynFlags, DynFlag(..), dopt,
-                         getCoreToDo )
+                         getCoreToDo, shouldDumpSimplPhase )
 import CoreSyn
-import HscTypes                ( HscEnv(..), ModGuts(..), ExternalPackageState(..),
-                         Dependencies( dep_mods ), 
-                         hscEPS, hptRules )
+import HscTypes
 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 )
 import IdInfo          ( setNewStrictnessInfo, newStrictnessInfo, 
-                         setWorkerInfo, workerInfo,
+                         setWorkerInfo, workerInfo, setSpecInfoHead,
                          setInlinePragInfo, inlinePragInfo,
                          setSpecInfo, specInfo, specInfoRules )
 import CoreUtils       ( coreBindsSize )
 import Simplify                ( simplTopBinds, simplExpr )
 import SimplEnv                ( SimplEnv, simplBinders, mkSimplEnv, setInScopeSet )
 import SimplMonad
-import ErrUtils                ( dumpIfSet, dumpIfSet_dyn, showPass )
-import CoreLint                ( endPass, endIteration )
+import CoreMonad
+import qualified ErrUtils as Err        ( dumpIfSet_dyn, dumpIfSet, showPass )
+import CoreLint                ( showPass, endPass, endPassIf, endIteration )
 import FloatIn         ( floatInwards )
 import FloatOut                ( floatOutwards )
 import FamInstEnv
-import Id              ( Id, modifyIdInfo, idInfo, isExportedId, isLocalId,
-                         idSpecialisation, idName )
+import Id
+import DataCon
+import TyCon           ( tyConDataCons )
+import Class           ( classSelIds )
+import BasicTypes       ( CompilerPhase, isActive )
 import VarSet
 import VarEnv
 import NameEnv         ( lookupNameEnv )
@@ -57,12 +60,15 @@ import StrictAnal   ( saBinds )
 import CprAnalyse       ( cprAnalyse )
 #endif
 import Vectorise        ( vectorise )
+import FastString
+import Util
 
 import UniqSupply      ( UniqSupply, mkSplitUniqSupply, splitUniqSupply )
 import IO              ( hPutStr, stderr )
 import Outputable
-import List            ( partition )
-import Maybes          ( orElse )
+import Control.Monad
+import List            ( partition, intersperse )
+import Maybes
 \end{code}
 
 %************************************************************************
@@ -76,28 +82,39 @@ core2core :: HscEnv
          -> 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
+    us <- mkSplitUniqSupply 's'
+    let (cp_us, ru_us) = splitUniqSupply us
 
-               -- COMPUTE THE RULE BASE TO USE
-       (imp_rule_base, guts') <- prepareRules hsc_env guts ru_us
+    -- COMPUTE THE ANNOTATIONS TO USE
+    ann_env <- prepareAnnotations hsc_env (Just guts)
 
-               -- DO THE BUSINESS
-       (stats, guts'') <- doCorePasses hsc_env imp_rule_base cp_us
-                                       (zeroSimplCount dflags) 
-                                       guts' core_todos
+    -- COMPUTE THE RULE BASE TO USE
+    (imp_rule_base, guts1) <- prepareRules hsc_env guts ru_us
 
-       dumpIfSet_dyn dflags Opt_D_dump_simpl_stats
-                 "Grand total simplifier statistics"
-                 (pprSimplCount stats)
+    -- 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 imp_rule_base cp_us mod $ do
+        -- FIND BUILT-IN PASSES
+        let builtin_core_todos = getCoreToDo dflags
 
-       return guts''
+        -- DO THE BUSINESS
+        doCorePasses builtin_core_todos guts1
 
+    Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_stats
+        "Grand total simplifier statistics"
+        (pprSimplCount stats)
+
+    return guts2
+
+
+type CorePass = CoreToDo
 
 simplifyExpr :: DynFlags -- includes spec of what core-to-core passes to do
             -> CoreExpr
@@ -106,14 +123,14 @@ simplifyExpr :: DynFlags -- includes spec of what core-to-core passes to do
 -- expression typed in at the interactive prompt
 simplifyExpr dflags expr
   = do {
-       ; showPass dflags "Simplify"
+       ; Err.showPass dflags "Simplify"
 
        ; us <-  mkSplitUniqSupply 's'
 
        ; let (expr', _counts) = initSmpl dflags emptyRuleBase emptyFamInstEnvs us $
                                 simplExprGently gentleSimplEnv expr
 
-       ; dumpIfSet_dyn dflags Opt_D_dump_simpl "Simplified expression"
+       ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl "Simplified expression"
                        (pprCoreExpr expr')
 
        ; return expr'
@@ -122,97 +139,171 @@ simplifyExpr dflags expr
 gentleSimplEnv :: SimplEnv
 gentleSimplEnv = mkSimplEnv SimplGently  (isAmongSimpl [])
 
-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 (CoreDoPasses to_dos1 : to_dos2) 
-  = doCorePasses hsc_env rb us stats guts (to_dos1 ++ to_dos2) 
-
-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 :: CoreToDo -> HscEnv -> UniqSupply -> RuleBase
-          -> ModGuts -> IO (SimplCount, ModGuts)
-doCorePass (CoreDoSimplify mode sws)   = {-# SCC "Simplify" #-}      simplifyPgm mode sws
-doCorePass CoreCSE                    = {-# SCC "CommonSubExpr" #-} trBinds  cseProgram
-doCorePass CoreLiberateCase           = {-# SCC "LiberateCase" #-}  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 CoreDoVectorisation         = {-# SCC "Vectorise" #-}     vectorise
-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
-#else
-doCorePass CoreDoOldStrictness        = panic "CoreDoOldStrictness"
+doCorePasses :: [CorePass] -> ModGuts -> CoreM ModGuts
+doCorePasses passes guts = foldM (flip doCorePass) guts passes
+
+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 $
+                                       doPassDU  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
+
+#ifdef OLD_STRICTNESS
+doCorePass CoreDoOldStrictness          = {-# SCC "OldStrictness" #-} doOldStrictness
 #endif
-doCorePass (CoreDoPasses _) = panic "CoreDoPasses"
+
+doCorePass CoreDoNothing                = return
+doCorePass (CoreDoPasses passes)        = doCorePasses passes
 
 #ifdef OLD_STRICTNESS
-doOldStrictness dfs binds
-  = do binds1 <- saBinds dfs binds
-       binds2 <- cprAnalyse dfs binds1
-       return binds2
+doOldStrictness :: ModGuts -> CoreM ModGuts
+doOldStrictness guts
+  = do dfs <- getDynFlags
+       guts'  <- describePass "Strictness analysis" Opt_D_dump_stranal $ 
+                 doPassM (saBinds dfs) guts
+       guts'' <- describePass "Constructed Product analysis" Opt_D_dump_cpranal $ 
+                 doPass cprAnalyse guts'
+       return guts''
 #endif
 
-printCore _ binds = dumpIfSet True "Print Core" (pprCoreBindings binds)
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection{Core pass combinators}
+%*                                                                     *
+%************************************************************************
 
-ruleCheck phase pat dflags binds = do showPass dflags "RuleCheck"
-                                     printDump (ruleCheckProgram phase pat binds)
+\begin{code}
 
--- 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
+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 $ showPass dflags name
+    guts' <- pass guts
+    liftIO $ endPass dflags name dflag (mg_binds 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)
-       -> 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
+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
 %*                                                                     *
 %************************************************************************
 
@@ -234,14 +325,15 @@ prepareRules :: HscEnv
                                        --      (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 
   = do { 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))
              env              = setInScopeSet gentleSimplEnv local_ids 
              (better_rules,_) = initSmpl dflags emptyRuleBase emptyFamInstEnvs us $
-                                (mapSmpl (simplRule env) local_rules)
+                                (mapM (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
@@ -266,8 +358,9 @@ prepareRules hsc_env@(HscEnv { hsc_dflags = dflags, hsc_HPT = hpt })
              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,
+       ; Err.dumpIfSet_dyn dflags Opt_D_dump_rules "Transformation rules"
+               (withPprStyle (mkUserStyle (mkPrintUnqualified dflags rdr_env) AllTheWay) $
+                vcat [text "Local rules", pprRules better_rules,
                       text "",
                       text "Imported rules", pprRuleBase imp_rule_base])
 
@@ -289,21 +382,28 @@ updateBinders local_rules binds
                                -- arising from specialisation pragmas
 \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.
+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)
 
 \begin{code}
 simplRule env rule@(BuiltinRule {})
-  = returnSmpl rule
+  = return rule
 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' })
+  = 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 = rhs' })
 
 -- It's important that simplExprGently does eta reduction.
 -- For example, in a rule like:
@@ -325,13 +425,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
+--     (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
 
-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}
 
@@ -370,7 +476,7 @@ glomBinds :: DynFlags -> [CoreBind] -> IO [CoreBind]
 -- 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... 
@@ -385,37 +491,46 @@ glomBinds dflags binds
 %************************************************************************
 
 \begin{code}
-simplifyPgm :: SimplifierMode
+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
+       ; let fam_inst_env = mg_fam_inst_env guts
+             dump_phase = shouldDumpSimplPhase (hsc_dflags hsc_env) mode
+            simplify_pgm = simplifyPgmIO dump_phase mode switches 
+                                          hsc_env us rb fam_inst_env
+
+       ; doPassM (liftIOWithCount . simplify_pgm) guts }
+  where
+    doc = ptext (sLit "Simplifier Phase") <+> text (showPpr mode) 
+
+simplifyPgmIO :: Bool
+            -> SimplifierMode
            -> [SimplifierSwitch]
            -> HscEnv
            -> UniqSupply
            -> RuleBase
-           -> ModGuts
-           -> IO (SimplCount, ModGuts)  -- New bindings
+           -> FamInstEnv
+           -> [CoreBind]
+           -> IO (SimplCount, [CoreBind])  -- New bindings
 
-simplifyPgm mode switches hsc_env us imp_rule_base guts
+simplifyPgmIO dump_phase mode switches hsc_env us imp_rule_base fam_inst_env binds
   = do {
-       showPass dflags "Simplify";
-
        (termination_msg, it_count, counts_out, binds') 
-          <- do_iteration us 1 (zeroSimplCount dflags) (mg_binds guts) ;
+          <- do_iteration us 1 (zeroSimplCount dflags) binds ;
 
-       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",
                         text "",
                         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, binds')
     }
   where
     dflags        = hsc_dflags hsc_env
-    phase_info    = case mode of
-                         SimplGently  -> "gentle"
-                         SimplPhase n -> show n
                   
     sw_chkr       = isAmongSimpl switches
     max_iterations = intSwitchSet sw_chkr MaxSimplifierIterations `orElse` 2
@@ -424,19 +539,13 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts
        -- 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.  Size = " ++ show (coreBindsSize binds) ++ "\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
-           return ("Simplifier baled out", iteration_no - 1, counts, binds)
-       }
+           return ("Simplifier bailed out", iteration_no - 1, counts, binds)
 
       -- Try and force thunks off the binds; significantly reduces
       -- space usage, especially with -O.  JRS, 000620.
@@ -444,7 +553,7 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts
       = do {
                -- Occurrence analysis
           let { tagged_binds = {-# SCC "OccAnal" #-} occurAnalysePgm binds } ;
-          dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis"
+          Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis"
                     (pprCoreBindings tagged_binds);
 
                -- Get any new rules, and extend the rule base
@@ -457,7 +566,7 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts
                ; simpl_env  = mkSimplEnv mode sw_chkr 
                ; simpl_binds = {-# SCC "SimplTopBinds" #-} 
                                simplTopBinds simpl_env tagged_binds
-               ; fam_envs = (eps_fam_inst_env eps, mg_fam_inst_env guts) } ;
+               ; 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
@@ -474,7 +583,7 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts
                (binds', counts') -> do {
 
           let  { all_counts = counts `plusSimplCount` counts'
-               ; herald     = "Simplifier phase " ++ phase_info ++ 
+               ; herald     = "Simplifier mode " ++ showPpr mode ++ 
                              ", iteration " ++ show iteration_no ++
                              " out of " ++ show max_iterations
                } ;
@@ -495,7 +604,7 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts
           let { binds'' = {-# SCC "ZapInd" #-} shortOutIndirections binds' } ;
 
                -- Dump the result of this iteration
-          dumpIfSet_dyn dflags Opt_D_dump_simpl_iterations herald
+          Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_iterations herald
                         (pprSimplCount counts') ;
           endIteration dflags herald Opt_D_dump_simpl_iterations binds'' ;
 
@@ -700,6 +809,9 @@ transferIdInfo exported_id local_id
     transfer exp_info = exp_info `setNewStrictnessInfo` newStrictnessInfo local_info
                                 `setWorkerInfo`        workerInfo 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}