X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2FsimplCore%2FSimplCore.lhs;h=86d3ec0a1e13d22bfdd04665288c314993460446;hb=85514ae1d86203212930c4953ae608b53aa9f452;hp=8c98492ec3b56ee9e75734e318349a71e4d93314;hpb=913c612f25e118f06a2c21617fbccf34b80f1146;p=ghc-hetmet.git diff --git a/compiler/simplCore/SimplCore.lhs b/compiler/simplCore/SimplCore.lhs index 8c98492..86d3ec0 100644 --- a/compiler/simplCore/SimplCore.lhs +++ b/compiler/simplCore/SimplCore.lhs @@ -4,17 +4,22 @@ \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, - 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, @@ -22,7 +27,7 @@ import Rules ( RuleBase, emptyRuleBase, mkRuleBase, unionRuleBase, 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 ) @@ -30,12 +35,14 @@ import Simplify ( simplTopBinds, simplExpr ) import SimplEnv ( SimplEnv, simplBinders, mkSimplEnv, setInScopeSet ) import SimplMonad import ErrUtils ( dumpIfSet, dumpIfSet_dyn, showPass ) -import CoreLint ( endPass ) +import CoreLint ( 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 ( tyConSelIds, tyConDataCons ) +import Class ( classSelIds ) import VarSet import VarEnv import NameEnv ( lookupNameEnv ) @@ -50,12 +57,14 @@ import StrictAnal ( saBinds ) import CprAnalyse ( cprAnalyse ) #endif import Vectorise ( vectorise ) +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} %************************************************************************ @@ -70,26 +79,30 @@ core2core :: HscEnv -> IO ModGuts core2core hsc_env guts - = do - let dflags = hsc_dflags hsc_env - core_todos = getCoreToDo dflags + = do { + ; let dflags = hsc_dflags hsc_env + core_todos = getCoreToDo dflags - 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 + ; (imp_rule_base, guts1) <- prepareRules hsc_env guts ru_us + + -- Note [Injecting implicit bindings] + ; let implicit_binds = getImplicitBinds (mg_types guts1) + guts2 = guts1 { mg_binds = implicit_binds ++ mg_binds guts1 } -- DO THE BUSINESS - (stats, guts'') <- doCorePasses hsc_env imp_rule_base cp_us - (zeroSimplCount dflags) - guts' core_todos + ; (stats, guts3) <- doCorePasses hsc_env imp_rule_base cp_us + (zeroSimplCount dflags) + guts2 core_todos - dumpIfSet_dyn dflags Opt_D_dump_simpl_stats + ; dumpIfSet_dyn dflags Opt_D_dump_simpl_stats "Grand total simplifier statistics" (pprSimplCount stats) - return guts'' + ; return guts3 } simplifyExpr :: DynFlags -- includes spec of what core-to-core passes to do @@ -137,23 +150,23 @@ doCorePasses hsc_env rb us stats guts (to_do : 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 (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" #-} trBindsU 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 (CoreDoVectorisation be) = {-# SCC "Vectorise" #-} vectorise be doCorePass CoreDoPrintCore = observe printCore -doCorePass (CoreDoRuleCheck phase pat) = observe (ruleCheck phase pat) +doCorePass (CoreDoRuleCheck phase pat) = ruleCheck phase pat doCorePass CoreDoNothing = observe (\ _ _ -> return ()) #ifdef OLD_STRICTNESS -doCorePass CoreDoOldStrictness = _scc_ "OldStrictness" trBinds doOldStrictness +doCorePass CoreDoOldStrictness = {-# SCC "OldStrictness" #-} trBinds doOldStrictness #else doCorePass CoreDoOldStrictness = panic "CoreDoOldStrictness" #endif @@ -168,8 +181,11 @@ doOldStrictness dfs binds printCore _ binds = dumpIfSet True "Print Core" (pprCoreBindings binds) -ruleCheck phase pat dflags binds = do showPass dflags "RuleCheck" - printDump (ruleCheckProgram phase pat binds) +ruleCheck phase pat hsc_env us rb guts + = do let dflags = hsc_dflags hsc_env + showPass dflags "RuleCheck" + printDump (ruleCheckProgram phase pat rb (mg_binds guts)) + return (zeroSimplCount dflags, guts) -- Most passes return no stats and don't change rules trBinds :: (DynFlags -> [CoreBind] -> IO [CoreBind]) @@ -202,10 +218,51 @@ observe do_pass hsc_env us rb guts \end{code} +%************************************************************************ +%* * + Implicit bindings +%* * +%************************************************************************ + +Note [Injecting implicit bindings] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We used to inject the implict bindings right at the end, in CoreTidy. +But some of these bindings, notably record selectors, are not +constructed in an optimised form. E.g. record selector for + data T = MkT { x :: {-# UNPACK #-} !Int } +Then the unfolding looks like + x = \t. case t of MkT x1 -> let x = I# x1 in x +This generates bad code unless it's first simplified a bit. +(Only matters when the selector is used curried; eg map x ys.) +See Trac #2070. + +\begin{code} +getImplicitBinds :: TypeEnv -> [CoreBind] +getImplicitBinds type_env + = map get_defn (concatMap implicit_con_ids (typeEnvTyCons type_env) + ++ concatMap other_implicit_ids (typeEnvElts type_env)) + -- Put the constructor wrappers first, because + -- other implicit bindings (notably the fromT functions arising + -- from generics) use the constructor wrappers. At least that's + -- what External Core likes + where + implicit_con_ids tc = mapCatMaybes dataConWrapId_maybe (tyConDataCons tc) + + other_implicit_ids (ATyCon tc) = filter (not . isNaughtyRecordSelector) (tyConSelIds tc) + -- The "naughty" ones are not real functions at all + -- They are there just so we can get decent error messages + -- See Note [Naughty record selectors] in MkId.lhs + other_implicit_ids (AClass cl) = classSelIds cl + other_implicit_ids _other = [] + + get_defn :: Id -> CoreBind + get_defn id = NonRec id (unfoldingTemplate (idUnfolding id)) +\end{code} + %************************************************************************ %* * -\subsection{Dealing with rules} + Dealing with rules %* * %************************************************************************ @@ -234,7 +291,7 @@ prepareRules hsc_env@(HscEnv { hsc_dflags = dflags, hsc_HPT = hpt }) 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 @@ -282,21 +339,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: @@ -318,13 +382,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} @@ -393,22 +463,28 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts (termination_msg, it_count, counts_out, binds') <- do_iteration us 1 (zeroSimplCount dflags) (mg_binds guts) ; - dumpIfSet (dopt Opt_D_verbose_core2core dflags - && dopt Opt_D_dump_simpl_stats dflags) + dumpIfSet (dump_phase && dopt Opt_D_dump_simpl_stats dflags) "Simplifier statistics" (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'; + endPassIf dump_phase dflags + ("Simplify phase " ++ phase_info ++ " done") + Opt_D_dump_simpl_phases binds'; return (counts_out, guts { mg_binds = binds' }) } where dflags = hsc_dflags hsc_env phase_info = case mode of - SimplGently -> "gentle" - SimplPhase n -> show n + SimplGently -> "gentle" + SimplPhase n ss -> shows n + . showString " [" + . showString (concat $ intersperse "," ss) + $ "]" + + dump_phase = shouldDumpSimplPhase dflags mode sw_chkr = isAmongSimpl switches max_iterations = intSwitchSet sw_chkr MaxSimplifierIterations `orElse` 2 @@ -417,26 +493,20 @@ 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.\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. | let sz = coreBindsSize binds in sz == sz = do { -- Occurrence analysis - let { tagged_binds = _scc_ "OccAnal" occurAnalysePgm binds } ; + let { tagged_binds = {-# SCC "OccAnal" #-} occurAnalysePgm binds } ; dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis" (pprCoreBindings tagged_binds); @@ -448,7 +518,7 @@ simplifyPgm mode switches hsc_env us imp_rule_base guts eps <- hscEPS hsc_env ; let { rule_base' = unionRuleBase imp_rule_base (eps_rule_base eps) ; simpl_env = mkSimplEnv mode sw_chkr - ; simpl_binds = _scc_ "SimplTopBinds" + ; simpl_binds = {-# SCC "SimplTopBinds" #-} simplTopBinds simpl_env tagged_binds ; fam_envs = (eps_fam_inst_env eps, mg_fam_inst_env guts) } ; @@ -485,12 +555,12 @@ 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) - let { binds'' = _scc_ "ZapInd" shortOutIndirections binds' } ; + let { binds'' = {-# SCC "ZapInd" #-} shortOutIndirections binds' } ; -- 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'' ; + endIteration dflags herald Opt_D_dump_simpl_iterations binds'' ; -- Loop do_iteration us2 (iteration_no + 1) all_counts binds'' @@ -693,6 +763,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}