summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/coreSyn/CoreLint.hs1
-rw-r--r--compiler/ghc.cabal.in1
-rw-r--r--compiler/simplCore/AnfiseCore.hs90
-rw-r--r--compiler/simplCore/CoreMonad.hs2
-rw-r--r--compiler/simplCore/SimplCore.hs16
5 files changed, 109 insertions, 1 deletions
diff --git a/compiler/coreSyn/CoreLint.hs b/compiler/coreSyn/CoreLint.hs
index c39fb641df..cdf729b9b6 100644
--- a/compiler/coreSyn/CoreLint.hs
+++ b/compiler/coreSyn/CoreLint.hs
@@ -265,6 +265,7 @@ coreDumpFlag CoreDoFloatInwards = Just Opt_D_verbose_core2core
coreDumpFlag (CoreDoFloatOutwards {}) = Just Opt_D_verbose_core2core
coreDumpFlag CoreLiberateCase = Just Opt_D_verbose_core2core
coreDumpFlag CoreDoStaticArgs = Just Opt_D_verbose_core2core
+coreDumpFlag CoreDoAnfise = Just Opt_D_verbose_core2core
coreDumpFlag CoreDoCallArity = Just Opt_D_dump_call_arity
coreDumpFlag CoreDoExitify = Just Opt_D_dump_exitify
coreDumpFlag CoreDoStrictness = Just Opt_D_dump_stranal
diff --git a/compiler/ghc.cabal.in b/compiler/ghc.cabal.in
index b7b6f69d88..c9ab1c22e4 100644
--- a/compiler/ghc.cabal.in
+++ b/compiler/ghc.cabal.in
@@ -400,6 +400,7 @@ Library
OccurAnal
SAT
SetLevels
+ AnfiseCore
SimplCore
SimplEnv
SimplMonad
diff --git a/compiler/simplCore/AnfiseCore.hs b/compiler/simplCore/AnfiseCore.hs
new file mode 100644
index 0000000000..ef4cfb5404
--- /dev/null
+++ b/compiler/simplCore/AnfiseCore.hs
@@ -0,0 +1,90 @@
+-- | Convert Core into A-normal form (ANF).
+module AnfiseCore ( anfiseProgram ) where
+
+import BasicTypes
+import Type
+import Id
+import VarEnv
+import CoreUtils
+import CoreSyn
+import FastString
+import Unique
+
+import Data.Bifunctor
+import Data.Either
+import Control.Monad.Trans.State
+
+anfiseProgram :: CoreProgram -> CoreProgram
+anfiseProgram top_binds = map goTopLvl top_binds
+ where
+ goTopLvl (NonRec v e) = NonRec v (go in_scope_toplvl e)
+ goTopLvl (Rec pairs) = Rec (map (second (go in_scope_toplvl)) pairs)
+
+ in_scope_toplvl = emptyInScopeSet `extendInScopeSetList` bindersOfBinds top_binds
+
+ go :: InScopeSet -> CoreExpr -> CoreExpr
+ go _ e@(Var{}) = e
+ go _ e@(Lit {}) = e
+ go _ e@(Type {}) = e
+ go _ e@(Coercion {}) = e
+
+ go in_scope e@(App e1 e2)
+ | Var f_id <- f
+ , isJoinId f_id
+ = dont_bind
+ | otherwise
+ = let bound_args :: [Either CoreExpr (Id, CoreExpr)]
+ bound_args = evalState (mapM bind_arg args) in_scope
+ where
+ bind_arg :: CoreExpr -> State InScopeSet (Either CoreExpr (Id, CoreExpr))
+ bind_arg arg
+ | not should_bind = return $ Left arg
+ | otherwise = do
+ bndr <- mkAnfId ty
+ nowInScope bndr
+ return $ Right (bndr, arg)
+ where
+ ty = exprType arg
+ should_bind = isValArg arg && not (isUnliftedType ty) && not (exprIsTrivial arg)
+ binds = map (uncurry NonRec) (rights bound_args)
+ to_arg = either id (Var . fst)
+ in mkLets binds $ mkApps f (map to_arg bound_args)
+ where
+ (f, args) = collectArgs e
+ dont_bind = App (go in_scope e1) (go in_scope e2)
+ go in_scope (Lam v e') = Lam v (go in_scope' e')
+ where in_scope' = in_scope `extendInScopeSet` v
+ go in_scope (Case scrut bndr ty alts)
+ = Case (go in_scope scrut) bndr ty (map (goAlt in_scope') alts)
+ where in_scope' = in_scope `extendInScopeSet` bndr
+ go in_scope (Cast e' c) = Cast (go in_scope e') c
+ go in_scope (Tick t e') = Tick t (go in_scope e')
+ go in_scope (Let bind body) = goBind in_scope bind (go in_scope' body)
+ where in_scope' = in_scope `extendInScopeSetList` bindersOf bind
+
+ goAlt :: InScopeSet -> CoreAlt -> CoreAlt
+ goAlt in_scope (dc, pats, rhs) = (dc, pats, go in_scope' rhs)
+ where in_scope' = in_scope `extendInScopeSetList` pats
+
+ goBind :: InScopeSet -> CoreBind -> (CoreExpr -> CoreExpr)
+ goBind in_scope (NonRec v rhs) = Let (NonRec v (go in_scope rhs))
+ goBind in_scope (Rec pairs) = Let (Rec pairs')
+ where pairs' = map (second (go in_scope')) pairs
+ in_scope' = in_scope `extendInScopeSetList` bindersOf (Rec pairs)
+
+nowInScope :: Id -> State InScopeSet ()
+nowInScope id = modify (`extendInScopeSet` id)
+
+mkAnfId :: Type -> State InScopeSet Id
+mkAnfId ty = do
+ in_scope <- get
+ return $ uniqAway in_scope id_tmpl
+ where
+ id_tmpl = mkSysLocal (fsLit "anf") initExitJoinUnique ty
+ `setIdOccInfo` occ_info
+ occ_info =
+ OneOcc { occ_in_lam = insideLam
+ , occ_one_br = oneBranch
+ , occ_int_cxt = False
+ , occ_tail = NoTailCallInfo
+ }
diff --git a/compiler/simplCore/CoreMonad.hs b/compiler/simplCore/CoreMonad.hs
index 46d81dfb8b..d64f89d2b8 100644
--- a/compiler/simplCore/CoreMonad.hs
+++ b/compiler/simplCore/CoreMonad.hs
@@ -115,6 +115,7 @@ data CoreToDo -- These are diff core-to-core passes,
| CoreDoPrintCore
| CoreDoStaticArgs
| CoreDoCallArity
+ | CoreDoAnfise
| CoreDoExitify
| CoreDoStrictness
| CoreDoWorkerWrapper
@@ -143,6 +144,7 @@ instance Outputable CoreToDo where
ppr CoreLiberateCase = text "Liberate case"
ppr CoreDoStaticArgs = text "Static argument"
ppr CoreDoCallArity = text "Called arity analysis"
+ ppr CoreDoAnfise = text "ANFisation"
ppr CoreDoExitify = text "Exitification transformation"
ppr CoreDoStrictness = text "Demand analysis"
ppr CoreDoWorkerWrapper = text "Worker Wrapper binds"
diff --git a/compiler/simplCore/SimplCore.hs b/compiler/simplCore/SimplCore.hs
index 70d5e0f250..6ebc92e699 100644
--- a/compiler/simplCore/SimplCore.hs
+++ b/compiler/simplCore/SimplCore.hs
@@ -43,6 +43,7 @@ import Specialise ( specProgram)
import SpecConstr ( specConstrProgram)
import DmdAnal ( dmdAnalProgram )
import CallArity ( callArityAnalProgram )
+import AnfiseCore ( anfiseProgram )
import Exitify ( exitifyProgram )
import WorkWrap ( wwTopBinds )
import Vectorise ( vectorise )
@@ -186,7 +187,7 @@ getCoreToDo dflags
-- inlined. I found that spectral/hartel/genfft lost some useful
-- strictness in the function sumcode' if augment is not inlined
-- before strictness analysis runs
- simpl_phases = CoreDoPasses [ simpl_phase phase ["main"] max_iter
+ simpl_phases = CoreDoPasses [ CoreDoPasses [ anfise, simpl_phase phase ["main"] max_iter ]
| phase <- [phases, phases-1 .. 1] ]
@@ -212,6 +213,16 @@ getCoreToDo dflags
[simpl_phase 0 ["post-worker-wrapper"] max_iter]
))
+ anfise = CoreDoPasses
+ [ CoreDoAnfise
+ , CoreDoFloatOutwards FloatOutSwitches { floatOutLambdas = Just 0
+ , floatOutConstants = True
+ , floatOutOverSatApps = True
+ , floatToTopLevelOnly = False
+ }
+ , CoreCSE
+ ]
+
-- Static forms are moved to the top level with the FloatOut pass.
-- See Note [Grand plan for static forms] in StaticPtrTable.
static_ptrs_float_outwards =
@@ -482,6 +493,9 @@ doCorePass CoreDoStaticArgs = {-# SCC "StaticArgs" #-}
doCorePass CoreDoCallArity = {-# SCC "CallArity" #-}
doPassD callArityAnalProgram
+doCorePass CoreDoAnfise = {-# SCC "ANFise" #-}
+ doPass anfiseProgram
+
doCorePass CoreDoExitify = {-# SCC "Exitify" #-}
doPass exitifyProgram