futhark-0.16.1: src/Futhark/Analysis/PrimExp/Convert.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
-- | Converting back and forth between 'PrimExp's. Use the 'ToExp'
-- instance to convert to Futhark expressions.
module Futhark.Analysis.PrimExp.Convert
(
primExpFromExp
, primExpFromSubExp
, primExpFromSubExpM
, replaceInPrimExp
, replaceInPrimExpM
, substituteInPrimExp
, primExpSlice
, subExpSlice
-- * Module reexport
, module Futhark.Analysis.PrimExp
) where
import qualified Control.Monad.Fail as Fail
import Control.Monad.Identity
import qualified Data.Map.Strict as M
import Data.Maybe
import Futhark.Analysis.PrimExp
import Futhark.Construct
import Futhark.IR
instance ToExp v => ToExp (PrimExp v) where
toExp (BinOpExp op x y) =
BasicOp <$> (BinOp op <$> toSubExp "binop_x" x <*> toSubExp "binop_y" y)
toExp (CmpOpExp op x y) =
BasicOp <$> (CmpOp op <$> toSubExp "cmpop_x" x <*> toSubExp "cmpop_y" y)
toExp (UnOpExp op x) =
BasicOp <$> (UnOp op <$> toSubExp "unop_x" x)
toExp (ConvOpExp op x) =
BasicOp <$> (ConvOp op <$> toSubExp "convop_x" x)
toExp (ValueExp v) =
return $ BasicOp $ SubExp $ Constant v
toExp (FunExp h args t) =
Apply (nameFromString h) <$> args' <*> pure [primRetType t] <*>
pure (Safe, mempty, [])
where args' = zip <$> mapM (toSubExp "apply_arg") args <*> pure (repeat Observe)
toExp (LeafExp v _) =
toExp v
-- | Convert an expression to a 'PrimExp'. The provided function is
-- used to convert expressions that are not trivially 'PrimExp's.
-- This includes constants and variable names, which are passed as
-- t'SubExp's.
primExpFromExp :: (Fail.MonadFail m, Decorations lore) =>
(VName -> m (PrimExp v)) -> Exp lore -> m (PrimExp v)
primExpFromExp f (BasicOp (BinOp op x y)) =
BinOpExp op <$> primExpFromSubExpM f x <*> primExpFromSubExpM f y
primExpFromExp f (BasicOp (CmpOp op x y)) =
CmpOpExp op <$> primExpFromSubExpM f x <*> primExpFromSubExpM f y
primExpFromExp f (BasicOp (UnOp op x)) =
UnOpExp op <$> primExpFromSubExpM f x
primExpFromExp f (BasicOp (ConvOp op x)) =
ConvOpExp op <$> primExpFromSubExpM f x
primExpFromExp f (BasicOp (SubExp se)) =
primExpFromSubExpM f se
primExpFromExp f (Apply fname args ts _)
| isBuiltInFunction fname, [Prim t] <- map declExtTypeOf ts =
FunExp (nameToString fname) <$> mapM (primExpFromSubExpM f . fst) args <*> pure t
primExpFromExp _ _ = fail "Not a PrimExp"
-- | Like 'primExpFromExp', but for a t'SubExp'.
primExpFromSubExpM :: Applicative m => (VName -> m (PrimExp v)) -> SubExp -> m (PrimExp v)
primExpFromSubExpM f (Var v) = f v
primExpFromSubExpM _ (Constant v) = pure $ ValueExp v
-- | Convert t'SubExp's of a given type.
primExpFromSubExp :: PrimType -> SubExp -> PrimExp VName
primExpFromSubExp t (Var v) = LeafExp v t
primExpFromSubExp _ (Constant v) = ValueExp v
-- | Applying a monadic transformation to the leaves in a 'PrimExp'.
replaceInPrimExpM :: Monad m =>
(a -> PrimType -> m (PrimExp b)) ->
PrimExp a -> m (PrimExp b)
replaceInPrimExpM f (LeafExp v pt) =
f v pt
replaceInPrimExpM _ (ValueExp v) =
return $ ValueExp v
replaceInPrimExpM f (BinOpExp bop pe1 pe2) =
constFoldPrimExp <$>
(BinOpExp bop <$> replaceInPrimExpM f pe1 <*> replaceInPrimExpM f pe2)
replaceInPrimExpM f (CmpOpExp cop pe1 pe2) =
CmpOpExp cop <$> replaceInPrimExpM f pe1 <*> replaceInPrimExpM f pe2
replaceInPrimExpM f (UnOpExp uop pe) =
UnOpExp uop <$> replaceInPrimExpM f pe
replaceInPrimExpM f (ConvOpExp cop pe) =
ConvOpExp cop <$> replaceInPrimExpM f pe
replaceInPrimExpM f (FunExp h args t) =
FunExp h <$> mapM (replaceInPrimExpM f) args <*> pure t
-- | As 'replaceInPrimExpM', but in the identity monad.
replaceInPrimExp :: (a -> PrimType -> PrimExp b) ->
PrimExp a -> PrimExp b
replaceInPrimExp f e = runIdentity $ replaceInPrimExpM f' e
where f' x y = return $ f x y
-- | Substituting names in a PrimExp with other PrimExps
substituteInPrimExp :: Ord v => M.Map v (PrimExp v)
-> PrimExp v -> PrimExp v
substituteInPrimExp tab = replaceInPrimExp $ \v t ->
fromMaybe (LeafExp v t) $ M.lookup v tab
-- | Convert a 'SubExp' slice to a 'PrimExp' slice.
primExpSlice :: Slice SubExp -> Slice (PrimExp VName)
primExpSlice = map $ fmap $ primExpFromSubExp int32
-- | Convert a 'PrimExp' slice to a 'SubExp' slice.
subExpSlice :: MonadBinder m => Slice (PrimExp VName) -> m (Slice SubExp)
subExpSlice = mapM $ traverse $ toSubExp "slice"