Continue refactoring the core-to-core pipeline
[ghc-hetmet.git] / compiler / simplCore / SimplCore.lhs
index bd1c920..4df489b 100644 (file)
@@ -15,10 +15,9 @@ module SimplCore ( core2core, simplifyExpr ) where
 
 #include "HsVersions.h"
 
-import DynFlags                ( CoreToDo(..), SimplifierSwitch(..),
-                         SimplifierMode(..), DynFlags, DynFlag(..), dopt,
-                         getCoreToDo, shouldDumpSimplPhase )
+import DynFlags                ( DynFlags, DynFlag(..), dopt )
 import CoreSyn
+import CoreSubst
 import HscTypes
 import CSE             ( cseProgram )
 import Rules           ( RuleBase, emptyRuleBase, mkRuleBase, unionRuleBase,
@@ -30,11 +29,12 @@ import OccurAnal    ( occurAnalysePgm, occurAnalyseExpr )
 import IdInfo
 import CoreUtils       ( coreBindsSize )
 import Simplify                ( simplTopBinds, simplExpr )
-import SimplEnv                ( SimplEnv, simplBinders, mkSimplEnv, setInScopeSet )
+import SimplUtils      ( simplEnvForGHCi, simplEnvForRules )
+import SimplEnv
 import SimplMonad
 import CoreMonad
-import qualified ErrUtils as Err        ( dumpIfSet_dyn, dumpIfSet, showPass )
-import CoreLint                ( showPass, endPass, endPassIf, endIteration )
+import qualified ErrUtils as Err 
+import CoreLint
 import FloatIn         ( floatInwards )
 import FloatOut                ( floatOutwards )
 import FamInstEnv
@@ -52,19 +52,15 @@ import Specialise   ( specProgram)
 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 IO              ( hPutStr, stderr )
 import Outputable
 import Control.Monad
-import List            ( partition, intersperse )
+import Data.List
+import System.IO
 import Maybes
 \end{code}
 
@@ -85,11 +81,9 @@ core2core hsc_env guts = do
     us <- mkSplitUniqSupply 's'
     let (cp_us, ru_us) = splitUniqSupply us
 
-    -- COMPUTE THE ANNOTATIONS TO USE
-    ann_env <- prepareAnnotations hsc_env (Just guts)
-
     -- COMPUTE THE RULE BASE TO USE
-    (imp_rule_base, guts1) <- prepareRules hsc_env guts ru_us
+    -- See Note [Overall plumbing for rules] in Rules.lhs
+    (hpt_rule_base, guts1) <- 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
@@ -97,7 +91,7 @@ core2core hsc_env guts = do
     -- _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
+    (guts2, stats) <- runCoreM hsc_env hpt_rule_base cp_us mod $ do
         -- FIND BUILT-IN PASSES
         let builtin_core_todos = getCoreToDo dflags
 
@@ -118,6 +112,8 @@ simplifyExpr :: DynFlags -- includes spec of what core-to-core passes to do
             -> 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 {
        ; Err.showPass dflags "Simplify"
@@ -125,7 +121,7 @@ simplifyExpr dflags expr
        ; us <-  mkSplitUniqSupply 's'
 
        ; let (expr', _counts) = initSmpl dflags emptyRuleBase emptyFamInstEnvs us $
-                                simplExprGently gentleSimplEnv expr
+                                simplExprGently simplEnvForGHCi expr
 
        ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl "Simplified expression"
                        (pprCoreExpr expr')
@@ -133,79 +129,58 @@ simplifyExpr dflags expr
        ; return expr'
        }
 
-gentleSimplEnv :: SimplEnv
-gentleSimplEnv = mkSimplEnv SimplGently  (isAmongSimpl [])
-
 doCorePasses :: [CorePass] -> ModGuts -> CoreM ModGuts
-doCorePasses passes guts = foldM (flip doCorePass) guts passes
+doCorePasses passes guts 
+  = foldM do_pass guts passes
+  where
+    do_pass guts CoreDoNothing = return guts
+    do_pass guts (CoreDoPasses ps) = doCorePasses ps guts
+    do_pass guts pass 
+       = do { dflags <- getDynFlags
+                   ; liftIO $ showPass dflags pass
+                   ; guts' <- doCorePass pass guts
+                   ; liftIO $ endPass dflags pass (mg_binds guts') (mg_rules guts')
+                   ; return guts' }
 
 doCorePass :: CorePass -> ModGuts -> CoreM ModGuts
-doCorePass (CoreDoSimplify mode sws) = {-# SCC "Simplify" #-}
-                                       simplifyPgm mode sws
+doCorePass pass@(CoreDoSimplify {})  = {-# SCC "Simplify" #-}
+                                       simplifyPgm pass
 
 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
+                                       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 CoreDoGlomBinds              = doPassDM  glomBinds
+doCorePass CoreDoPrintCore              = observe   printCore
+doCorePass (CoreDoRuleCheck phase pat)  = ruleCheck phase pat
 doCorePass CoreDoNothing                = return
 doCorePass (CoreDoPasses passes)        = doCorePasses passes
-
-#ifdef OLD_STRICTNESS
-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
-
 \end{code}
 
 %************************************************************************
@@ -215,39 +190,14 @@ doOldStrictness guts
 %************************************************************************
 
 \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 $ 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))
+    liftIO $ printDump (ruleCheckProgram current_phase pat rb (mg_binds guts))
     return guts
 
 
@@ -319,64 +269,74 @@ prepareRules :: HscEnv
 
                    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 })
             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
+  = 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))
-             env              = setInScopeSet gentleSimplEnv local_ids 
-             (better_rules,_) = initSmpl dflags emptyRuleBase emptyFamInstEnvs us $
-                                (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
-               -- 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
+             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 better_rules,
-                      text "",
-                      text "Imported rules", pprRuleBase imp_rule_base])
+                vcat [text "Local rules for local Ids", pprRules simpl_rules,
+                      blankLine,
+                      text "Local rules for imported Ids", pprRuleBase hpt_rule_base])
 
