import AnalFBWW ( analFBWW )
import Bag ( isEmptyBag, foldBag )
import BinderInfo ( BinderInfo{-instance Outputable-} )
-import CgCompInfo ( uNFOLDING_CREATION_THRESHOLD,
- uNFOLDING_USE_THRESHOLD,
- uNFOLDING_OVERRIDE_THRESHOLD,
- uNFOLDING_CON_DISCOUNT_WEIGHT
- )
import CmdLineOpts ( CoreToDo(..), SimplifierSwitch(..), switchIsOn,
opt_D_show_passes,
opt_D_simplifier_stats,
+ opt_D_dump_simpl,
opt_D_verbose_core2core,
opt_DoCoreLinting,
opt_FoldrBuildOn,
opt_ReportWhyUnfoldingsDisallowed,
opt_ShowImportSpecs,
- opt_UnfoldingCreationThreshold,
- opt_UnfoldingOverrideThreshold,
- opt_UnfoldingUseThreshold
+ opt_LiberateCaseThreshold
)
import CoreLint ( lintCoreBindings )
import CoreSyn
+import CoreUtils ( coreExprType )
+import SimplUtils ( etaCoreExpr, typeOkForCase )
import CoreUnfold
-import CoreUtils ( substCoreBindings )
-import ErrUtils ( ghcExit )
+import Literal ( Literal(..), literalType, mkMachInt )
+import ErrUtils ( ghcExit, dumpIfSet, doIfSet )
import FiniteMap ( FiniteMap )
import FloatIn ( floatInwards )
import FloatOut ( floatOutwards )
import FoldrBuildWW ( mkFoldrBuildWW )
-import Id ( idType, toplevelishId, idWantsToBeINLINEd,
- unfoldingUnfriendlyId, isWrapperId,
+import Id ( mkSysLocal, setIdVisibility, replaceIdInfo,
+ replacePragmaInfo, getIdDemandInfo, idType,
+ getIdInfo, getPragmaInfo, mkIdWithNewUniq,
nullIdEnv, addOneToIdEnv, delOneFromIdEnv,
- lookupIdEnv, SYN_IE(IdEnv),
- GenId{-instance Outputable-}
+ lookupIdEnv, SYN_IE(IdEnv), omitIfaceSigForId,
+ apply_to_Id,
+ GenId{-instance Outputable-}, SYN_IE(Id)
+ )
+import IdInfo ( willBeDemanded, DemandInfo )
+import Name ( isExported, isLocallyDefined,
+ isLocalName, uniqToOccName,
+ SYN_IE(Module), NamedThing(..), OccName(..)
+ )
+import TyCon ( TyCon )
+import PrimOp ( PrimOp(..) )
+import PrelVals ( unpackCStringId, unpackCString2Id,
+ integerZeroId, integerPlusOneId,
+ integerPlusTwoId, integerMinusOneId
)
-import IdInfo ( mkUnfolding )
+import Type ( maybeAppDataTyCon, isPrimType, SYN_IE(Type) )
+import TysWiredIn ( stringTy, isIntegerTy )
import LiberateCase ( liberateCase )
import MagicUFs ( MagicUnfoldingFun )
-import Maybes ( maybeToBool )
-import Outputable ( Outputable(..){-instance * (,) -} )
+import Outputable ( pprDumpStyle, printErrs,
+ PprStyle(..), Outputable(..){-instance * (,) -}
+ )
import PprCore
-import PprStyle ( PprStyle(..) )
-import PprType ( GenType{-instance Outputable-}, GenTyVar{-ditto-} )
-import Pretty ( ppShow, ppAboves, ppAbove, ppCat, ppStr )
+import PprType ( GenType{-instance Outputable-}, GenTyVar{-ditto-},
+ nmbrType
+ )
+import Pretty ( Doc, vcat, ($$), hsep )
import SAT ( doStaticArgs )
import SimplMonad ( zeroSimplCount, showSimplCount, SimplCount )
import SimplPgm ( simplifyPgm )
import Specialise
import SpecUtils ( pprSpecErrs )
import StrictAnal ( saWwTopBinds )
-import TyVar ( nullTyVarEnv, GenTyVar{-instance Eq-} )
-import Unique ( Unique{-instance Eq-} )
-import UniqSupply ( splitUniqSupply )
-import Util ( panic{-ToDo:rm-} )
-
-#ifndef OMIT_DEFORESTER
-import Deforest ( deforestProgram )
-import DefUtils ( deforestable )
-#endif
+import TyVar ( SYN_IE(TyVar), nullTyVarEnv, GenTyVar{-instance Eq-},
+ nameTyVar
+ )
+import Unique ( Unique{-instance Eq-}, Uniquable(..),
+ integerTyConKey, ratioTyConKey,
+ mkUnique, incrUnique,
+ initTidyUniques
+ )
+import UniqSupply ( UniqSupply, mkSplitUniqSupply,
+ splitUniqSupply, getUnique
+ )
+import UniqFM ( UniqFM, lookupUFM, addToUFM )
+import Usage ( SYN_IE(UVar), cloneUVar )
+import Util ( mapAccumL, assertPanic, panic{-ToDo:rm-}, pprTrace, pprPanic )
+import SrcLoc ( noSrcLoc )
+import Constants ( tARGET_MIN_INT, tARGET_MAX_INT )
+import Bag
+import Maybes
-isWrapperFor = panic "SimplCore.isWrapperFor (ToDo)"
\end{code}
\begin{code}
core2core :: [CoreToDo] -- spec of what core-to-core passes to do
-> FAST_STRING -- module name (profiling only)
- -> PprStyle -- printing style (for debugging only)
-> UniqSupply -- a name supply
-> [TyCon] -- local data tycons and tycon specialisations
-> FiniteMap TyCon [(Bool, [Maybe Type])]
-> [CoreBinding] -- input...
-> IO
- ([CoreBinding], -- results: program, plus...
- IdEnv Unfolding, -- unfoldings to be exported from here
+ ([CoreBinding], -- results: program, plus...
SpecialiseData) -- specialisation data
-core2core core_todos module_name ppr_style us local_tycons tycon_specs binds
- = if null core_todos then -- very rare, I suspect...
- -- well, we still must do some renumbering
- return (
- (substCoreBindings nullIdEnv nullTyVarEnv binds us,
- nullIdEnv,
- init_specdata)
- )
- else
- (if do_verbose_core2core then
- hPutStr stderr "VERBOSE CORE-TO-CORE:\n"
- else return ()) >>
-
- -- better do the main business
- foldl_mn do_core_pass
- (binds, us, nullIdEnv, init_specdata, zeroSimplCount)
+core2core core_todos module_name us local_tycons tycon_specs binds
+ = -- Do the main business
+ foldl_mn do_core_pass
+ (binds, us, init_specdata, zeroSimplCount)
core_todos
- >>= \ (processed_binds, _, inline_env, spec_data, simpl_stats) ->
-
- (if opt_D_simplifier_stats
- then hPutStr stderr ("\nSimplifier Stats:\n")
- >>
- hPutStr stderr (showSimplCount simpl_stats)
- >>
- hPutStr stderr "\n"
- else return ()
- ) >>
-
- return (processed_binds, inline_env, spec_data)
- where
- init_specdata = initSpecData local_tycons tycon_specs
+ >>= \ (processed_binds, us', spec_data, simpl_stats) ->
+
+ -- Do the final tidy-up
+ let
+ final_binds = tidyCorePgm module_name processed_binds
+ in
+ lintCoreBindings "TidyCorePgm" True final_binds >>
- do_verbose_core2core = opt_D_verbose_core2core
- lib_case_threshold -- ToDo: HACK HACK HACK : FIX ME FIX ME FIX ME
- -- Use 4x a known threshold
- = case opt_UnfoldingOverrideThreshold of
- Nothing -> 4 * uNFOLDING_USE_THRESHOLD
- Just xx -> 4 * xx
+ -- Dump output
+ dumpIfSet (opt_D_dump_simpl || opt_D_verbose_core2core)
+ "Core transformations"
+ (pprCoreBindings pprDumpStyle final_binds) >>
- -------------
- core_linter = if opt_DoCoreLinting
- then lintCoreBindings ppr_style
- else ( \ whodunnit spec_done binds -> binds )
+ -- Report statistics
+ doIfSet opt_D_simplifier_stats
+ (hPutStr stderr ("\nSimplifier Stats:\n") >>
+ hPutStr stderr (showSimplCount simpl_stats) >>
+ hPutStr stderr "\n") >>
+
+ -- Return results
+ return (final_binds, spec_data)
+ where
+ init_specdata = initSpecData local_tycons tycon_specs
--------------
- do_core_pass info@(binds, us, inline_env, spec_data, simpl_stats) to_do
- = let
- (us1, us2) = splitUniqSupply us
- in
+ do_core_pass info@(binds, us, spec_data, simpl_stats) to_do =
+ case (splitUniqSupply us) of
+ (us1,us2) ->
case to_do of
CoreDoSimplify simpl_sw_chkr
-> _scc_ "CoreSimplify"
then " (foldr/build)" else "") >>
case (simplifyPgm binds simpl_sw_chkr simpl_stats us1) of
(p, it_cnt, simpl_stats2)
- -> end_pass False us2 p inline_env spec_data simpl_stats2
+ -> end_pass us2 p spec_data simpl_stats2
("Simplify (" ++ show it_cnt ++ ")"
++ if switchIsOn simpl_sw_chkr SimplDoFoldrBuild
then " foldr/build" else "")
-> _scc_ "CoreDoFoldrBuildWorkerWrapper"
begin_pass "FBWW" >>
case (mkFoldrBuildWW us1 binds) of { binds2 ->
- end_pass False us2 binds2 inline_env spec_data simpl_stats "FBWW" }
+ end_pass us2 binds2 spec_data simpl_stats "FBWW" }
CoreDoFoldrBuildWWAnal
-> _scc_ "CoreDoFoldrBuildWWAnal"
begin_pass "AnalFBWW" >>
case (analFBWW binds) of { binds2 ->
- end_pass False us2 binds2 inline_env spec_data simpl_stats "AnalFBWW" }
+ end_pass us2 binds2 spec_data simpl_stats "AnalFBWW" }
CoreLiberateCase
-> _scc_ "LiberateCase"
begin_pass "LiberateCase" >>
- case (liberateCase lib_case_threshold binds) of { binds2 ->
- end_pass False us2 binds2 inline_env spec_data simpl_stats "LiberateCase" }
-
- CoreDoCalcInlinings1 -- avoid inlinings w/ cost-centres
- -> _scc_ "CoreInlinings1"
- begin_pass "CalcInlinings" >>
- case (calcInlinings False inline_env binds) of { inline_env2 ->
- end_pass False us2 binds inline_env2 spec_data simpl_stats "CalcInlinings" }
-
- CoreDoCalcInlinings2 -- allow inlinings w/ cost-centres
- -> _scc_ "CoreInlinings2"
- begin_pass "CalcInlinings" >>
- case (calcInlinings True inline_env binds) of { inline_env2 ->
- end_pass False us2 binds inline_env2 spec_data simpl_stats "CalcInlinings" }
+ case (liberateCase opt_LiberateCaseThreshold binds) of { binds2 ->
+ end_pass us2 binds2 spec_data simpl_stats "LiberateCase" }
CoreDoFloatInwards
-> _scc_ "FloatInwards"
begin_pass "FloatIn" >>
case (floatInwards binds) of { binds2 ->
- end_pass False us2 binds2 inline_env spec_data simpl_stats "FloatIn" }
+ end_pass us2 binds2 spec_data simpl_stats "FloatIn" }
CoreDoFullLaziness
-> _scc_ "CoreFloating"
begin_pass "FloatOut" >>
case (floatOutwards us1 binds) of { binds2 ->
- end_pass False us2 binds2 inline_env spec_data simpl_stats "FloatOut" }
+ end_pass us2 binds2 spec_data simpl_stats "FloatOut" }
CoreDoStaticArgs
-> _scc_ "CoreStaticArgs"
begin_pass "StaticArgs" >>
case (doStaticArgs binds us1) of { binds2 ->
- end_pass False us2 binds2 inline_env spec_data simpl_stats "StaticArgs" }
+ end_pass us2 binds2 spec_data simpl_stats "StaticArgs" }
-- Binds really should be dependency-analysed for static-
-- arg transformation... Not to worry, they probably are.
-- (I don't think it *dies* if they aren't [WDP 94/04/15])
-> _scc_ "CoreStranal"
begin_pass "StrAnal" >>
case (saWwTopBinds us1 binds) of { binds2 ->
- end_pass False us2 binds2 inline_env spec_data simpl_stats "StrAnal" }
+ end_pass us2 binds2 spec_data simpl_stats "StrAnal" }
CoreDoSpecialising
-> _scc_ "Specialise"
spec_errs spec_warn spec_tyerrs)) ->
-- if we got errors, we die straight away
- (if not spec_noerrs ||
- (opt_ShowImportSpecs && not (isEmptyBag spec_warn)) then
- hPutStr stderr (ppShow 1000 {-pprCols-}
+ doIfSet ((not spec_noerrs) ||
+ (opt_ShowImportSpecs && not (isEmptyBag spec_warn)))
+ (printErrs
(pprSpecErrs module_name spec_errs spec_warn spec_tyerrs))
- >> hPutStr stderr "\n"
- else
- return ()) >>
+ >>
- (if not spec_noerrs then -- Stop here if specialisation errors occured
- ghcExit 1
- else
- return ()) >>
+ doIfSet (not spec_noerrs) -- Stop here if specialisation errors occured
+ (ghcExit 1) >>
- end_pass False us2 p inline_env spec_data2 simpl_stats "Specialise"
+ end_pass us2 p spec_data2 simpl_stats "Specialise"
}
- CoreDoDeforest
-#if OMIT_DEFORESTER
- -> error "ERROR: CoreDoDeforest: not built into compiler\n"
-#else
- -> _scc_ "Deforestation"
- begin_pass "Deforestation" >>
- case (deforestProgram binds us1) of { binds2 ->
- end_pass False us2 binds2 inline_env spec_data simpl_stats "Deforestation" }
-#endif
-
CoreDoPrintCore -- print result of last pass
- -> end_pass True us2 binds inline_env spec_data simpl_stats "Print"
+ -> dumpIfSet (not opt_D_verbose_core2core) "Print Core"
+ (pprCoreBindings pprDumpStyle binds) >>
+ return (binds, us1, spec_data, simpl_stats)
-------------------------------------------------
- begin_pass
+ begin_pass what
= if opt_D_show_passes
- then \ what -> hPutStr stderr ("*** Core2Core: "++what++"\n")
- else \ what -> return ()
+ then hPutStr stderr ("*** Core2Core: "++what++"\n")
+ else return ()
- end_pass print us2 binds2 inline_env2
+ end_pass us2 binds2
spec_data2@(SpecData spec_done _ _ _ _ _ _ _)
simpl_stats2 what
- = -- report verbosely, if required
- (if (do_verbose_core2core && not print) ||
- (print && not do_verbose_core2core)
- then
- hPutStr stderr ("\n*** "++what++":\n")
- >>
- hPutStr stderr (ppShow 1000
- (ppAboves (map (pprCoreBinding ppr_style) binds2)))
- >>
- hPutStr stderr "\n"
- else
- return ()) >>
- let
- linted_binds = core_linter what spec_done binds2
- in
+ = -- Report verbosely, if required
+ dumpIfSet opt_D_verbose_core2core what
+ (pprCoreBindings pprDumpStyle binds2) >>
+
+ lintCoreBindings what spec_done binds2 >>
+
return
- (linted_binds, -- processed binds, possibly run thru CoreLint
- us2, -- UniqueSupply for the next guy
- inline_env2, -- possibly-updated inline env
- spec_data2, -- possibly-updated specialisation info
- simpl_stats2 -- accumulated simplifier stats
- )
+ (binds2, -- processed binds, possibly run thru CoreLint
+ us2, -- UniqSupply for the next guy
+ spec_data2, -- possibly-updated specialisation info
+ simpl_stats2 -- accumulated simplifier stats
+ )
+
-- here so it can be inlined...
foldl_mn f z [] = return z
foldl_mn f z (x:xs) = f z x >>= \ zz ->
- foldl_mn f zz xs
+ foldl_mn f zz xs
+\end{code}
+
+
+
+%************************************************************************
+%* *
+\subsection[SimplCore-indirections]{Eliminating indirections in Core code, and globalising}
+%* *
+%************************************************************************
+
+Several tasks are done by @tidyCorePgm@
+
+1. Eliminate indirections. The point here is to transform
+ x_local = E
+ x_exported = x_local
+ ==>
+ x_exported = E
+
+2. Make certain top-level bindings into Globals. The point is that
+ Global things get externally-visible labels at code generation
+ time
+
+3. Make the representation of NoRep literals explicit, and
+ float their bindings to the top level
+
+4. Convert
+ case x of {...; x' -> ...x'...}
+ ==>
+ case x of {...; _ -> ...x... }
+ See notes in SimplCase.lhs, near simplDefault for the reasoning here.
+
+5. *Mangle* cases involving fork# and par# in the discriminant. The
+ original templates for these primops (see @PrelVals.lhs@) constructed
+ case expressions with boolean results solely to fool the strictness
+ analyzer, the simplifier, and anyone else who might want to fool with
+ the evaluation order. At this point in the compiler our evaluation
+ order is safe. Therefore, we convert expressions of the form:
+
+ case par# e of
+ True -> rhs
+ False -> parError#
+ ==>
+ case par# e of
+ _ -> rhs
+
+6. Eliminate polymorphic case expressions. We can't generate code for them yet.
+
+7. Do eta reduction for lambda abstractions appearing in:
+ - the RHS of case alternatives
+ - the body of a let
+ These will otherwise turn into local bindings during Core->STG; better to
+ nuke them if possible. (In general the simplifier does eta expansion not
+ eta reduction, up to this point.)
+
+8. Do let-to-case. See notes in Simplify.lhs for why we defer let-to-case
+ for multi-constructor types.
+
+9. Give all binders a nice print-name. Their uniques aren't changed; rather we give
+ them lexically unique occ-names, so that we can safely print the OccNae only
+ in the interface file. [Bad idea to change the uniques, because the code
+ generator makes global labels from the uniques for local thunks etc.]
+
+
+Eliminate indirections
+~~~~~~~~~~~~~~~~~~~~~~
+In @elimIndirections@, we look for things at the top-level of the form...
+\begin{verbatim}
+ x_local = ....
+ x_exported = x_local
+\end{verbatim}
+In cases we find like this, we go {\em backwards} and replace
+\tr{x_local} with \tr{x_exported}. This save a gratuitous jump
+(from \tr{x_exported} to \tr{x_local}), and makes strictness
+information propagate better.
+
+We rely on prior eta reduction to simplify things like
+\begin{verbatim}
+ x_exported = /\ tyvars -> x_local tyvars
+==>
+ x_exported = x_local
+\end{verbatim}
+
+If more than one exported thing is equal to a local thing (i.e., the
+local thing really is shared), then we do one only:
+\begin{verbatim}
+ x_local = ....
+ x_exported1 = x_local
+ x_exported2 = x_local
+==>
+ x_exported1 = ....
+
+ x_exported2 = x_exported1
+\end{verbatim}
+
+There's a possibility of leaving unchanged something like this:
+\begin{verbatim}
+ x_local = ....
+ x_exported1 = x_local Int
+\end{verbatim}
+By the time we've thrown away the types in STG land this
+could be eliminated. But I don't think it's very common
+and it's dangerous to do this fiddling in STG land
+because we might elminate a binding that's mentioned in the
+unfolding for something.
+
+General Strategy: first collect the info; then make a \tr{Id -> Id} mapping.
+Then blast the whole program (LHSs as well as RHSs) with it.
+
+
+
+\begin{code}
+tidyCorePgm :: Module -> [CoreBinding] -> [CoreBinding]
+
+tidyCorePgm mod binds_in
+ = initTM mod indirection_env $
+ tidyTopBindings (catMaybes reduced_binds) `thenTM` \ binds ->
+ returnTM (bagToList binds)
+ where
+ (indirection_env, reduced_binds) = mapAccumL try_bind nullIdEnv binds_in
+
+ try_bind :: IdEnv CoreBinder -> CoreBinding -> (IdEnv CoreBinder, Maybe CoreBinding)
+ try_bind env_so_far (NonRec exported_binder rhs)
+ | isExported exported_binder && -- Only if this is exported
+ maybeToBool maybe_rhs_id && -- and the RHS is a simple Id
+
+ isLocallyDefined rhs_id && -- Only if this one is defined in this
+ -- module, so that we *can* change its
+ -- binding to be the exported thing!
+
+ not (isExported rhs_id) && -- Only if this one is not itself exported,
+ -- since the transformation will nuke it
+
+ not (omitIfaceSigForId rhs_id) && -- Don't do the transformation if rhs_id is
+ -- something like a constructor, whose
+ -- definition is implicitly exported and
+ -- which must not vanish.
+ -- To illustrate the preceding check consider
+ -- data T = MkT Int
+ -- mkT = MkT
+ -- f x = MkT (x+1)
+ -- Here, we'll make a local, non-exported, defn for MkT, and without the
+ -- above condition we'll transform it to:
+ -- mkT = \x. MkT [x]
+ -- f = \y. mkT (y+1)
+ -- This is bad because mkT will get the IdDetails of MkT, and won't
+ -- be exported. Also the code generator won't make a definition for
+ -- the MkT constructor.
+ -- Slightly gruesome, this.
+
+ not (maybeToBool (lookupIdEnv env_so_far rhs_id))
+ -- Only if not already substituted for
+
+ = (addOneToIdEnv env_so_far rhs_id (ValBinder new_rhs_id), Nothing)
+ where
+ maybe_rhs_id = case etaCoreExpr rhs of
+ Var rhs_id -> Just rhs_id
+ other -> Nothing
+ Just rhs_id = maybe_rhs_id
+ new_rhs_id = exported_binder `replaceIdInfo` getIdInfo rhs_id
+ `replacePragmaInfo` getPragmaInfo rhs_id
+ -- NB: we keep the Pragmas and IdInfo for the old rhs_id!
+ -- This is important; it might be marked "no-inline" by
+ -- the occurrence analyser (because it's recursive), and
+ -- we must not lose that information.
+
+ try_bind env_so_far bind
+ = (env_so_far, Just bind)
+\end{code}
+
+Top level bindings
+~~~~~~~~~~~~~~~~~~
+\begin{code}
+tidyTopBindings [] = returnTM emptyBag
+tidyTopBindings (b:bs)
+ = tidyTopBinding b $
+ tidyTopBindings bs
+
+tidyTopBinding :: CoreBinding
+ -> TopTidyM (Bag CoreBinding)
+ -> TopTidyM (Bag CoreBinding)
+
+tidyTopBinding (NonRec bndr rhs) thing_inside
+ = initNestedTM (tidyCoreExpr rhs) `thenTM` \ (rhs',floats) ->
+ mungeTopBinder bndr $ \ bndr' ->
+ thing_inside `thenTM` \ binds ->
+ returnTM ((floats `snocBag` NonRec bndr' rhs') `unionBags` binds)
+
+tidyTopBinding (Rec pairs) thing_inside
+ = mungeTopBinders binders $ \ binders' ->
+ initNestedTM (mapTM tidyCoreExpr rhss) `thenTM` \ (rhss', floats) ->
+ thing_inside `thenTM` \ binds_inside ->
+ returnTM ((floats `snocBag` Rec (binders' `zip` rhss')) `unionBags` binds_inside)
+ where
+ (binders, rhss) = unzip pairs
+\end{code}
+
+
+
+Expressions
+~~~~~~~~~~~
+\begin{code}
+tidyCoreExpr (Var v) = lookupId v `thenTM` \ v' ->
+ returnTM (Var v')
+
+tidyCoreExpr (Lit lit)
+ = litToRep lit `thenTM` \ (_, lit_expr) ->
+ returnTM lit_expr
+
+tidyCoreExpr (App fun arg)
+ = tidyCoreExpr fun `thenTM` \ fun' ->
+ tidyCoreArg arg `thenTM` \ arg' ->
+ returnTM (App fun' arg')
+
+tidyCoreExpr (Con con args)
+ = mapTM tidyCoreArg args `thenTM` \ args' ->
+ returnTM (Con con args')
+
+tidyCoreExpr (Prim prim args)
+ = tidyPrimOp prim `thenTM` \ prim' ->
+ mapTM tidyCoreArg args `thenTM` \ args' ->
+ returnTM (Prim prim' args')
+
+tidyCoreExpr (Lam (ValBinder v) body)
+ = newId v $ \ v' ->
+ tidyCoreExpr body `thenTM` \ body' ->
+ returnTM (Lam (ValBinder v') body')
+
+tidyCoreExpr (Lam (TyBinder tv) body)
+ = newTyVar tv $ \ tv' ->
+ tidyCoreExpr body `thenTM` \ body' ->
+ returnTM (Lam (TyBinder tv') body')
+
+tidyCoreExpr (Lam (UsageBinder uv) body)
+ = newUVar uv $ \ uv' ->
+ tidyCoreExpr body `thenTM` \ body' ->
+ returnTM (Lam (UsageBinder uv') body')
+
+ -- Try for let-to-case (see notes in Simplify.lhs for why
+ -- some let-to-case stuff is deferred to now).
+tidyCoreExpr (Let (NonRec bndr rhs) body)
+ | willBeDemanded (getIdDemandInfo bndr) &&
+ typeOkForCase (idType bndr)
+ = ASSERT( not (isPrimType (idType bndr)) )
+ tidyCoreExpr (Case rhs (AlgAlts [] (BindDefault bndr body)))
+
+tidyCoreExpr (Let (NonRec bndr rhs) body)
+ = tidyCoreExpr rhs `thenTM` \ rhs' ->
+ newId bndr $ \ bndr' ->
+ tidyCoreExprEta body `thenTM` \ body' ->
+ returnTM (Let (NonRec bndr' rhs') body')
+
+tidyCoreExpr (Let (Rec pairs) body)
+ = newIds bndrs $ \ bndrs' ->
+ mapTM tidyCoreExpr rhss `thenTM` \ rhss' ->
+ tidyCoreExprEta body `thenTM` \ body' ->
+ returnTM (Let (Rec (bndrs' `zip` rhss')) body')
+ where
+ (bndrs, rhss) = unzip pairs
+
+tidyCoreExpr (SCC cc body)
+ = tidyCoreExprEta body `thenTM` \ body' ->
+ returnTM (SCC cc body')
+
+tidyCoreExpr (Coerce coercion ty body)
+ = tidyCoreExprEta body `thenTM` \ body' ->
+ tidyTy ty `thenTM` \ ty' ->
+ returnTM (Coerce coercion ty' body')
+
+-- Wierd case for par, seq, fork etc. See notes above.
+tidyCoreExpr (Case scrut@(Prim op args) (PrimAlts _ (BindDefault binder rhs)))
+ | funnyParallelOp op
+ = tidyCoreExpr scrut `thenTM` \ scrut' ->
+ newId binder $ \ binder' ->
+ tidyCoreExprEta rhs `thenTM` \ rhs' ->
+ returnTM (Case scrut' (PrimAlts [] (BindDefault binder' rhs')))
+
+-- Eliminate polymorphic case, for which we can't generate code just yet
+tidyCoreExpr (Case scrut (AlgAlts [] (BindDefault deflt_bndr rhs)))
+ | not (typeOkForCase (idType deflt_bndr))
+ = pprTrace "Warning: discarding polymorphic case:" (ppr PprDebug scrut) $
+ case scrut of
+ Var v -> lookupId v `thenTM` \ v' ->
+ extendEnvTM deflt_bndr v' (tidyCoreExpr rhs)
+ other -> tidyCoreExpr (Let (NonRec deflt_bndr scrut) rhs)
+
+tidyCoreExpr (Case scrut alts)
+ = tidyCoreExpr scrut `thenTM` \ scrut' ->
+ tidy_alts scrut' alts `thenTM` \ alts' ->
+ returnTM (Case scrut' alts')
+ where
+ tidy_alts scrut (AlgAlts alts deflt)
+ = mapTM tidy_alg_alt alts `thenTM` \ alts' ->
+ tidy_deflt scrut deflt `thenTM` \ deflt' ->
+ returnTM (AlgAlts alts' deflt')
+
+ tidy_alts scrut (PrimAlts alts deflt)
+ = mapTM tidy_prim_alt alts `thenTM` \ alts' ->
+ tidy_deflt scrut deflt `thenTM` \ deflt' ->
+ returnTM (PrimAlts alts' deflt')
+
+ tidy_alg_alt (con,bndrs,rhs) = newIds bndrs $ \ bndrs' ->
+ tidyCoreExprEta rhs `thenTM` \ rhs' ->
+ returnTM (con, bndrs', rhs')
+
+ tidy_prim_alt (lit,rhs) = tidyCoreExprEta rhs `thenTM` \ rhs' ->
+ returnTM (lit,rhs')
+
+ -- We convert case x of {...; x' -> ...x'...}
+ -- to
+ -- case x of {...; _ -> ...x... }
+ --
+ -- See notes in SimplCase.lhs, near simplDefault for the reasoning.
+ -- It's quite easily done: simply extend the environment to bind the
+ -- default binder to the scrutinee.
+
+ tidy_deflt scrut NoDefault = returnTM NoDefault
+ tidy_deflt scrut (BindDefault bndr rhs)
+ = newId bndr $ \ bndr' ->
+ extend_env (tidyCoreExprEta rhs) `thenTM` \ rhs' ->
+ returnTM (BindDefault bndr' rhs')
+ where
+ extend_env = case scrut of
+ Var v -> extendEnvTM bndr v
+ other -> \x -> x
+
+tidyCoreExprEta e = tidyCoreExpr e `thenTM` \ e' ->
+ returnTM (etaCoreExpr e')
+\end{code}
+
+Arguments
+~~~~~~~~~
+\begin{code}
+tidyCoreArg :: CoreArg -> NestTidyM CoreArg
+
+tidyCoreArg (VarArg v)
+ = lookupId v `thenTM` \ v' ->
+ returnTM (VarArg v')
+
+tidyCoreArg (LitArg lit)
+ = litToRep lit `thenTM` \ (lit_ty, lit_expr) ->
+ case lit_expr of
+ Var v -> returnTM (VarArg v)
+ Lit l -> returnTM (LitArg l)
+ other -> addTopFloat lit_ty lit_expr `thenTM` \ v ->
+ returnTM (VarArg v)
+
+tidyCoreArg (TyArg ty) = tidyTy ty `thenTM` \ ty' ->
+ returnTM (TyArg ty')
+tidyCoreArg (UsageArg u) = returnTM (UsageArg u)
+\end{code}
+
+\begin{code}
+tidyPrimOp (CCallOp fn casm gc tys ty)
+ = mapTM tidyTy tys `thenTM` \ tys' ->
+ tidyTy ty `thenTM` \ ty' ->
+ returnTM (CCallOp fn casm gc tys' ty')
+
+tidyPrimOp other_prim_op = returnTM other_prim_op
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection[coreToStg-lits]{Converting literals}
+%* *
+%************************************************************************
+
+Literals: the NoRep kind need to be de-no-rep'd.
+We always replace them with a simple variable, and float a suitable
+binding out to the top level.
+
+\begin{code}
+
+litToRep :: Literal -> NestTidyM (Type, CoreExpr)
+
+litToRep (NoRepStr s)
+ = returnTM (stringTy, rhs)
+ where
+ rhs = if (any is_NUL (_UNPK_ s))
+
+ then -- Must cater for NULs in literal string
+ mkGenApp (Var unpackCString2Id)
+ [LitArg (MachStr s),
+ LitArg (mkMachInt (toInteger (_LENGTH_ s)))]
+
+ else -- No NULs in the string
+ App (Var unpackCStringId) (LitArg (MachStr s))
+
+ is_NUL c = c == '\0'
+\end{code}
+
+If an Integer is small enough (Haskell implementations must support
+Ints in the range $[-2^29+1, 2^29-1]$), wrap it up in @int2Integer@;
+otherwise, wrap with @litString2Integer@.
+
+\begin{code}
+litToRep (NoRepInteger i integer_ty)
+ = returnTM (integer_ty, rhs)
+ where
+ rhs | i == 0 = Var integerZeroId -- Extremely convenient to look out for
+ | i == 1 = Var integerPlusOneId -- a few very common Integer literals!
+ | i == 2 = Var integerPlusTwoId
+ | i == (-1) = Var integerMinusOneId
+
+ | i > tARGET_MIN_INT && -- Small enough, so start from an Int
+ i < tARGET_MAX_INT
+ = Prim Int2IntegerOp [LitArg (mkMachInt i)]
+
+ | otherwise -- Big, so start from a string
+ = Prim Addr2IntegerOp [LitArg (MachStr (_PK_ (show i)))]
+
+
+litToRep (NoRepRational r rational_ty)
+ = tidyCoreArg (LitArg (NoRepInteger (numerator r) integer_ty)) `thenTM` \ num_arg ->
+ tidyCoreArg (LitArg (NoRepInteger (denominator r) integer_ty)) `thenTM` \ denom_arg ->
+ returnTM (rational_ty, Con ratio_data_con [TyArg integer_ty, num_arg, denom_arg])
+ where
+ (ratio_data_con, integer_ty)
+ = case (maybeAppDataTyCon rational_ty) of
+ Just (tycon, [i_ty], [con])
+ -> ASSERT(isIntegerTy i_ty && uniqueOf tycon == ratioTyConKey)
+ (con, i_ty)
+
+ _ -> (panic "ratio_data_con", panic "integer_ty")
+
+litToRep other_lit = returnTM (literalType other_lit, Lit other_lit)
+\end{code}
+
+\begin{code}
+funnyParallelOp SeqOp = True
+funnyParallelOp ParOp = True
+funnyParallelOp ForkOp = True
+funnyParallelOp _ = False
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{The monad}
+%* *
+%************************************************************************
+
+\begin{code}
+type TidyM a state = Module
+ -> UniqFM CoreBinder -- Maps Ids to Ids, TyVars to TyVars etc
+ -> state
+ -> (a, state)
+
+type TopTidyM a = TidyM a Unique
+type NestTidyM a = TidyM a (Unique, -- Global names
+ Unique, -- Local names
+ Bag CoreBinding) -- Floats
+
+
+(initialTopTidyUnique, initialNestedTidyUnique) = initTidyUniques
+
+initTM :: Module -> UniqFM CoreBinder -> TopTidyM a -> a
+initTM mod env m
+ = case m mod env initialTopTidyUnique of
+ (result, _) -> result
+
+initNestedTM :: NestTidyM a -> TopTidyM (a, Bag CoreBinding)
+initNestedTM m mod env global_us
+ = case m mod env (global_us, initialNestedTidyUnique, emptyBag) of
+ (result, (global_us', _, floats)) -> ((result, floats), global_us')
+
+returnTM v mod env usf = (v, usf)
+thenTM m k mod env usf = case m mod env usf of
+ (r, usf') -> k r mod env usf'
+
+mapTM f [] = returnTM []
+mapTM f (x:xs) = f x `thenTM` \ r ->
+ mapTM f xs `thenTM` \ rs ->
+ returnTM (r:rs)
\end{code}
---- ToDo: maybe move elsewhere ---
-For top-level, exported binders that either (a)~have been INLINEd by
-the programmer or (b)~are sufficiently ``simple'' that they should be
-inlined, we want to record this info in a suitable IdEnv.
+\begin{code}
+-- Need to extend the environment when we munge a binder, so that occurrences
+-- of the binder will print the correct way (i.e. as a global not a local)
+mungeTopBinder :: Id -> (Id -> TopTidyM a) -> TopTidyM a
+mungeTopBinder id thing_inside mod env us
+ = case lookupIdEnv env id of
+ Just (ValBinder global) -> thing_inside global mod env us -- Already bound
+
+ other -> -- Give it a new print-name unless it's an exported thing
+ -- setNameVisibility also does the local/global thing
+ let
+ (id', us') | isExported id = (id, us)
+ | otherwise
+ = (setIdVisibility (Just mod) us id,
+ incrUnique us)
+
+ new_env = addToUFM env id (ValBinder id')
+ in
+ thing_inside id' mod new_env us'
+
+mungeTopBinders [] k = k []
+mungeTopBinders (b:bs) k = mungeTopBinder b $ \ b' ->
+ mungeTopBinders bs $ \ bs' ->
+ k (b' : bs')
+
+addTopFloat :: Type -> CoreExpr -> NestTidyM Id
+addTopFloat lit_ty lit_rhs mod env (gus, lus, floats)
+ = let
+ gus' = incrUnique gus
+ lit_local = mkSysLocal SLIT("lit") gus lit_ty noSrcLoc
+ lit_id = setIdVisibility (Just mod) gus lit_local
+ in
+ (lit_id, (gus', lus, floats `snocBag` NonRec lit_id lit_rhs))
-But: if something has a ``wrapper unfolding,'' we do NOT automatically
-give it a regular unfolding (exception below). We usually assume its
-worker will get a ``regular'' unfolding. We can then treat these two
-levels of unfolding separately (we tend to be very friendly towards
-wrapper unfoldings, for example), giving more fine-tuned control.
+lookupId :: Id -> TidyM Id state
+lookupId v mod env usf
+ = case lookupUFM env v of
+ Nothing -> (v, usf)
+ Just (ValBinder v') -> (v', usf)
-The exception is: If the ``regular unfolding'' mentions no other
-global Ids (i.e., it's all PrimOps and cases and local Ids) then we
-assume it must be really good and we take it anyway.
+extendEnvTM :: Id -> Id -> (TidyM a state) -> TidyM a state
+extendEnvTM v v' m mod env usf
+ = m mod (addOneToIdEnv env v (ValBinder v')) usf
+\end{code}
-We also need to check that everything in the RHS (values and types)
-will be visible on the other side of an interface, too.
+Making new local binders
+~~~~~~~~~~~~~~~~~~~~~~~~
\begin{code}
-calcInlinings :: Bool -- True => inlinings with _scc_s are OK
- -> IdEnv Unfolding
- -> [CoreBinding]
- -> IdEnv Unfolding
+newId id thing_inside mod env (gus, local_uniq, floats)
+ = let
+ -- Give the Id a fresh print-name, *and* rename its type
+ local_uniq' = incrUnique local_uniq
+ rn_id = setIdVisibility Nothing local_uniq id
+ id' = apply_to_Id (nmbr_ty env local_uniq') rn_id
+ env' = addToUFM env id (ValBinder id')
+ in
+ thing_inside id' mod env' (gus, local_uniq', floats)
+
+newIds [] thing_inside
+ = thing_inside []
+newIds (bndr:bndrs) thing_inside
+ = newId bndr $ \ bndr' ->
+ newIds bndrs $ \ bndrs' ->
+ thing_inside (bndr' : bndrs')
-calcInlinings scc_s_OK inline_env_so_far top_binds
+
+newTyVar tyvar thing_inside mod env (gus, local_uniq, floats)
= let
- result = foldl calci inline_env_so_far top_binds
+ local_uniq' = incrUnique local_uniq
+ tyvar' = nameTyVar tyvar (uniqToOccName local_uniq)
+ env' = addToUFM env tyvar (TyBinder tyvar')
in
- --pprTrace "inline env:\n" (ppAboves (map pp_item (getIdEnvMapping result)))
- result
- where
- pp_item (binder, details)
- = ppCat [ppr PprDebug binder, ppStr "=>", pp_det details]
- where
- pp_det NoUnfolding = ppStr "_N_"
---LATER: pp_det (IWantToBeINLINEd _) = ppStr "INLINE"
- pp_det (CoreUnfolding (SimpleUnfolding _ guide expr))
- = ppAbove (ppr PprDebug guide) (ppr PprDebug expr)
- pp_det other = ppStr "???"
-
- ------------
- my_trace = if opt_ReportWhyUnfoldingsDisallowed
- then trace
- else \ msg stuff -> stuff
-
- (unfolding_creation_threshold, explicit_creation_threshold)
- = case opt_UnfoldingCreationThreshold of
- Nothing -> (uNFOLDING_CREATION_THRESHOLD, False)
- Just xx -> (xx, True)
-
- unfold_use_threshold
- = case opt_UnfoldingUseThreshold of
- Nothing -> uNFOLDING_USE_THRESHOLD
- Just xx -> xx
-
- unfold_override_threshold
- = case opt_UnfoldingOverrideThreshold of
- Nothing -> uNFOLDING_OVERRIDE_THRESHOLD
- Just xx -> xx
-
- con_discount_weight = uNFOLDING_CON_DISCOUNT_WEIGHT
-
- calci inline_env (Rec pairs)
- = foldl (calc True{-recursive-}) inline_env pairs
-
- calci inline_env bind@(NonRec binder rhs)
- = calc False{-not recursive-} inline_env (binder, rhs)
-
- ---------------------------------------
-
- calc is_recursive inline_env (binder, rhs)
- | not (toplevelishId binder)
- = --pprTrace "giving up on not top-level:" (ppr PprDebug binder)
- ignominious_defeat
-
- | rhs_mentions_an_unmentionable
- || (not explicit_INLINE_requested
- && (rhs_looks_like_a_caf || guidance_size_too_big))
- = let
- my_my_trace
- = if explicit_INLINE_requested
- && not (isWrapperId binder) -- these always claim to be INLINEd
- && not have_inlining_already
- then trace -- we'd better have a look...
- else my_trace
-
- which = if scc_s_OK then " (late):" else " (early):"
- in
- my_my_trace ("unfolding disallowed for"++which++(ppShow 80 (ppr PprDebug binder))) (
- ignominious_defeat
- )
-
- | rhs `isWrapperFor` binder
- -- Don't add an explicit "unfolding"; let the worker/wrapper
- -- stuff do its thing. INLINE things don't get w/w'd, so
- -- they will be OK.
- = ignominious_defeat
-
-#if ! OMIT_DEFORESTER
- -- For the deforester: bypass the barbed wire for recursive
- -- functions that want to be inlined and are tagged deforestable
- -- by the user, allowing these things to be communicated
- -- across module boundaries.
-
- | is_recursive &&
- explicit_INLINE_requested &&
- deforestable binder &&
- scc_s_OK -- hack, only get them in
- -- calc_inlinings2
- = glorious_success UnfoldAlways
-#endif
-
- | is_recursive && not rhs_looks_like_a_data_val
- -- The only recursive defns we are prepared to tolerate at the
- -- moment is top-level very-obviously-a-data-value ones.
- -- We *need* these for dictionaries to be exported!
- = --pprTrace "giving up on rec:" (ppr PprDebug binder)
- ignominious_defeat
-
- -- Not really interested unless it's exported, but doing it
- -- this way (not worrying about export-ness) gets us all the
- -- workers/specs, etc., too; which we will need for generating
- -- interfaces. We are also not interested if this binder is
- -- in the environment we already have (perhaps from a previous
- -- run of calcInlinings -- "earlier" is presumed to mean
- -- "better").
-
- | explicit_INLINE_requested
- = glorious_success UnfoldAlways
-
- | otherwise
- = glorious_success guidance
-
- where
- guidance
- = calcUnfoldingGuidance scc_s_OK max_out_threshold rhs
- where
- max_out_threshold = if explicit_INLINE_requested
- then 100000 -- you asked for it, you got it
- else unfolding_creation_threshold
-
- guidance_size
- = case guidance of
- UnfoldAlways -> 0 -- *extremely* small
- UnfoldIfGoodArgs _ _ _ size -> size
-
- guidance_size_too_big
- -- Does the guidance suggest that this unfolding will
- -- be of no use *no matter* the arguments given to it?
- -- Could be more sophisticated...
- = not (couldBeSmallEnoughToInline con_discount_weight unfold_use_threshold guidance)
-
-
- rhs_looks_like_a_caf = not (whnfOrBottom rhs)
-
- rhs_looks_like_a_data_val
- = case (collectBinders rhs) of
- (_, _, [], Con _ _) -> True
- other -> False
-
- rhs_arg_tys
- = case (collectBinders rhs) of
- (_, _, val_binders, _) -> map idType val_binders
-
- (mentioned_ids, _, _, mentions_litlit)
- = mentionedInUnfolding (\x -> x) rhs
-
- rhs_mentions_an_unmentionable
- = foldBag (||) unfoldingUnfriendlyId False mentioned_ids
- || mentions_litlit
- -- ToDo: probably need to chk tycons/classes...
-
- mentions_no_other_ids = isEmptyBag mentioned_ids
-
- explicit_INLINE_requested
- -- did it come from a user {-# INLINE ... #-}?
- -- (Warning: must avoid including wrappers.)
- = idWantsToBeINLINEd binder
- && not (rhs `isWrapperFor` binder)
-
- have_inlining_already = maybeToBool (lookupIdEnv inline_env binder)
-
- ignominious_defeat = inline_env -- just give back what we got
-
- {-
- "glorious_success" is ours if we've found a suitable unfolding.
-
- But we check for a couple of fine points.
-
- (1) If this Id already has an inlining in the inline_env,
- we don't automatically take it -- the earlier one is
- "likely" to be better.
-
- But if the new one doesn't mention any other global
- Ids, and it's pretty small (< UnfoldingOverrideThreshold),
- then we take the chance that the new one *is* better.
-
- (2) If we have an Id w/ a worker/wrapper split (with
- an unfolding for the wrapper), we tend to want to keep
- it -- and *nuke* any inlining that we conjured up
- earlier.
-
- But, again, if this unfolding doesn't mention any
- other global Ids (and small enough), then it is
- probably better than the worker/wrappery, so we take
- it.
- -}
- glorious_success guidance
- = let
- new_env = addOneToIdEnv inline_env binder (mkUnfolding guidance rhs)
-
- foldr_building = opt_FoldrBuildOn
- in
- if (not have_inlining_already) then
- -- Not in env: we take it no matter what
- -- NB: we could check for worker/wrapper-ness,
- -- but the truth is we probably haven't run
- -- the strictness analyser yet.
- new_env
-
- else if explicit_INLINE_requested then
- -- If it was a user INLINE, then we know it's already
- -- in the inline_env; we stick with what we already
- -- have.
- --pprTrace "giving up on INLINE:" (ppr PprDebug binder)
- ignominious_defeat
-
- else if isWrapperId binder then
- -- It's in the env, but we have since worker-wrapperised;
- -- we either take this new one (because it's so good),
- -- or we *undo* the one in the inline_env, so the
- -- wrapper-inlining will take over.
-
- if mentions_no_other_ids {- *** && size <= unfold_override_threshold -} then
- new_env
- else
- delOneFromIdEnv inline_env binder
-
- else
- -- It's in the env, nothing to do w/ worker wrapper;
- -- we'll take it if it is better.
-
- if not foldr_building -- ANDY hates us... (see below)
- && mentions_no_other_ids
- && guidance_size <= unfold_override_threshold then
- new_env
- else
- --pprTrace "giving up on final hurdle:" (ppCat [ppr PprDebug binder, ppInt guidance_size, ppInt unfold_override_threshold])
- ignominious_defeat -- and at the last hurdle, too!
+ thing_inside tyvar' mod env' (gus, local_uniq', floats)
+
+newUVar uvar thing_inside mod env (gus, local_uniq, floats)
+ = let
+ local_uniq' = incrUnique local_uniq
+ uvar' = cloneUVar uvar local_uniq
+ env' = addToUFM env uvar (UsageBinder uvar')
+ in
+ thing_inside uvar' mod env' (gus, local_uniq', floats)
\end{code}
-ANDY, on the hatred of the check above; why obliterate it? Consider
+Re-numbering types
+~~~~~~~~~~~~~~~~~~
+\begin{code}
+tidyTy ty mod env usf@(_, local_uniq, _)
+ = (nmbr_ty env local_uniq ty, usf)
+ -- We can use local_uniq as a base for renaming forall'd variables
+ -- in the type; we don't need to know how many are consumed.
+
+-- This little impedance-matcher calls nmbrType with the right arguments
+nmbr_ty env uniq ty
+ = nmbrType tv_env u_env uniq ty
+ where
+ tv_env :: TyVar -> TyVar
+ tv_env tyvar = case lookupUFM env tyvar of
+ Just (TyBinder tyvar') -> tyvar'
+ other -> tyvar
+
+ u_env :: UVar -> UVar
+ u_env uvar = case lookupUFM env uvar of
+ Just (UsageBinder uvar') -> uvar'
+ other -> uvar
+\end{code}
- head xs = foldr (\ x _ -> x) (_|_) xs
-This then is exported via a pragma. However,
-*if* you include the extra code above, you will
-export the non-foldr/build version.