futhark-0.20.7: src/Futhark/Optimise/Simplify/Rep.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Representation used by the simplification engine.
module Futhark.Optimise.Simplify.Rep
( Wise,
VarWisdom (..),
ExpWisdom,
removeStmWisdom,
removeLambdaWisdom,
removeFunDefWisdom,
removeExpWisdom,
removePatWisdom,
removeBodyWisdom,
removeScopeWisdom,
addScopeWisdom,
addWisdomToPat,
mkWiseBody,
mkWiseLetStm,
mkWiseExpDec,
CanBeWise (..),
-- * Constructing representation
Informing,
informLambda,
informFunDef,
informStms,
)
where
import Control.Category
import Control.Monad.Identity
import Control.Monad.Reader
import qualified Data.Kind
import qualified Data.Map.Strict as M
import Futhark.Analysis.Rephrase
import Futhark.Builder
import Futhark.IR
import Futhark.IR.Aliases
( AliasDec (..),
ConsumedInExp,
VarAliases,
unAliases,
)
import qualified Futhark.IR.Aliases as Aliases
import Futhark.IR.Prop.Aliases
import Futhark.Transform.Rename
import Futhark.Transform.Substitute
import Futhark.Util.Pretty
import Prelude hiding (id, (.))
data Wise rep
-- | The wisdom of the let-bound variable.
newtype VarWisdom = VarWisdom {varWisdomAliases :: VarAliases}
deriving (Eq, Ord, Show)
instance Rename VarWisdom where
rename = substituteRename
instance Substitute VarWisdom where
substituteNames substs (VarWisdom als) =
VarWisdom (substituteNames substs als)
instance FreeIn VarWisdom where
freeIn' (VarWisdom als) = freeIn' als
-- | Wisdom about an expression.
data ExpWisdom = ExpWisdom
{ _expWisdomConsumed :: ConsumedInExp,
expWisdomFree :: AliasDec
}
deriving (Eq, Ord, Show)
instance FreeIn ExpWisdom where
freeIn' = mempty
instance FreeDec ExpWisdom where
precomputed = const . fvNames . unAliases . expWisdomFree
instance Substitute ExpWisdom where
substituteNames substs (ExpWisdom cons free) =
ExpWisdom
(substituteNames substs cons)
(substituteNames substs free)
instance Rename ExpWisdom where
rename = substituteRename
-- | Wisdom about a body.
data BodyWisdom = BodyWisdom
{ bodyWisdomAliases :: [VarAliases],
bodyWisdomConsumed :: ConsumedInExp,
bodyWisdomFree :: AliasDec
}
deriving (Eq, Ord, Show)
instance Rename BodyWisdom where
rename = substituteRename
instance Substitute BodyWisdom where
substituteNames substs (BodyWisdom als cons free) =
BodyWisdom
(substituteNames substs als)
(substituteNames substs cons)
(substituteNames substs free)
instance FreeIn BodyWisdom where
freeIn' (BodyWisdom als cons free) =
freeIn' als <> freeIn' cons <> freeIn' free
instance FreeDec BodyWisdom where
precomputed = const . fvNames . unAliases . bodyWisdomFree
instance (RepTypes rep, CanBeWise (Op rep)) => RepTypes (Wise rep) where
type LetDec (Wise rep) = (VarWisdom, LetDec rep)
type ExpDec (Wise rep) = (ExpWisdom, ExpDec rep)
type BodyDec (Wise rep) = (BodyWisdom, BodyDec rep)
type FParamInfo (Wise rep) = FParamInfo rep
type LParamInfo (Wise rep) = LParamInfo rep
type RetType (Wise rep) = RetType rep
type BranchType (Wise rep) = BranchType rep
type Op (Wise rep) = OpWithWisdom (Op rep)
withoutWisdom ::
(HasScope (Wise rep) m, Monad m) =>
ReaderT (Scope rep) m a ->
m a
withoutWisdom m = do
scope <- asksScope removeScopeWisdom
runReaderT m scope
instance (ASTRep rep, CanBeWise (Op rep)) => ASTRep (Wise rep) where
expTypesFromPat =
withoutWisdom . expTypesFromPat . removePatWisdom
instance Pretty VarWisdom where
ppr _ = ppr ()
instance (PrettyRep rep, CanBeWise (Op rep)) => PrettyRep (Wise rep) where
ppExpDec (_, dec) = ppExpDec dec . removeExpWisdom
instance AliasesOf (VarWisdom, dec) where
aliasesOf = unAliases . varWisdomAliases . fst
instance (ASTRep rep, CanBeWise (Op rep)) => Aliased (Wise rep) where
bodyAliases = map unAliases . bodyWisdomAliases . fst . bodyDec
consumedInBody = unAliases . bodyWisdomConsumed . fst . bodyDec
removeWisdom :: CanBeWise (Op rep) => Rephraser Identity (Wise rep) rep
removeWisdom =
Rephraser
{ rephraseExpDec = return . snd,
rephraseLetBoundDec = return . snd,
rephraseBodyDec = return . snd,
rephraseFParamDec = return,
rephraseLParamDec = return,
rephraseRetType = return,
rephraseBranchType = return,
rephraseOp = return . removeOpWisdom
}
removeScopeWisdom :: Scope (Wise rep) -> Scope rep
removeScopeWisdom = M.map unAlias
where
unAlias (LetName (_, dec)) = LetName dec
unAlias (FParamName dec) = FParamName dec
unAlias (LParamName dec) = LParamName dec
unAlias (IndexName it) = IndexName it
addScopeWisdom :: Scope rep -> Scope (Wise rep)
addScopeWisdom = M.map alias
where
alias (LetName dec) = LetName (VarWisdom mempty, dec)
alias (FParamName dec) = FParamName dec
alias (LParamName dec) = LParamName dec
alias (IndexName it) = IndexName it
removeFunDefWisdom :: CanBeWise (Op rep) => FunDef (Wise rep) -> FunDef rep
removeFunDefWisdom = runIdentity . rephraseFunDef removeWisdom
removeStmWisdom :: CanBeWise (Op rep) => Stm (Wise rep) -> Stm rep
removeStmWisdom = runIdentity . rephraseStm removeWisdom
removeLambdaWisdom :: CanBeWise (Op rep) => Lambda (Wise rep) -> Lambda rep
removeLambdaWisdom = runIdentity . rephraseLambda removeWisdom
removeBodyWisdom :: CanBeWise (Op rep) => Body (Wise rep) -> Body rep
removeBodyWisdom = runIdentity . rephraseBody removeWisdom
removeExpWisdom :: CanBeWise (Op rep) => Exp (Wise rep) -> Exp rep
removeExpWisdom = runIdentity . rephraseExp removeWisdom
removePatWisdom :: PatT (VarWisdom, a) -> PatT a
removePatWisdom = runIdentity . rephrasePat (return . snd)
addWisdomToPat ::
(ASTRep rep, CanBeWise (Op rep)) =>
Pat rep ->
Exp (Wise rep) ->
Pat (Wise rep)
addWisdomToPat pat e =
Pat $ map f $ Aliases.mkPatAliases pat e
where
f pe =
let (als, dec) = patElemDec pe
in pe `setPatElemDec` (VarWisdom als, dec)
mkWiseBody ::
(ASTRep rep, CanBeWise (Op rep)) =>
BodyDec rep ->
Stms (Wise rep) ->
Result ->
Body (Wise rep)
mkWiseBody dec stms res =
Body
( BodyWisdom aliases consumed (AliasDec $ freeIn $ freeInStmsAndRes stms res),
dec
)
stms
res
where
(aliases, consumed) = Aliases.mkBodyAliases stms res
mkWiseLetStm ::
(ASTRep rep, CanBeWise (Op rep)) =>
Pat rep ->
StmAux (ExpDec rep) ->
Exp (Wise rep) ->
Stm (Wise rep)
mkWiseLetStm pat (StmAux cs attrs dec) e =
let pat' = addWisdomToPat pat e
in Let pat' (StmAux cs attrs $ mkWiseExpDec pat' dec e) e
mkWiseExpDec ::
(ASTRep rep, CanBeWise (Op rep)) =>
Pat (Wise rep) ->
ExpDec rep ->
Exp (Wise rep) ->
ExpDec (Wise rep)
mkWiseExpDec pat expdec e =
( ExpWisdom
(AliasDec $ consumedInExp e)
(AliasDec $ freeIn pat <> freeIn expdec <> freeIn e),
expdec
)
instance (Buildable rep, CanBeWise (Op rep)) => Buildable (Wise rep) where
mkExpPat ids e =
addWisdomToPat (mkExpPat ids $ removeExpWisdom e) e
mkExpDec pat e =
mkWiseExpDec pat (mkExpDec (removePatWisdom pat) $ removeExpWisdom e) e
mkLetNames names e = do
env <- asksScope removeScopeWisdom
flip runReaderT env $ do
Let pat dec _ <- mkLetNames names $ removeExpWisdom e
return $ mkWiseLetStm pat dec e
mkBody stms res =
let Body bodyrep _ _ = mkBody (fmap removeStmWisdom stms) res
in mkWiseBody bodyrep stms res
-- | Constraints that let us transform a representation into a 'Wise'
-- representation.
type Informing rep = (ASTRep rep, CanBeWise (Op rep))
class
( AliasedOp (OpWithWisdom op),
IsOp (OpWithWisdom op)
) =>
CanBeWise op
where
type OpWithWisdom op :: Data.Kind.Type
removeOpWisdom :: OpWithWisdom op -> op
addOpWisdom :: op -> OpWithWisdom op
instance CanBeWise () where
type OpWithWisdom () = ()
removeOpWisdom () = ()
addOpWisdom () = ()
informStm :: Informing rep => Stm rep -> Stm (Wise rep)
informStm (Let pat aux e) = mkWiseLetStm pat aux $ informExp e
informStms :: Informing rep => Stms rep -> Stms (Wise rep)
informStms = fmap informStm
informBody :: Informing rep => Body rep -> Body (Wise rep)
informBody (Body dec stms res) = mkWiseBody dec (informStms stms) res
informLambda :: Informing rep => Lambda rep -> Lambda (Wise rep)
informLambda (Lambda ps body ret) = Lambda ps (informBody body) ret
informExp :: Informing rep => Exp rep -> Exp (Wise rep)
informExp (If cond tbranch fbranch (IfDec ts ifsort)) =
If cond (informBody tbranch) (informBody fbranch) (IfDec ts ifsort)
informExp (DoLoop merge form loopbody) =
let form' = case form of
ForLoop i it bound params -> ForLoop i it bound params
WhileLoop cond -> WhileLoop cond
in DoLoop merge form' $ informBody loopbody
informExp e = runIdentity $ mapExpM mapper e
where
mapper =
Mapper
{ mapOnBody = const $ pure . informBody,
mapOnSubExp = pure,
mapOnVName = pure,
mapOnRetType = pure,
mapOnBranchType = pure,
mapOnFParam = pure,
mapOnLParam = pure,
mapOnOp = pure . addOpWisdom
}
informFunDef :: Informing rep => FunDef rep -> FunDef (Wise rep)
informFunDef (FunDef entry attrs fname rettype params body) =
FunDef entry attrs fname rettype params $ informBody body