import CoreTidy
import CoreMonad
import CoreUtils
+import Rules
import CoreArity ( exprArity, exprBotStrictness_maybe )
import Class ( classSelIds )
import VarEnv
import Module
import HscTypes
import Maybes
-import ErrUtils
import UniqSupply
import Outputable
import FastBool hiding ( fastOr )
import Util
+import FastString
import Data.List ( sortBy )
import Data.IORef ( IORef, readIORef, writeIORef )
-> [Instance] -> [FamInstEnv.FamInst] -> IO ModDetails
mkBootModDetails hsc_env exports type_env insts fam_insts
= do { let dflags = hsc_dflags hsc_env
- ; showPass dflags "Tidy [hoot] type env"
+ ; showPass dflags CoreTidy
; let { insts' = tidyInstances globaliseAndTidyId insts
; dfun_ids = map instanceDFunId insts'
; expose_all = dopt Opt_ExposeAllUnfoldings dflags
; th = dopt Opt_TemplateHaskell dflags
}
- ; showPass dflags "Tidy Core"
+ ; showPass dflags CoreTidy
; let { implicit_binds = getImplicitBinds type_env }
binds implicit_binds imp_rules
; let { ext_rules = findExternalRules omit_prags binds imp_rules unfold_env }
+ -- Glom together imp_rules and rules currently attached to binders
+ -- Then pick just the ones we need to expose
-- See Note [Which rules to expose]
; let { (tidy_env, tidy_binds)
; alg_tycons = filter isAlgTyCon (typeEnvTyCons type_env)
}
- ; endPass dflags "Tidy Core" Opt_D_dump_simpl all_tidy_binds tidy_rules
+ ; endPass dflags CoreTidy all_tidy_binds tidy_rules
+
+ -- If the endPass didn't print the rules, but ddump-rules is on, print now
+ ; dumpIfSet (dopt Opt_D_dump_rules dflags
+ && (not (dopt Opt_D_dump_simpl dflags)))
+ CoreTidy
+ (ptext (sLit "rules"))
+ (pprRulesForUser tidy_rules)
+
; let dir_imp_mods = moduleEnvKeys dir_imps
; return (CgGuts { cg_module = mod,
(varSetElems spec_ids) -- XXX non-det ordering
idinfo = idInfo id
- dont_inline = isNeverActive (inlinePragmaActivation (inlinePragInfo idinfo))
+ never_active = isNeverActive (inlinePragmaActivation (inlinePragInfo idinfo))
loop_breaker = isNonRuleLoopBreaker (occInfo idinfo)
bottoming_fn = isBottomingSig (strictnessInfo idinfo `orElse` topSig)
spec_ids = specInfoFreeVars (specInfo idinfo)
mb_unfold_ids :: Maybe (IdSet, [Id]) -- Nothing => don't unfold
mb_unfold_ids = case unfoldingInfo idinfo of
- CoreUnfolding { uf_tmpl = unf_rhs, uf_guidance = guide }
- | expose_all || -- expose_all says to expose all
- -- unfoldings willy-nilly
- not (bottoming_fn -- No need to inline bottom functions
- || dont_inline -- Or ones that say not to
- || loop_breaker -- Or that are loop breakers
- || neverUnfoldGuidance guide)
- -> Just (exprFvsInOrder unf_rhs)
- DFunUnfolding _ ops -> Just (exprsFvsInOrder ops)
- _ -> Nothing
+ CoreUnfolding { uf_tmpl = unf_rhs, uf_src = src, uf_guidance = guide }
+ | show_unfolding src guide
+ -> Just (unf_ext_ids src unf_rhs)
+ DFunUnfolding _ _ ops -> Just (exprsFvsInOrder ops)
+ _ -> Nothing
+ where
+ unf_ext_ids (InlineWrapper v) _ = (unitVarSet v, [v])
+ unf_ext_ids _ unf_rhs = exprFvsInOrder unf_rhs
+ -- For a wrapper, externalise the wrapper id rather than the
+ -- fvs of the rhs. The two usually come down to the same thing
+ -- but I've seen cases where we had a wrapper id $w but a
+ -- rhs where $w had been inlined; see Trac #3922
+
+ show_unfolding unf_source unf_guidance
+ = expose_all -- 'expose_all' says to expose all
+ -- unfoldings willy-nilly
+
+ || isInlineRuleSource unf_source -- Always expose things whose
+ -- source is an inline rule
+
+ || not (bottoming_fn -- No need to inline bottom functions
+ || never_active -- Or ones that say not to
+ || loop_breaker -- Or that are loop breakers
+ || neverUnfoldGuidance unf_guidance)
-- We want a deterministic free-variable list. exprFreeVars gives us
-- a VarSet, which is in a non-deterministic order when converted to a
-- in the IdInfo of one early in the group
tidyTopPair show_unfold rhs_tidy_env caf_info name' (bndr, rhs)
- = WARN( not _bottom_exposed, ppr bndr1 )
- (bndr1, rhs1)
+ = (bndr1, rhs1)
where
- -- If the cheap-and-cheerful bottom analyser can see that
- -- the RHS is bottom, it should jolly well be exposed
- _bottom_exposed = case exprBotStrictness_maybe rhs of
- Nothing -> True
- Just (arity, _) -> appIsBottom str arity
- where
- str = strictnessInfo idinfo `orElse` topSig
-
- bndr1 = mkGlobalId details name' ty' idinfo'
- details = idDetails bndr -- Preserve the IdDetails
- ty' = tidyTopType (idType bndr)
- rhs1 = tidyExpr rhs_tidy_env rhs
- idinfo = idInfo bndr
- idinfo' = tidyTopIdInfo (isExternalName name')
- idinfo unfold_info
- arity caf_info
- (occInfo idinfo)
-
- unfold_info | show_unfold = tidyUnfolding rhs_tidy_env rhs1 (unfoldingInfo idinfo)
- | otherwise = noUnfolding
- -- NB: do *not* expose the worker if show_unfold is off,
- -- because that means this thing is a loop breaker or
- -- marked NOINLINE or something like that
- -- This is important: if you expose the worker for a loop-breaker
- -- then you can make the simplifier go into an infinite loop, because
- -- in effect the unfolding is exposed. See Trac #1709
- --
- -- You might think that if show_unfold is False, then the thing should
- -- not be w/w'd in the first place. But a legitimate reason is this:
- -- the function returns bottom
- -- In this case, show_unfold will be false (we don't expose unfoldings
- -- for bottoming functions), but we might still have a worker/wrapper
- -- split (see Note [Worker-wrapper for bottoming functions] in WorkWrap.lhs
-
- -- Usually the Id will have an accurate arity on it, because
- -- the simplifier has just run, but not always.
- -- One case I found was when the last thing the simplifier
- -- did was to let-bind a non-atomic argument and then float
- -- it to the top level. So it seems more robust just to
- -- fix it here.
- arity = exprArity rhs
-
+ bndr1 = mkGlobalId details name' ty' idinfo'
+ details = idDetails bndr -- Preserve the IdDetails
+ ty' = tidyTopType (idType bndr)
+ rhs1 = tidyExpr rhs_tidy_env rhs
+ idinfo' = tidyTopIdInfo rhs_tidy_env name' rhs rhs1 (idInfo bndr)
+ show_unfold caf_info
-- tidyTopIdInfo creates the final IdInfo for top-level
-- binders. There are two delicate pieces:
-- occurrences of the binders in RHSs, and hence to occurrences in
-- unfoldings, which are inside Ids imported by GHCi. Ditto RULES.
-- CoreToStg makes use of this when constructing SRTs.
-tidyTopIdInfo :: Bool -> IdInfo -> Unfolding
- -> ArityInfo -> CafInfo -> OccInfo
- -> IdInfo
-tidyTopIdInfo is_external idinfo unfold_info arity caf_info occ_info
+tidyTopIdInfo :: TidyEnv -> Name -> CoreExpr -> CoreExpr
+ -> IdInfo -> Bool -> CafInfo -> IdInfo
+tidyTopIdInfo rhs_tidy_env name orig_rhs tidy_rhs idinfo show_unfold caf_info
| not is_external -- For internal Ids (not externally visible)
= vanillaIdInfo -- we only need enough info for code generation
-- Arity and strictness info are enough;
-- c.f. CoreTidy.tidyLetBndr
- `setOccInfo` robust_occ_info
- `setCafInfo` caf_info
- `setArityInfo` arity
- `setStrictnessInfo` strictnessInfo idinfo
+ `setCafInfo` caf_info
+ `setArityInfo` arity
+ `setStrictnessInfo` final_sig
| otherwise -- Externally-visible Ids get the whole lot
= vanillaIdInfo
- `setOccInfo` robust_occ_info
`setCafInfo` caf_info
`setArityInfo` arity
- `setStrictnessInfo` strictnessInfo idinfo
- `setInlinePragInfo` inlinePragInfo idinfo
+ `setStrictnessInfo` final_sig
+ `setOccInfo` robust_occ_info
+ `setInlinePragInfo` (inlinePragInfo idinfo)
`setUnfoldingInfo` unfold_info
-- NB: we throw away the Rules
-- They have already been extracted by findExternalRules
where
- robust_occ_info = zapFragileOcc occ_info
+ is_external = isExternalName name
+
+ --------- OccInfo ------------
+ robust_occ_info = zapFragileOcc (occInfo idinfo)
-- It's important to keep loop-breaker information
-- when we are doing -fexpose-all-unfoldings
+ --------- Strictness ------------
+ final_sig | Just sig <- strictnessInfo idinfo
+ = WARN( _bottom_hidden sig, ppr name ) Just sig
+ | Just (_, sig) <- mb_bot_str = Just sig
+ | otherwise = Nothing
+
+ -- If the cheap-and-cheerful bottom analyser can see that
+ -- the RHS is bottom, it should jolly well be exposed
+ _bottom_hidden id_sig = case mb_bot_str of
+ Nothing -> False
+ Just (arity, _) -> not (appIsBottom id_sig arity)
+
+ mb_bot_str = exprBotStrictness_maybe orig_rhs
+
+ --------- Unfolding ------------
+ unf_info = unfoldingInfo idinfo
+ unfold_info | show_unfold = tidyUnfolding rhs_tidy_env tidy_rhs final_sig unf_info
+ | otherwise = noUnfolding
+ -- NB: do *not* expose the worker if show_unfold is off,
+ -- because that means this thing is a loop breaker or
+ -- marked NOINLINE or something like that
+ -- This is important: if you expose the worker for a loop-breaker
+ -- then you can make the simplifier go into an infinite loop, because
+ -- in effect the unfolding is exposed. See Trac #1709
+ --
+ -- You might think that if show_unfold is False, then the thing should
+ -- not be w/w'd in the first place. But a legitimate reason is this:
+ -- the function returns bottom
+ -- In this case, show_unfold will be false (we don't expose unfoldings
+ -- for bottoming functions), but we might still have a worker/wrapper
+ -- split (see Note [Worker-wrapper for bottoming functions] in WorkWrap.lhs
+
+ --------- Arity ------------
+ -- Usually the Id will have an accurate arity on it, because
+ -- the simplifier has just run, but not always.
+ -- One case I found was when the last thing the simplifier
+ -- did was to let-bind a non-atomic argument and then float
+ -- it to the top level. So it seems more robust just to
+ -- fix it here.
+ arity = exprArity orig_rhs
+
------------ Unfolding --------------
-tidyUnfolding :: TidyEnv -> CoreExpr -> Unfolding -> Unfolding
-tidyUnfolding tidy_env _ (DFunUnfolding con ids)
- = DFunUnfolding con (map (tidyExpr tidy_env) ids)
-tidyUnfolding tidy_env tidy_rhs unf@(CoreUnfolding { uf_tmpl = unf_rhs, uf_src = src })
+tidyUnfolding :: TidyEnv -> CoreExpr -> Maybe StrictSig -> Unfolding -> Unfolding
+tidyUnfolding tidy_env _ _ (DFunUnfolding ar con ids)
+ = DFunUnfolding ar con (map (tidyExpr tidy_env) ids)
+tidyUnfolding tidy_env tidy_rhs strict_sig
+ unf@(CoreUnfolding { uf_tmpl = unf_rhs, uf_src = src })
| isInlineRuleSource src
= unf { uf_tmpl = tidyExpr tidy_env unf_rhs, -- Preserves OccInfo
uf_src = tidyInl tidy_env src }
| otherwise
- = mkTopUnfolding tidy_rhs
-tidyUnfolding _ _ unf = unf
+ = mkTopUnfolding is_bot tidy_rhs
+ where
+ is_bot = case strict_sig of
+ Just sig -> isBottomingSig sig
+ Nothing -> False
+
+tidyUnfolding _ _ _ unf = unf
tidyInl :: TidyEnv -> UnfoldingSource -> UnfoldingSource
tidyInl tidy_env (InlineWrapper w) = InlineWrapper (tidyVarOcc tidy_env w)