\begin{code}
module CoreTidy (
- tidyCorePgm, tidyExpr, tidyCoreExpr,
+ tidyCorePgm, tidyExpr, tidyCoreExpr, tidyIdRules,
tidyBndr, tidyBndrs
) where
import CmdLineOpts ( DynFlags, DynFlag(..), opt_OmitInterfacePragmas )
import CoreSyn
import CoreUnfold ( noUnfolding, mkTopUnfolding, okToUnfoldInHiFile )
-import CoreFVs ( ruleSomeFreeVars, exprSomeFreeVars )
-import PprCore ( pprIdCoreRule )
+import CoreFVs ( ruleLhsFreeIds, ruleRhsFreeVars, exprSomeFreeVars )
+import PprCore ( pprIdRules )
import CoreLint ( showPass, endPass )
import CoreUtils ( exprArity )
import VarEnv
import VarSet
import Var ( Id, Var )
-import Id ( idType, idInfo, idName, isExportedId,
- idSpecialisation, idUnique,
- mkVanillaGlobal, isLocalId,
+import Id ( idType, idInfo, idName, idCoreRules,
+ isExportedId, idUnique, mkVanillaGlobal, isLocalId,
isImplicitId, mkUserLocal, setIdInfo
)
import IdInfo {- loads of stuff -}
import NewDemand ( isBottomingSig, topSig )
import BasicTypes ( isNeverActive )
-import Name ( getOccName, nameOccName, mkLocalName, mkGlobalName,
- localiseName, isGlobalName, nameSrcLoc
+import Name ( getOccName, nameOccName, mkInternalName, mkExternalName,
+ localiseName, isExternalName, nameSrcLoc
)
import NameEnv ( filterNameEnv )
import OccName ( TidyOccEnv, initTidyOccEnv, tidyOccName )
; let ext_ids = findExternalSet binds_in orphans_in
; let ext_rules = findExternalRules binds_in orphans_in ext_ids
+ -- findExternalRules filters ext_rules to avoid binders that
+ -- aren't externally visible; but the externally-visible binders
+ -- are computed (by findExternalSet) assuming that all orphan
+ -- rules are exported. So in fact we may export more than we
+ -- need. (It's a sort of mutual recursion.)
-- We also make sure to avoid any exported binders. Consider
-- f{-u1-} = 1 -- Local decl
init_tidy_env = (orig_ns, initTidyOccEnv avoids, emptyVarEnv)
avoids = [getOccName name | bndr <- typeEnvIds env_tc,
let name = idName bndr,
- isGlobalName name]
+ isExternalName name]
-- In computing our "avoids" list, we must include
-- all implicit Ids
-- all things with global names (assigned once and for
= mapAccumL (tidyTopBind mod ext_ids cg_info_env)
init_tidy_env binds_in
- ; let tidy_rules = tidyIdRules (occ_env,subst_env) ext_rules
+ ; let tidy_rules = tidyIdCoreRules (occ_env,subst_env) ext_rules
; let prs' = prs { prsOrig = orig_ns' }
pcs' = pcs { pcs_PRS = prs' }
; let final_ids = [ id
| bind <- tidy_binds
, id <- bindersOf bind
- , isGlobalName (idName id)]
+ , isExternalName (idName id)]
-- Dfuns are local Ids that might have
-- changed their unique during tidying
; endPass dflags "Tidy Core" Opt_D_dump_simpl tidy_binds
; dumpIfSet_core dflags Opt_D_dump_simpl
"Tidy Core Rules"
- (vcat (map pprIdCoreRule tidy_rules))
+ (pprIdRules tidy_rules)
; return (pcs', tidy_details)
}
findExternalRules binds orphan_rules ext_ids
| opt_OmitInterfacePragmas = []
| otherwise
- = orphan_rules ++ local_rules
+ = filter needed_rule (orphan_rules ++ local_rules)
where
- local_rules = [ (id, rule)
+ local_rules = [ rule
| id <- bindersOfBinds binds,
id `elemVarEnv` ext_ids,
- rule <- rulesRules (idSpecialisation id),
- not (isBuiltinRule rule)
- -- We can't print builtin rules in interface files
- -- Since they are built in, an importing module
- -- will have access to them anyway
- ]
+ rule <- idCoreRules id
+ ]
+ needed_rule (id, rule)
+ = not (isBuiltinRule rule)
+ -- We can't print builtin rules in interface files
+ -- Since they are built in, an importing module
+ -- will have access to them anyway
+
+ && not (any internal_id (varSetElems (ruleLhsFreeIds rule)))
+ -- Don't export a rule whose LHS mentions an Id that
+ -- is completely internal (i.e. not visible to an
+ -- importing module)
+
+ internal_id id = isLocalId id && not (id `elemVarEnv` ext_ids)
\end{code}
%************************************************************************
= foldr find init_needed binds
where
orphan_rule_ids :: IdSet
- orphan_rule_ids = unionVarSets [ ruleSomeFreeVars isLocalId rule
+ orphan_rule_ids = unionVarSets [ ruleRhsFreeVars rule
| (_, rule) <- orphan_rules]
init_needed :: IdEnv Bool
init_needed = mapUFM (\_ -> False) orphan_rule_ids
where
((orig,occ,subst), bndr')
= tidyTopBinder mod ext_ids cg_info_env
- rec_tidy_env rhs' top_tidy_env bndr
+ rec_tidy_env rhs rhs' top_tidy_env bndr
rec_tidy_env = (occ,subst)
rhs' = tidyExpr rec_tidy_env rhs
where
((orig,occ,subst), bndr')
= tidyTopBinder mod ext_ids cg_info_env
- rec_tidy_env rhs' top_tidy_env bndr
+ rec_tidy_env rhs rhs' top_tidy_env bndr
rhs' = tidyExpr rec_tidy_env rhs
tidyTopBinder :: Module -> IdEnv Bool -> CgInfoEnv
- -> TidyEnv -> CoreExpr
- -- The TidyEnv is used to tidy the IdInfo
- -- The expr is the already-tided RHS
- -- Both are knot-tied: don't look at them!
+ -> TidyEnv -- The TidyEnv is used to tidy the IdInfo
+ -> CoreExpr -- RHS *before* tidying
+ -> CoreExpr -- RHS *after* tidying
+ -- The TidyEnv and the after-tidying RHS are
+ -- both are knot-tied: don't look at them!
-> TopTidyEnv -> Id -> (TopTidyEnv, Id)
-- NB: tidyTopBinder doesn't affect the unique supply
-tidyTopBinder mod ext_ids cg_info_env rec_tidy_env rhs
+tidyTopBinder mod ext_ids cg_info_env rec_tidy_env rhs tidy_rhs
env@(ns2, occ_env2, subst_env2) id
-- This function is the heart of Step 2
-- The rec_tidy_env is the one to use for the IdInfo
-- Remember that ext_ids maps an Id to a Bool:
-- True to show the unfolding, False to hide it
show_unfold = maybe_external `orElse` False
- unfold_info | show_unfold = mkTopUnfolding rhs
+ unfold_info | show_unfold = mkTopUnfolding tidy_rhs
| otherwise = noUnfolding
-- Usually the Id will have an accurate arity on it, because
basic_info = vanillaIdInfo
`setCgInfo` cg_info
`setArityInfo` arity
- `setNewStrictnessInfo` newStrictnessInfo idinfo
+ `setAllStrictnessInfo` newStrictnessInfo idinfo
-- This is where we set names to local/global based on whether they really are
-- externally visible (see comment at the top of this module). If the name
-- was previously local, we have to give it a unique occurrence name if
--- we intend to globalise it.
+-- we intend to externalise it.
tidyTopName mod ns occ_env external name
| global && internal = (ns, occ_env, localiseName name)
| local && internal = (ns_w_local, occ_env', new_local_name)
-- Even local, internal names must get a unique occurrence, because
- -- if we do -split-objs we globalise the name later, in the code generator
+ -- if we do -split-objs we externalise the name later, in the code generator
--
-- Similarly, we must make sure it has a system-wide Unique, because
-- the byte-code generator builds a system-wide Name->BCO symbol table
| local && external = case lookupFM ns_names key of
Just orig -> (ns, occ_env', orig)
- Nothing -> (ns_w_global, occ_env', new_global_name)
- -- If we want to globalise a currently-local name, check
+ Nothing -> (ns_w_global, occ_env', new_external_name)
+ -- If we want to externalise a currently-local name, check
-- whether we have already assigned a unique for it.
-- If so, use it; if not, extend the table (ns_w_global).
-- This is needed when *re*-compiling a module in GHCi; we want to
-- use the same name for externally-visible things as we did before.
where
- global = isGlobalName name
+ global = isExternalName name
local = not global
internal = not external
uniq = uniqFromSupply us1
loc = nameSrcLoc name
- new_local_name = mkLocalName uniq occ' loc
- new_global_name = mkGlobalName uniq mod occ' loc
+ new_local_name = mkInternalName uniq occ' loc
+ new_external_name = mkExternalName uniq mod occ' loc
ns_w_local = ns { nsUniqs = us2 }
- ns_w_global = ns { nsUniqs = us2, nsNames = addToFM ns_names key new_global_name }
+ ns_w_global = ns { nsUniqs = us2, nsNames = addToFM ns_names key new_external_name }
------------ Worker --------------
= NoWorker
------------ Rules --------------
-tidyIdRules :: TidyEnv -> [IdCoreRule] -> [IdCoreRule]
-tidyIdRules env [] = []
-tidyIdRules env ((fn,rule) : rules)
+tidyIdRules :: Id -> [IdCoreRule]
+tidyIdRules id = tidyIdCoreRules emptyTidyEnv (idCoreRules id)
+
+tidyIdCoreRules :: TidyEnv -> [IdCoreRule] -> [IdCoreRule]
+tidyIdCoreRules env [] = []
+tidyIdCoreRules env ((fn,rule) : rules)
= tidyRule env rule =: \ rule ->
- tidyIdRules env rules =: \ rules ->
+ tidyIdCoreRules env rules =: \ rules ->
((tidyVarOcc env fn, rule) : rules)
tidyRule :: TidyEnv -> CoreRule -> CoreRule
idinfo = idInfo id
new_info = vanillaIdInfo
`setArityInfo` exprArity rhs
- `setNewStrictnessInfo` newStrictnessInfo idinfo
+ `setAllStrictnessInfo` newStrictnessInfo idinfo
`setNewDemandInfo` newDemandInfo idinfo
-- Override the env we get back from tidyId with the new IdInfo
-- so it gets propagated to the usage sites.
new_var_env = extendVarEnv var_env id final_id
+-- Non-top-level variables
tidyIdBndr :: TidyEnv -> Id -> (TidyEnv, Id)
tidyIdBndr env@(tidy_env, var_env) id
- = -- Non-top-level variables
+ = -- do this pattern match strictly, otherwise we end up holding on to
+ -- stuff in the OccName.
+ case tidyOccName tidy_env (getOccName id) of { (tidy_env', occ') ->
let
-- Give the Id a fresh print-name, *and* rename its type
-- The SrcLoc isn't important now,
--
-- All nested Ids now have the same IdInfo, namely none,
-- which should save some space.
- (tidy_env', occ') = tidyOccName tidy_env (getOccName id)
ty' = tidyType env (idType id)
id' = mkUserLocal occ' (idUnique id) ty' noSrcLoc
var_env' = extendVarEnv var_env id id'
in
((tidy_env', var_env'), id')
+ }
\end{code}
\begin{code}