-       ; return (imp_rule_base, guts { mg_binds = binds_w_rules, 
+       ; return (hpt_rule_base, guts { mg_binds = binds_w_rules, 
                                        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
-    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}
 
 Note [Simplifying the left-hand side of a RULE]
@@ -393,25 +353,19 @@ we do not want to get
 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}
+simplRule :: SimplEnv -> CoreRule -> SimplM CoreRule
 simplRule env rule@(BuiltinRule {})
   = return rule
 simplRule env rule@(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:
---     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.
+       return (rule { ru_bndrs = bndrs', ru_args = args'
+                    , ru_rhs = occurAnalyseExpr rhs' })
 \end{code}
 
 \begin{code}
@@ -488,51 +442,49 @@ glomBinds dflags binds
 %************************************************************************
 
 \begin{code}
-simplifyPgm :: SimplifierMode -> [SimplifierSwitch] -> ModGuts -> CoreM ModGuts
-simplifyPgm mode switches
-  = describePassD doc Opt_D_dump_simpl_phases $ \guts -> 
-    do { hsc_env <- getHscEnv
+simplifyPgm :: CoreToDo -> ModGuts -> CoreM ModGuts
+simplifyPgm pass 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
-           -> FamInstEnv
-           -> [CoreBind]
-           -> IO (SimplCount, [CoreBind])  -- New bindings
-
-simplifyPgmIO dump_phase mode switches hsc_env us imp_rule_base fam_inst_env binds
+       ; liftIOWithCount $  
+                simplifyPgmIO pass hsc_env us rb guts }
+
+simplifyPgmIO :: CoreToDo
+             -> HscEnv
+             -> UniqSupply
+             -> RuleBase
+             -> ModGuts
+             -> IO (SimplCount, ModGuts)  -- New bindings
+
+simplifyPgmIO pass@(CoreDoSimplify mode max_iterations switches)
+              hsc_env us hpt_rule_base 
+              guts@(ModGuts { mg_binds = binds, mg_rules = rules
+                            , mg_fam_inst_env = fam_inst_env })
   = do {
-       (termination_msg, it_count, counts_out, binds') 
-          <- do_iteration us 1 (zeroSimplCount dflags) binds ;
+       (termination_msg, it_count, counts_out, guts') 
+          <- do_iteration us 1 (zeroSimplCount dflags) binds rules ;
 
        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 "",
+                        blankLine,
                         pprSimplCount counts_out]);
 
-       return (counts_out, binds')
+       return (counts_out, guts')
     }
   where
-    dflags        = hsc_dflags hsc_env
-                  
-    sw_chkr       = isAmongSimpl switches
-    max_iterations = intSwitchSet sw_chkr MaxSimplifierIterations `orElse` 2
-    do_iteration us iteration_no counts binds
+    dflags              = hsc_dflags hsc_env
+    dump_phase          = dumpSimplPhase dflags mode
+    sw_chkr     = isAmongSimpl switches
+    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
@@ -542,25 +494,28 @@ simplifyPgmIO dump_phase mode switches hsc_env us imp_rule_base fam_inst_env bin
                                " iterations; bailing out.  Size = " ++ show (coreBindsSize binds) ++ "\n" ))
                -- Subtract 1 from iteration_no to get the
                -- number of iterations we actually completed
-           return ("Simplifier bailed 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
-          let { tagged_binds = {-# SCC "OccAnal" #-} occurAnalysePgm binds } ;
+          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
+               -- See Note [Overall plumbing for rules] in Rules.lhs
                -- We need to do this regularly, because simplification can
                -- poke on IdInfo thunks, which in turn brings in new rules
                -- 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 
+          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) } ;
@@ -576,19 +531,18 @@ simplifyPgmIO dump_phase mode switches hsc_env us imp_rule_base fam_inst_env bin
                --      case t of {(_,counts') -> if counts'=0 then ... }
                -- So the conditional didn't force counts', because the
                -- selection got duplicated.  Sigh!
-          case initSmpl dflags rule_base' fam_envs us1 simpl_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 mode " ++ showPpr mode ++ 
-                             ", iteration " ++ show iteration_no ++
-                             " out of " ++ show max_iterations
+          let  { all_counts = counts `plusSimplCount` counts1
+               ; binds1 = getFloats env1
+                ; rules1 = substRulesForImportedIds (mkCoreSubst (text "imp-rules") env1) rules
                } ;
 
                -- 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 
@@ -598,18 +552,27 @@ simplifyPgmIO dump_phase mode switches hsc_env us imp_rule_base fam_inst_env bin
                --
                -- 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
-          Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_iterations herald
-                        (pprSimplCount counts') ;
-          endIteration dflags herald Opt_D_dump_simpl_iterations binds'' ;
+          end_iteration dflags pass iteration_no counts1 binds2 rules1 ;
 
                -- 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
+
+-------------------
+end_iteration :: DynFlags -> CoreToDo -> Int 
+             -> SimplCount -> [CoreBind] -> [CoreRule] -> IO ()
+-- Same as endIteration but with simplifier counts
+end_iteration dflags pass iteration_no counts binds rules
+  = do { dumpIfSet (dopt Opt_D_dump_simpl_iterations dflags)
+                   pass (ptext (sLit "Simplifier counts"))
+                  (pprSimplCount counts)
+
+       ; endIteration dflags pass iteration_no binds rules }
 \end{code}
 
 
@@ -646,11 +609,11 @@ 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 [Messing up the exported Id's IdInfo]
+Note [Messing up the exported Id's RULES]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We must be careful about discarding the IdInfo on the old Id
-
-The example that went bad on me at one stage was this one:
+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]
@@ -821,8 +784,8 @@ transferIdInfo exported_id 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
                                 `setSpecInfo`          addSpecInfo (specInfo exp_info) new_info
     new_info = setSpecInfoHead (idName exported_id)