\section[SimplCore]{Driver for simplifying @Core@ programs}
\begin{code}
-#include "HsVersions.h"
-
module SimplCore ( core2core ) where
-IMP_Ubiq(){-uitous-}
-IMPORT_1_3(IO(hPutStr,stderr))
+#include "HsVersions.h"
import AnalFBWW ( analFBWW )
import Bag ( isEmptyBag, foldBag )
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,
import CoreLint ( lintCoreBindings )
import CoreSyn
import CoreUtils ( coreExprType )
+import SimplUtils ( etaCoreExpr, typeOkForCase )
import CoreUnfold
import Literal ( Literal(..), literalType, mkMachInt )
-import ErrUtils ( ghcExit )
-import FiniteMap ( FiniteMap )
+import ErrUtils ( ghcExit, dumpIfSet, doIfSet )
+import FiniteMap ( FiniteMap, emptyFM )
import FloatIn ( floatInwards )
import FloatOut ( floatOutwards )
import FoldrBuildWW ( mkFoldrBuildWW )
-import Id ( mkSysLocal, setIdVisibility,
+import MkId ( mkSysLocal, mkUserId )
+import Id ( setIdVisibility, getIdSpecialisation, setIdSpecialisation,
+ getIdDemandInfo, idType,
nullIdEnv, addOneToIdEnv, delOneFromIdEnv,
- lookupIdEnv, SYN_IE(IdEnv),
- GenId{-instance Outputable-}
+ lookupIdEnv, IdEnv,
+ Id
+ )
+import IdInfo ( willBeDemanded, DemandInfo )
+import Name ( isExported, isLocallyDefined,
+ isLocalName, uniqToOccName,
+ setNameVisibility,
+ Module, NamedThing(..), OccName(..)
)
-import Name ( isExported, isLocallyDefined )
import TyCon ( TyCon )
import PrimOp ( PrimOp(..) )
import PrelVals ( unpackCStringId, unpackCString2Id,
integerZeroId, integerPlusOneId,
integerPlusTwoId, integerMinusOneId
)
-import Type ( maybeAppDataTyCon, getAppDataTyConExpandingDicts, maybeAppSpecDataTyConExpandingDicts )
-import TysWiredIn ( stringTy )
+import Type ( splitAlgTyConApp_maybe, isUnpointedType, Type )
+import TysWiredIn ( stringTy, isIntegerTy )
import LiberateCase ( liberateCase )
import MagicUFs ( MagicUnfoldingFun )
-import Outputable ( Outputable(..){-instance * (,) -} )
import PprCore
-import PprStyle ( PprStyle(..) )
-import PprType ( GenType{-instance Outputable-}, GenTyVar{-ditto-} )
-import Pretty ( ppShow, ppAboves, ppAbove, ppCat, ppStr )
+import PprType ( nmbrType )
import SAT ( doStaticArgs )
import SimplMonad ( zeroSimplCount, showSimplCount, SimplCount )
import SimplPgm ( simplifyPgm )
import Specialise
-import SpecUtils ( pprSpecErrs )
+import SpecEnv ( substSpecEnv, isEmptySpecEnv )
import StrictAnal ( saWwTopBinds )
-import TyVar ( nullTyVarEnv, GenTyVar{-instance Eq-} )
-import Unique ( integerTyConKey, ratioTyConKey, Unique{-instance Eq-} )
-import UniqSupply ( splitUniqSupply, getUnique )
-import Util ( mapAccumL, assertPanic, panic{-ToDo:rm-}, pprTrace, pprPanic )
+import TyVar ( TyVar, nameTyVar, emptyTyVarEnv )
+import Unique ( Unique{-instance Eq-}, Uniquable(..),
+ integerTyConKey, ratioTyConKey,
+ mkUnique, incrUnique,
+ initTidyUniques
+ )
+import UniqSupply ( UniqSupply, mkSplitUniqSupply,
+ splitUniqSupply, getUnique
+ )
+import UniqFM ( UniqFM, lookupUFM, addToUFM, delFromUFM )
+import Util ( mapAccumL )
import SrcLoc ( noSrcLoc )
import Constants ( tARGET_MIN_INT, tARGET_MAX_INT )
import Bag
import Maybes
-
-
-#ifndef OMIT_DEFORESTER
-import Deforest ( deforestProgram )
-import DefUtils ( deforestable )
-#endif
-
+import IO ( hPutStr, stderr )
+import Outputable
\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...
- SpecialiseData) -- specialisation data
-
-core2core core_todos module_name ppr_style us local_tycons tycon_specs binds
- = -- Print heading
- (if opt_D_verbose_core2core then
- hPutStr stderr "VERBOSE CORE-TO-CORE:\n"
- else return ()) >>
+ -> IO [CoreBinding] -- results: program
- -- Do the main business
+core2core core_todos module_name us local_tycons binds
+ = -- Do the main business
foldl_mn do_core_pass
- (binds, us1, init_specdata, zeroSimplCount)
+ (binds, us, zeroSimplCount)
core_todos
- >>= \ (processed_binds, _, spec_data, simpl_stats) ->
+ >>= \ (processed_binds, us', simpl_stats) ->
-- Do the final tidy-up
let
- final_binds = tidyCorePgm module_name us2 processed_binds
+ final_binds = tidyCorePgm module_name processed_binds
in
+ lintCoreBindings "TidyCorePgm" True final_binds >>
- -- Report statistics
- (if opt_D_simplifier_stats then
- hPutStr stderr ("\nSimplifier Stats:\n") >>
- hPutStr stderr (showSimplCount simpl_stats) >>
- hPutStr stderr "\n"
- else return ()) >>
-
- --
- return (final_binds, spec_data)
- where
- (us1, us2) = splitUniqSupply us
- init_specdata = initSpecData local_tycons tycon_specs
- -------------
- core_linter = if opt_DoCoreLinting
- then lintCoreBindings ppr_style
- else ( \ whodunnit spec_done binds -> binds )
+ -- Dump output
+ dumpIfSet (opt_D_dump_simpl || opt_D_verbose_core2core)
+ "Core transformations"
+ (pprCoreBindings final_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
+ where
--------------
- do_core_pass info@(binds, us, spec_data, simpl_stats) to_do
- = let
- (us1, us2) = splitUniqSupply us
- in
+ do_core_pass info@(binds, us, 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 spec_data simpl_stats2
+ -> end_pass us2 p 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 spec_data simpl_stats "FBWW" }
+ end_pass us2 binds2 simpl_stats "FBWW" }
CoreDoFoldrBuildWWAnal
-> _scc_ "CoreDoFoldrBuildWWAnal"
begin_pass "AnalFBWW" >>
case (analFBWW binds) of { binds2 ->
- end_pass False us2 binds2 spec_data simpl_stats "AnalFBWW" }
+ end_pass us2 binds2 simpl_stats "AnalFBWW" }
CoreLiberateCase
-> _scc_ "LiberateCase"
begin_pass "LiberateCase" >>
case (liberateCase opt_LiberateCaseThreshold binds) of { binds2 ->
- end_pass False us2 binds2 spec_data simpl_stats "LiberateCase" }
+ end_pass us2 binds2 simpl_stats "LiberateCase" }
CoreDoFloatInwards
-> _scc_ "FloatInwards"
begin_pass "FloatIn" >>
case (floatInwards binds) of { binds2 ->
- end_pass False us2 binds2 spec_data simpl_stats "FloatIn" }
+ end_pass us2 binds2 simpl_stats "FloatIn" }
CoreDoFullLaziness
-> _scc_ "CoreFloating"
begin_pass "FloatOut" >>
case (floatOutwards us1 binds) of { binds2 ->
- end_pass False us2 binds2 spec_data simpl_stats "FloatOut" }
+ end_pass us2 binds2 simpl_stats "FloatOut" }
CoreDoStaticArgs
-> _scc_ "CoreStaticArgs"
begin_pass "StaticArgs" >>
case (doStaticArgs binds us1) of { binds2 ->
- end_pass False us2 binds2 spec_data simpl_stats "StaticArgs" }
+ end_pass us2 binds2 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 spec_data simpl_stats "StrAnal" }
+ end_pass us2 binds2 simpl_stats "StrAnal" }
CoreDoSpecialising
-> _scc_ "Specialise"
begin_pass "Specialise" >>
- case (specProgram us1 binds spec_data) of {
- (p, spec_data2@(SpecData _ spec_noerrs _ _ _
- 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-}
- (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 ()) >>
-
- end_pass False us2 p spec_data2 simpl_stats "Specialise"
+ case (specProgram us1 binds) of { p ->
+ end_pass us2 p 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 spec_data simpl_stats "Deforestation" }
-#endif
-
CoreDoPrintCore -- print result of last pass
- -> end_pass True us2 binds spec_data simpl_stats "Print"
+ -> dumpIfSet (not opt_D_verbose_core2core) "Print Core"
+ (pprCoreBindings binds) >>
+ return (binds, us1, 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
- spec_data2@(SpecData spec_done _ _ _ _ _ _ _)
+ end_pass us2 binds2
simpl_stats2 what
- = -- report verbosely, if required
- (if (opt_D_verbose_core2core && not print) ||
- (print && not opt_D_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 binds2) >>
+
+ lintCoreBindings what True {- spec_done -} binds2 >>
+ -- The spec_done flag tells the linter to
+ -- complain about unboxed let-bindings
+ -- But we're not specialising unboxed types any more,
+ -- so its irrelevant.
+
return
- (linted_binds, -- processed binds, possibly run thru CoreLint
- us2, -- UniqueSupply for the next guy
- spec_data2, -- possibly-updated specialisation info
- simpl_stats2 -- accumulated simplifier stats
- )
+ (binds2, -- processed binds, possibly run thru CoreLint
+ us2, -- UniqSupply for the next guy
+ simpl_stats2 -- accumulated simplifier stats
+ )
+
-- here so it can be inlined...
foldl_mn f z [] = return z
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
+----------------
+ [March 98] Indirections are now elimianted by the occurrence analyser
+ -- 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
6. Eliminate polymorphic case expressions. We can't generate code for them yet.
-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.
+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.]
+
\begin{code}
-tidyCorePgm :: Module -> UniqSupply -> [CoreBinding] -> [CoreBinding]
+tidyCorePgm :: Module -> [CoreBinding] -> [CoreBinding]
-tidyCorePgm mod us binds_in
- = initTM mod indirection_env us $
- tidyTopBindings (catMaybes reduced_binds) `thenTM` \ binds ->
+tidyCorePgm mod binds_in
+ = initTM mod nullIdEnv $
+ tidyTopBindings binds_in `thenTM` \ binds ->
returnTM (bagToList binds)
- where
- (indirection_env, reduced_binds) = mapAccumL try_bind nullIdEnv binds_in
-
- try_bind :: IdEnv Id -> CoreBinding -> (IdEnv Id, Maybe CoreBinding)
- try_bind env_so_far
- (NonRec exported_binder (Var local_id))
- | isExported exported_binder && -- Only if this is exported
- isLocallyDefined local_id && -- Only if this one is defined in this
- not (isExported local_id) && -- module, so that we *can* change its
- -- binding to be the exported thing!
- not (maybeToBool (lookupIdEnv env_so_far local_id))
- -- Only if not already substituted for
- = (addOneToIdEnv env_so_far local_id exported_binder, Nothing)
-
- try_bind env_so_far bind
- = (env_so_far, Just bind)
\end{code}
Top level bindings
tidyTopBindings bs
tidyTopBinding :: CoreBinding
- -> TidyM (Bag CoreBinding)
- -> TidyM (Bag CoreBinding)
+ -> TopTidyM (Bag CoreBinding)
+ -> TopTidyM (Bag CoreBinding)
tidyTopBinding (NonRec bndr rhs) thing_inside
- = getFloats (tidyCoreExpr rhs) `thenTM` \ (rhs',floats) ->
+ = 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' ->
- getFloats (mapTM tidyCoreExpr rhss) `thenTM` \ (rhss', floats) ->
+ initNestedTM (mapTM tidyCoreExpr rhss) `thenTM` \ (rhss', floats) ->
thing_inside `thenTM` \ binds_inside ->
returnTM ((floats `snocBag` Rec (binders' `zip` rhss')) `unionBags` binds_inside)
where
\end{code}
-Local Bindings
-~~~~~~~~~~~~~~
-\begin{code}
-tidyCoreBinding (NonRec bndr rhs)
- = tidyCoreExpr rhs `thenTM` \ rhs' ->
- returnTM (NonRec bndr rhs')
-
-tidyCoreBinding (Rec pairs)
- = mapTM do_one pairs `thenTM` \ pairs' ->
- returnTM (Rec pairs')
- where
- do_one (bndr,rhs) = tidyCoreExpr rhs `thenTM` \ rhs' ->
- returnTM (bndr, rhs')
-
-\end{code}
-
Expressions
~~~~~~~~~~~
\begin{code}
-tidyCoreExpr (Var v) = lookupTM v `thenTM` \ v' ->
+tidyCoreExpr (Var v) = lookupId v `thenTM` \ v' ->
returnTM (Var v')
tidyCoreExpr (Lit lit)
returnTM (Con con args')
tidyCoreExpr (Prim prim args)
- = mapTM tidyCoreArg args `thenTM` \ args' ->
- returnTM (Prim prim args')
+ = tidyPrimOp prim `thenTM` \ prim' ->
+ mapTM tidyCoreArg args `thenTM` \ args' ->
+ returnTM (Prim prim' args')
-tidyCoreExpr (Lam bndr body)
- = tidyCoreExpr body `thenTM` \ body' ->
- returnTM (Lam bndr body')
+tidyCoreExpr (Lam (ValBinder v) body)
+ = newId v $ \ v' ->
+ tidyCoreExpr body `thenTM` \ body' ->
+ returnTM (Lam (ValBinder v') body')
-tidyCoreExpr (Let bind body)
- = tidyCoreBinding bind `thenTM` \ bind' ->
+tidyCoreExpr (Lam (TyBinder tv) body)
+ = newTyVar tv $ \ tv' ->
tidyCoreExpr body `thenTM` \ body' ->
- returnTM (Let bind' body')
+ returnTM (Lam (TyBinder tv') 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) &&
+ not rhs_is_whnf && -- Don't do it if RHS is already in WHNF
+ typeOkForCase (idType bndr)
+ = ASSERT( not (isUnpointedType (idType bndr)) )
+ tidyCoreExpr (Case rhs (AlgAlts [] (BindDefault bndr body)))
+ where
+ rhs_is_whnf = case mkFormSummary rhs of
+ VarForm -> True
+ ValueForm -> True
+ other -> False
+
+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)
- = tidyCoreExpr body `thenTM` \ body' ->
- returnTM (SCC cc body')
+tidyCoreExpr (Note (Coerce to_ty from_ty) body)
+ = tidyCoreExprEta body `thenTM` \ body' ->
+ tidyTy to_ty `thenTM` \ to_ty' ->
+ tidyTy from_ty `thenTM` \ from_ty' ->
+ returnTM (Note (Coerce to_ty' from_ty') body')
-tidyCoreExpr (Coerce coercion ty body)
- = tidyCoreExpr body `thenTM` \ body' ->
- returnTM (Coerce coercion ty body')
+tidyCoreExpr (Note note body)
+ = tidyCoreExprEta body `thenTM` \ body' ->
+ returnTM (Note note 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' ->
- tidyCoreExpr rhs `thenTM` \ rhs' ->
- returnTM (Case scrut' (PrimAlts [] (BindDefault binder rhs')))
+ 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 (maybeToBool (maybeAppSpecDataTyConExpandingDicts (coreExprType scrut)))
- = pprTrace "Warning: discarding polymophic case:" (ppr PprDebug scrut) $
+ | not (typeOkForCase (idType deflt_bndr))
+ = pprTrace "Warning: discarding polymorphic case:" (ppr scrut) $
case scrut of
- Var v -> extendEnvTM deflt_bndr v (tidyCoreExpr rhs)
+ 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 alts `thenTM` \ alts' ->
+ tidy_alts scrut' alts `thenTM` \ alts' ->
returnTM (Case scrut' alts')
where
- tidy_alts (AlgAlts alts deflt)
+ tidy_alts scrut (AlgAlts alts deflt)
= mapTM tidy_alg_alt alts `thenTM` \ alts' ->
- tidy_deflt deflt `thenTM` \ deflt' ->
+ tidy_deflt scrut deflt `thenTM` \ deflt' ->
returnTM (AlgAlts alts' deflt')
- tidy_alts (PrimAlts alts deflt)
+ tidy_alts scrut (PrimAlts alts deflt)
= mapTM tidy_prim_alt alts `thenTM` \ alts' ->
- tidy_deflt deflt `thenTM` \ deflt' ->
+ tidy_deflt scrut deflt `thenTM` \ deflt' ->
returnTM (PrimAlts alts' deflt')
- tidy_alg_alt (con,bndrs,rhs) = tidyCoreExpr rhs `thenTM` \ rhs' ->
- returnTM (con,bndrs,rhs')
+ tidy_alg_alt (con,bndrs,rhs) = newIds bndrs $ \ bndrs' ->
+ tidyCoreExprEta rhs `thenTM` \ rhs' ->
+ returnTM (con, bndrs', rhs')
- tidy_prim_alt (lit,rhs) = tidyCoreExpr rhs `thenTM` \ rhs' ->
+ tidy_prim_alt (lit,rhs) = tidyCoreExprEta rhs `thenTM` \ rhs' ->
returnTM (lit,rhs')
-- We convert case x of {...; x' -> ...x'...}
-- It's quite easily done: simply extend the environment to bind the
-- default binder to the scrutinee.
- tidy_deflt NoDefault = returnTM NoDefault
- tidy_deflt (BindDefault bndr rhs)
- = extend_env (tidyCoreExpr rhs) `thenTM` \ rhs' ->
- returnTM (BindDefault bndr rhs')
+ 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 -> TidyM CoreArg
+tidyCoreArg :: CoreArg -> NestTidyM CoreArg
tidyCoreArg (VarArg v)
- = lookupTM v `thenTM` \ v' ->
+ = lookupId v `thenTM` \ v' ->
returnTM (VarArg v')
tidyCoreArg (LitArg lit)
other -> addTopFloat lit_ty lit_expr `thenTM` \ v ->
returnTM (VarArg v)
-tidyCoreArg (TyArg ty) = returnTM (TyArg ty)
-tidyCoreArg (UsageArg u) = returnTM (UsageArg u)
+tidyCoreArg (TyArg ty) = tidyTy ty `thenTM` \ ty' ->
+ returnTM (TyArg ty')
\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}
+
%************************************************************************
%* *
\begin{code}
-litToRep :: Literal -> TidyM (Type, CoreExpr)
+litToRep :: Literal -> NestTidyM (Type, CoreExpr)
litToRep (NoRepStr s)
= returnTM (stringTy, rhs)
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 [num_arg, 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
+ = case (splitAlgTyConApp_maybe rational_ty) of
Just (tycon, [i_ty], [con])
- -> ASSERT(is_integer_ty i_ty && uniqueOf tycon == ratioTyConKey)
+ -> ASSERT(isIntegerTy i_ty && uniqueOf tycon == ratioTyConKey)
(con, i_ty)
_ -> (panic "ratio_data_con", panic "integer_ty")
- is_integer_ty ty
- = case (maybeAppDataTyCon ty) of
- Just (tycon, [], _) -> uniqueOf tycon == integerTyConKey
- _ -> False
-
litToRep other_lit = returnTM (literalType other_lit, Lit other_lit)
\end{code}
%************************************************************************
\begin{code}
-type TidyM a = Module
- -> IdEnv Id
- -> (UniqSupply, Bag CoreBinding)
- -> (a, (UniqSupply, Bag CoreBinding))
+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
-initTM mod env us m
- = case m mod env (us,emptyBag) of
- (result, (us',floats)) -> 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
\begin{code}
-getFloats :: TidyM a -> TidyM (a, Bag CoreBinding)
-getFloats m mod env (us,floats)
- = case m mod env (us,emptyBag) of
- (r, (us',floats')) -> ((r, floats'), (us',floats))
-
-
-- 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 -> TidyM a) -> TidyM a
-mungeTopBinder id thing_inside mod env usf
- = case lookupIdEnv env id of
- Just global -> thing_inside global mod env usf
- Nothing -> thing_inside new_global mod new_env usf
- where
- new_env = addOneToIdEnv env id new_global
- new_global = setIdVisibility mod id
+-- of the binder will print the correct way (e.g. as a global not a local)
+mungeTopBinder :: Id -> (Id -> TopTidyM a) -> TopTidyM a
+mungeTopBinder id thing_inside mod env us
+ = -- Give it a new print-name unless it's an exported thing
+ -- setNameVisibility also does the local/global thing
+ let
+ (id1, us') | isExported id = (id, us)
+ | otherwise
+ = (setIdVisibility (Just mod) us id,
+ incrUnique us)
+
+ -- Tidy the Id's SpecEnv
+ spec_env = getIdSpecialisation id
+ id2 | isEmptySpecEnv spec_env = id1
+ | otherwise = setIdSpecialisation id1 (tidySpecEnv env spec_env)
+
+ new_env = addToUFM env id (ValBinder id2)
+ in
+ thing_inside id2 mod new_env us'
+
+tidySpecEnv env spec_env
+ = substSpecEnv
+ emptyTyVarEnv -- Top level only
+ (tidy_spec_rhs env)
+ spec_env
+ where
+ -- tidy_spec_rhs is another horrid little hacked-up function for
+ -- the RHS of specialisation templates.
+ -- It assumes there is no type substitution.
+ --
+ -- See also SimplVar.substSpecEnvRhs Urgh
+ tidy_spec_rhs env (Var v) = case lookupUFM env v of
+ Just (ValBinder v') -> Var v'
+ Nothing -> Var v
+ tidy_spec_rhs env (App f (VarArg v)) = App (tidy_spec_rhs env f) (case lookupUFM env v of
+ Just (ValBinder v') -> VarArg v'
+ Nothing -> VarArg v)
+ tidy_spec_rhs env (App f arg) = App (tidy_spec_rhs env f) arg
+ tidy_spec_rhs env (Lam b e) = Lam b (tidy_spec_rhs env' e)
+ where
+ env' = case b of
+ ValBinder id -> delFromUFM env id
+ TyBinder _ -> env
mungeTopBinders [] k = k []
mungeTopBinders (b:bs) k = mungeTopBinder b $ \ b' ->
mungeTopBinders bs $ \ bs' ->
k (b' : bs')
-addTopFloat :: Type -> CoreExpr -> TidyM Id
-addTopFloat lit_ty lit_rhs mod env (us, floats)
- = (lit_id, (us', floats `snocBag` NonRec lit_id lit_rhs))
- where
- lit_local = mkSysLocal SLIT("nrlit") uniq lit_ty noSrcLoc
- lit_id = setIdVisibility mod lit_local
- (us', us1) = splitUniqSupply us
- uniq = getUnique us1
+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))
+
+lookupId :: Id -> TidyM Id state
+lookupId v mod env usf
+ = case lookupUFM env v of
+ Nothing -> (v, usf)
+ Just (ValBinder v') -> (v', usf)
+
+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}
-lookupTM v mod env usf
- = case lookupIdEnv env v of
- Nothing -> (v, usf)
- Just v' -> (v', usf)
-extendEnvTM v v' m mod env usf
- = m mod (addOneToIdEnv env v v') usf
+Making new local binders
+~~~~~~~~~~~~~~~~~~~~~~~~
+\begin{code}
+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
+ name' = setNameVisibility Nothing local_uniq (getName id)
+ ty' = nmbr_ty env local_uniq' (idType id)
+ id' = mkUserId name' ty'
+ -- NB: This throws away the IdInfo of the Id, which we
+ -- no longer need. That means we don't need to
+ -- run over it with env, nor renumber it
+ --
+ -- NB: the Id's unique remains unchanged; it's only
+ -- its print name that is affected by local_uniq
+
+ 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')
+
+
+newTyVar tyvar thing_inside mod env (gus, local_uniq, floats)
+ = let
+ local_uniq' = incrUnique local_uniq
+ tyvar' = nameTyVar tyvar (uniqToOccName local_uniq)
+ env' = addToUFM env tyvar (TyBinder tyvar')
+ in
+ thing_inside tyvar' mod env' (gus, local_uniq', floats)
+\end{code}
+
+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 uniq ty
+ where
+ tv_env :: TyVar -> TyVar
+ tv_env tyvar = case lookupUFM env tyvar of
+ Just (TyBinder tyvar') -> tyvar'
+ other -> tyvar
\end{code}