futhark-0.17.1: src/Futhark/Optimise/Simplify.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Strict #-}
{-# LANGUAGE TupleSections #-}
module Futhark.Optimise.Simplify
( simplifyProg,
simplifySomething,
simplifyFun,
simplifyLambda,
simplifyStms,
Engine.SimpleOps (..),
Engine.SimpleM,
Engine.SimplifyOp,
Engine.bindableSimpleOps,
Engine.noExtraHoistBlockers,
Engine.neverHoist,
Engine.SimplifiableLore,
Engine.HoistBlockers,
RuleBook,
)
where
import Data.Bifunctor (second)
import qualified Futhark.Analysis.SymbolTable as ST
import qualified Futhark.Analysis.UsageTable as UT
import Futhark.IR
import Futhark.MonadFreshNames
import qualified Futhark.Optimise.Simplify.Engine as Engine
import Futhark.Optimise.Simplify.Lore
import Futhark.Optimise.Simplify.Rule
import Futhark.Pass
-- | Simplify the given program. Even if the output differs from the
-- output, meaningful simplification may not have taken place - the
-- order of bindings may simply have been rearranged.
simplifyProg ::
Engine.SimplifiableLore lore =>
Engine.SimpleOps lore ->
RuleBook (Engine.Wise lore) ->
Engine.HoistBlockers lore ->
Prog lore ->
PassM (Prog lore)
simplifyProg simpl rules blockers (Prog consts funs) = do
(consts_vtable, consts') <-
simplifyConsts
(UT.usages $ foldMap (freeIn . funDefBody) funs)
(mempty, consts)
funs' <- parPass (simplifyFun' consts_vtable) funs
let funs_uses = UT.usages $ foldMap (freeIn . funDefBody) funs'
(_, consts'') <- simplifyConsts funs_uses (mempty, consts')
return $ Prog consts'' funs'
where
simplifyFun' consts_vtable =
simplifySomething
(Engine.localVtable (consts_vtable <>) . Engine.simplifyFun)
removeFunDefWisdom
simpl
rules
blockers
mempty
simplifyConsts uses =
simplifySomething
(onConsts uses . snd)
(second (removeStmWisdom <$>))
simpl
rules
blockers
mempty
onConsts uses consts' = do
(_, consts'') <-
Engine.simplifyStms consts' (pure ((), mempty))
(consts''', _) <-
Engine.hoistStms rules (Engine.isFalse False) mempty uses consts''
return (ST.insertStms consts''' mempty, consts''')
-- | Run a simplification operation to convergence.
simplifySomething ::
(MonadFreshNames m, Engine.SimplifiableLore lore) =>
(a -> Engine.SimpleM lore b) ->
(b -> a) ->
Engine.SimpleOps lore ->
RuleBook (Wise lore) ->
Engine.HoistBlockers lore ->
ST.SymbolTable (Wise lore) ->
a ->
m a
simplifySomething f g simpl rules blockers vtable x = do
let f' x' = Engine.localVtable (vtable <>) $ f x'
loopUntilConvergence env simpl f' g x
where
env = Engine.emptyEnv rules blockers
-- | Simplify the given function. Even if the output differs from the
-- output, meaningful simplification may not have taken place - the
-- order of bindings may simply have been rearranged. Runs in a loop
-- until convergence.
simplifyFun ::
(MonadFreshNames m, Engine.SimplifiableLore lore) =>
Engine.SimpleOps lore ->
RuleBook (Engine.Wise lore) ->
Engine.HoistBlockers lore ->
ST.SymbolTable (Wise lore) ->
FunDef lore ->
m (FunDef lore)
simplifyFun = simplifySomething Engine.simplifyFun removeFunDefWisdom
-- | Simplify just a single t'Lambda'.
simplifyLambda ::
( MonadFreshNames m,
HasScope lore m,
Engine.SimplifiableLore lore
) =>
Engine.SimpleOps lore ->
RuleBook (Engine.Wise lore) ->
Engine.HoistBlockers lore ->
Lambda lore ->
m (Lambda lore)
simplifyLambda simpl rules blockers orig_lam = do
vtable <- ST.fromScope . addScopeWisdom <$> askScope
simplifySomething
Engine.simplifyLambdaNoHoisting
removeLambdaWisdom
simpl
rules
blockers
vtable
orig_lam
-- | Simplify a sequence of 'Stm's.
simplifyStms ::
(MonadFreshNames m, Engine.SimplifiableLore lore) =>
Engine.SimpleOps lore ->
RuleBook (Engine.Wise lore) ->
Engine.HoistBlockers lore ->
Scope lore ->
Stms lore ->
m (ST.SymbolTable (Wise lore), Stms lore)
simplifyStms simpl rules blockers scope =
simplifySomething f g simpl rules blockers vtable . (mempty,)
where
vtable = ST.fromScope $ addScopeWisdom scope
f (_, stms) =
Engine.simplifyStms stms ((,mempty) <$> Engine.askVtable)
g = second $ fmap removeStmWisdom
loopUntilConvergence ::
(MonadFreshNames m, Engine.SimplifiableLore lore) =>
Engine.Env lore ->
Engine.SimpleOps lore ->
(a -> Engine.SimpleM lore b) ->
(b -> a) ->
a ->
m a
loopUntilConvergence env simpl f g x = do
(x', changed) <- modifyNameSource $ Engine.runSimpleM (f x) simpl env
if changed then loopUntilConvergence env simpl f g (g x') else return $ g x'