    {-# LANGUAGE TypeFamilies #-}
    {-# LANGUAGE UndecidableInstances #-}

    -- | Definitions for multicore operations.
    --
    -- Most of the interesting stuff is in "Futhark.IR.SegOp", which is
    -- also re-exported from here.
    module Futhark.IR.MC.Op
      ( MCOp (..),
        traverseMCOpStms,
        typeCheckMCOp,
        simplifyMCOp,
        module Futhark.IR.SegOp,
      )
    where

    import Data.Bifunctor (first)
    import Futhark.Analysis.Metrics
    import Futhark.Analysis.SymbolTable qualified as ST
    import Futhark.IR
    import Futhark.IR.Aliases (Aliases, CanBeAliased (..))
    import Futhark.IR.Mem (OpReturns (..))
    import Futhark.IR.Prop.Aliases
    import Futhark.IR.SegOp
    import Futhark.IR.TypeCheck qualified as TC
    import Futhark.Optimise.Simplify qualified as Simplify
    import Futhark.Optimise.Simplify.Engine qualified as Engine
    import Futhark.Optimise.Simplify.Rep
    import Futhark.Transform.Rename
    import Futhark.Transform.Substitute
    import Futhark.Util.Pretty
      ( nestedBlock,
        pretty,
        (<+>),
        (</>),
      )
    import Prelude hiding (id, (.))

    -- | An operation for the multicore representation.  Feel free to
    -- extend this on an ad hoc basis as needed.  Parameterised with some
    -- other operation.
    data MCOp op rep
      = -- | The first 'SegOp' (if it exists) contains nested parallelism,
        -- while the second one has a fully sequential body.  They are
        -- semantically fully equivalent.
        ParOp
          (Maybe (SegOp () rep))
          (SegOp () rep)
      | -- | Something else (in practice often a SOAC).
        OtherOp (op rep)
      deriving (MCOp op rep -> MCOp op rep -> Bool
    (MCOp op rep -> MCOp op rep -> Bool)
    -> (MCOp op rep -> MCOp op rep -> Bool) -> Eq (MCOp op rep)
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    forall (op :: * -> *) rep.
    (RepTypes rep, Eq (op rep)) =>
    MCOp op rep -> MCOp op rep -> Bool
    $c== :: forall (op :: * -> *) rep.
    (RepTypes rep, Eq (op rep)) =>
    MCOp op rep -> MCOp op rep -> Bool
    == :: MCOp op rep -> MCOp op rep -> Bool
    $c/= :: forall (op :: * -> *) rep.
    (RepTypes rep, Eq (op rep)) =>
    MCOp op rep -> MCOp op rep -> Bool
    /= :: MCOp op rep -> MCOp op rep -> Bool
    Eq, Eq (MCOp op rep)
    Eq (MCOp op rep) =>
    (MCOp op rep -> MCOp op rep -> Ordering)
    -> (MCOp op rep -> MCOp op rep -> Bool)
    -> (MCOp op rep -> MCOp op rep -> Bool)
    -> (MCOp op rep -> MCOp op rep -> Bool)
    -> (MCOp op rep -> MCOp op rep -> Bool)
    -> (MCOp op rep -> MCOp op rep -> MCOp op rep)
    -> (MCOp op rep -> MCOp op rep -> MCOp op rep)
    -> Ord (MCOp op rep)
    MCOp op rep -> MCOp op rep -> Bool
    MCOp op rep -> MCOp op rep -> Ordering
    MCOp op rep -> MCOp op rep -> MCOp op rep
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    Eq (MCOp op rep)
    forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> Bool
    forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> Ordering
    forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> MCOp op rep
    $ccompare :: forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> Ordering
    compare :: MCOp op rep -> MCOp op rep -> Ordering
    $c< :: forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> Bool
    < :: MCOp op rep -> MCOp op rep -> Bool
    $c<= :: forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> Bool
    <= :: MCOp op rep -> MCOp op rep -> Bool
    $c> :: forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> Bool
    > :: MCOp op rep -> MCOp op rep -> Bool
    $c>= :: forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> Bool
    >= :: MCOp op rep -> MCOp op rep -> Bool
    $cmax :: forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> MCOp op rep
    max :: MCOp op rep -> MCOp op rep -> MCOp op rep
    $cmin :: forall (op :: * -> *) rep.
    (RepTypes rep, Ord (op rep)) =>
    MCOp op rep -> MCOp op rep -> MCOp op rep
    min :: MCOp op rep -> MCOp op rep -> MCOp op rep
    Ord, Int -> MCOp op rep -> ShowS
    [MCOp op rep] -> ShowS
    MCOp op rep -> String
    (Int -> MCOp op rep -> ShowS)
    -> (MCOp op rep -> String)
    -> ([MCOp op rep] -> ShowS)
    -> Show (MCOp op rep)
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    forall (op :: * -> *) rep.
    (RepTypes rep, Show (op rep)) =>
    Int -> MCOp op rep -> ShowS
    forall (op :: * -> *) rep.
    (RepTypes rep, Show (op rep)) =>
    [MCOp op rep] -> ShowS
    forall (op :: * -> *) rep.
    (RepTypes rep, Show (op rep)) =>
    MCOp op rep -> String
    $cshowsPrec :: forall (op :: * -> *) rep.
    (RepTypes rep, Show (op rep)) =>
    Int -> MCOp op rep -> ShowS
    showsPrec :: Int -> MCOp op rep -> ShowS
    $cshow :: forall (op :: * -> *) rep.
    (RepTypes rep, Show (op rep)) =>
    MCOp op rep -> String
    show :: MCOp op rep -> String
    $cshowList :: forall (op :: * -> *) rep.
    (RepTypes rep, Show (op rep)) =>
    [MCOp op rep] -> ShowS
    showList :: [MCOp op rep] -> ShowS
    Show)

    traverseMCOpStms ::
      (Monad m) =>
      OpStmsTraverser m (op rep) rep ->
      OpStmsTraverser m (MCOp op rep) rep
    traverseMCOpStms :: forall (m :: * -> *) (op :: * -> *) rep.
    Monad m =>
    OpStmsTraverser m (op rep) rep
    -> OpStmsTraverser m (MCOp op rep) rep
    traverseMCOpStms OpStmsTraverser m (op rep) rep
    _ Scope rep -> Stms rep -> m (Stms rep)
    f (ParOp Maybe (SegOp () rep)
    par_op SegOp () rep
    op) =
      Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    forall (op :: * -> *) rep.
    Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    ParOp (Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep)
    -> m (Maybe (SegOp () rep)) -> m (SegOp () rep -> MCOp op rep)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (SegOp () rep -> m (SegOp () rep))
    -> Maybe (SegOp () rep) -> m (Maybe (SegOp () rep))
    forall (t :: * -> *) (f :: * -> *) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> Maybe a -> f (Maybe b)
    traverse (OpStmsTraverser m (SegOp () rep) rep
    forall (m :: * -> *) lvl rep.
    Monad m =>
    OpStmsTraverser m (SegOp lvl rep) rep
    traverseSegOpStms Scope rep -> Stms rep -> m (Stms rep)
    f) Maybe (SegOp () rep)
    par_op m (SegOp () rep -> MCOp op rep)
    -> m (SegOp () rep) -> m (MCOp op rep)
    forall a b. m (a -> b) -> m a -> m b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> OpStmsTraverser m (SegOp () rep) rep
    forall (m :: * -> *) lvl rep.
    Monad m =>
    OpStmsTraverser m (SegOp lvl rep) rep
    traverseSegOpStms Scope rep -> Stms rep -> m (Stms rep)
    f SegOp () rep
    op
    traverseMCOpStms OpStmsTraverser m (op rep) rep
    onInner Scope rep -> Stms rep -> m (Stms rep)
    f (OtherOp op rep
    op) = op rep -> MCOp op rep
    forall (op :: * -> *) rep. op rep -> MCOp op rep
    OtherOp (op rep -> MCOp op rep) -> m (op rep) -> m (MCOp op rep)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> OpStmsTraverser m (op rep) rep
    onInner Scope rep -> Stms rep -> m (Stms rep)
    f op rep
    op

    instance (ASTRep rep, Substitute (op rep)) => Substitute (MCOp op rep) where
      substituteNames :: Map VName VName -> MCOp op rep -> MCOp op rep
    substituteNames Map VName VName
    substs (ParOp Maybe (SegOp () rep)
    par_op SegOp () rep
    op) =
        Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    forall (op :: * -> *) rep.
    Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    ParOp (Map VName VName -> SegOp () rep -> SegOp () rep
    forall a. Substitute a => Map VName VName -> a -> a
    substituteNames Map VName VName
    substs (SegOp () rep -> SegOp () rep)
    -> Maybe (SegOp () rep) -> Maybe (SegOp () rep)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe (SegOp () rep)
    par_op) (Map VName VName -> SegOp () rep -> SegOp () rep
    forall a. Substitute a => Map VName VName -> a -> a
    substituteNames Map VName VName
    substs SegOp () rep
    op)
      substituteNames Map VName VName
    substs (OtherOp op rep
    op) =
        op rep -> MCOp op rep
    forall (op :: * -> *) rep. op rep -> MCOp op rep
    OtherOp (op rep -> MCOp op rep) -> op rep -> MCOp op rep
    forall a b. (a -> b) -> a -> b
    $ Map VName VName -> op rep -> op rep
    forall a. Substitute a => Map VName VName -> a -> a
    substituteNames Map VName VName
    substs op rep
    op

    instance (ASTRep rep, Rename (op rep)) => Rename (MCOp op rep) where
      rename :: MCOp op rep -> RenameM (MCOp op rep)
    rename (ParOp Maybe (SegOp () rep)
    par_op SegOp () rep
    op) = Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    forall (op :: * -> *) rep.
    Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    ParOp (Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep)
    -> RenameM (Maybe (SegOp () rep))
    -> RenameM (SegOp () rep -> MCOp op rep)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe (SegOp () rep) -> RenameM (Maybe (SegOp () rep))
    forall a. Rename a => a -> RenameM a
    rename Maybe (SegOp () rep)
    par_op RenameM (SegOp () rep -> MCOp op rep)
    -> RenameM (SegOp () rep) -> RenameM (MCOp op rep)
    forall a b. RenameM (a -> b) -> RenameM a -> RenameM b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> SegOp () rep -> RenameM (SegOp () rep)
    forall a. Rename a => a -> RenameM a
    rename SegOp () rep
    op
      rename (OtherOp op rep
    op) = op rep -> MCOp op rep
    forall (op :: * -> *) rep. op rep -> MCOp op rep
    OtherOp (op rep -> MCOp op rep)
    -> RenameM (op rep) -> RenameM (MCOp op rep)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> op rep -> RenameM (op rep)
    forall a. Rename a => a -> RenameM a
    rename op rep
    op

    instance (ASTRep rep, FreeIn (op rep)) => FreeIn (MCOp op rep) where
      freeIn' :: MCOp op rep -> FV
    freeIn' (ParOp Maybe (SegOp () rep)
    par_op SegOp () rep
    op) = Maybe (SegOp () rep) -> FV
    forall a. FreeIn a => a -> FV
    freeIn' Maybe (SegOp () rep)
    par_op FV -> FV -> FV
    forall a. Semigroup a => a -> a -> a
    <> SegOp () rep -> FV
    forall a. FreeIn a => a -> FV
    freeIn' SegOp () rep
    op
      freeIn' (OtherOp op rep
    op) = op rep -> FV
    forall a. FreeIn a => a -> FV
    freeIn' op rep
    op

    instance (IsOp op) => IsOp (MCOp op) where
      safeOp :: forall rep. ASTRep rep => MCOp op rep -> Bool
    safeOp (ParOp Maybe (SegOp () rep)
    _ SegOp () rep
    op) = SegOp () rep -> Bool
    forall rep. ASTRep rep => SegOp () rep -> Bool
    forall (op :: * -> *) rep. (IsOp op, ASTRep rep) => op rep -> Bool
    safeOp SegOp () rep
    op
      safeOp (OtherOp op rep
    op) = op rep -> Bool
    forall rep. ASTRep rep => op rep -> Bool
    forall (op :: * -> *) rep. (IsOp op, ASTRep rep) => op rep -> Bool
    safeOp op rep
    op

      cheapOp :: forall rep. ASTRep rep => MCOp op rep -> Bool
    cheapOp (ParOp Maybe (SegOp () rep)
    _ SegOp () rep
    op) = SegOp () rep -> Bool
    forall rep. ASTRep rep => SegOp () rep -> Bool
    forall (op :: * -> *) rep. (IsOp op, ASTRep rep) => op rep -> Bool
    cheapOp SegOp () rep
    op
      cheapOp (OtherOp op rep
    op) = op rep -> Bool
    forall rep. ASTRep rep => op rep -> Bool
    forall (op :: * -> *) rep. (IsOp op, ASTRep rep) => op rep -> Bool
    cheapOp op rep
    op

      opDependencies :: forall rep. ASTRep rep => MCOp op rep -> [Names]
    opDependencies (ParOp Maybe (SegOp () rep)
    _ SegOp () rep
    op) = SegOp () rep -> [Names]
    forall rep. ASTRep rep => SegOp () rep -> [Names]
    forall (op :: * -> *) rep.
    (IsOp op, ASTRep rep) =>
    op rep -> [Names]
    opDependencies SegOp () rep
    op
      opDependencies (OtherOp op rep
    op) = op rep -> [Names]
    forall rep. ASTRep rep => op rep -> [Names]
    forall (op :: * -> *) rep.
    (IsOp op, ASTRep rep) =>
    op rep -> [Names]
    opDependencies op rep
    op

    instance (TypedOp op) => TypedOp (MCOp op) where
      opType :: forall rep (m :: * -> *).
    HasScope rep m =>
    MCOp op rep -> m [ExtType]
    opType (ParOp Maybe (SegOp () rep)
    _ SegOp () rep
    op) = SegOp () rep -> m [ExtType]
    forall rep (m :: * -> *).
    HasScope rep m =>
    SegOp () rep -> m [ExtType]
    forall (op :: * -> *) rep (m :: * -> *).
    (TypedOp op, HasScope rep m) =>
    op rep -> m [ExtType]
    opType SegOp () rep
    op
      opType (OtherOp op rep
    op) = op rep -> m [ExtType]
    forall rep (m :: * -> *). HasScope rep m => op rep -> m [ExtType]
    forall (op :: * -> *) rep (m :: * -> *).
    (TypedOp op, HasScope rep m) =>
    op rep -> m [ExtType]
    opType op rep
    op

    instance (AliasedOp op) => AliasedOp (MCOp op) where
      opAliases :: forall rep. Aliased rep => MCOp op rep -> [Names]
    opAliases (ParOp Maybe (SegOp () rep)
    _ SegOp () rep
    op) = SegOp () rep -> [Names]
    forall rep. Aliased rep => SegOp () rep -> [Names]
    forall (op :: * -> *) rep.
    (AliasedOp op, Aliased rep) =>
    op rep -> [Names]
    opAliases SegOp () rep
    op
      opAliases (OtherOp op rep
    op) = op rep -> [Names]
    forall rep. Aliased rep => op rep -> [Names]
    forall (op :: * -> *) rep.
    (AliasedOp op, Aliased rep) =>
    op rep -> [Names]
    opAliases op rep
    op

      consumedInOp :: forall rep. Aliased rep => MCOp op rep -> Names
    consumedInOp (ParOp Maybe (SegOp () rep)
    _ SegOp () rep
    op) = SegOp () rep -> Names
    forall rep. Aliased rep => SegOp () rep -> Names
    forall (op :: * -> *) rep.
    (AliasedOp op, Aliased rep) =>
    op rep -> Names
    consumedInOp SegOp () rep
    op
      consumedInOp (OtherOp op rep
    op) = op rep -> Names
    forall rep. Aliased rep => op rep -> Names
    forall (op :: * -> *) rep.
    (AliasedOp op, Aliased rep) =>
    op rep -> Names
    consumedInOp op rep
    op

    instance (CanBeAliased op) => CanBeAliased (MCOp op) where
      addOpAliases :: forall rep.
    AliasableRep rep =>
    AliasTable -> MCOp op rep -> MCOp op (Aliases rep)
    addOpAliases AliasTable
    aliases (ParOp Maybe (SegOp () rep)
    par_op SegOp () rep
    op) =
        Maybe (SegOp () (Aliases rep))
    -> SegOp () (Aliases rep) -> MCOp op (Aliases rep)
    forall (op :: * -> *) rep.
    Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    ParOp (AliasTable -> SegOp () rep -> SegOp () (Aliases rep)
    forall rep.
    AliasableRep rep =>
    AliasTable -> SegOp () rep -> SegOp () (Aliases rep)
    forall (op :: * -> *) rep.
    (CanBeAliased op, AliasableRep rep) =>
    AliasTable -> op rep -> op (Aliases rep)
    addOpAliases AliasTable
    aliases (SegOp () rep -> SegOp () (Aliases rep))
    -> Maybe (SegOp () rep) -> Maybe (SegOp () (Aliases rep))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe (SegOp () rep)
    par_op) (AliasTable -> SegOp () rep -> SegOp () (Aliases rep)
    forall rep.
    AliasableRep rep =>
    AliasTable -> SegOp () rep -> SegOp () (Aliases rep)
    forall (op :: * -> *) rep.
    (CanBeAliased op, AliasableRep rep) =>
    AliasTable -> op rep -> op (Aliases rep)
    addOpAliases AliasTable
    aliases SegOp () rep
    op)
      addOpAliases AliasTable
    aliases (OtherOp op rep
    op) =
        op (Aliases rep) -> MCOp op (Aliases rep)
    forall (op :: * -> *) rep. op rep -> MCOp op rep
    OtherOp (op (Aliases rep) -> MCOp op (Aliases rep))
    -> op (Aliases rep) -> MCOp op (Aliases rep)
    forall a b. (a -> b) -> a -> b
    $ AliasTable -> op rep -> op (Aliases rep)
    forall rep.
    AliasableRep rep =>
    AliasTable -> op rep -> op (Aliases rep)
    forall (op :: * -> *) rep.
    (CanBeAliased op, AliasableRep rep) =>
    AliasTable -> op rep -> op (Aliases rep)
    addOpAliases AliasTable
    aliases op rep
    op

    instance (CanBeWise op) => CanBeWise (MCOp op) where
      addOpWisdom :: forall rep. Informing rep => MCOp op rep -> MCOp op (Wise rep)
    addOpWisdom (ParOp Maybe (SegOp () rep)
    par_op SegOp () rep
    op) =
        Maybe (SegOp () (Wise rep))
    -> SegOp () (Wise rep) -> MCOp op (Wise rep)
    forall (op :: * -> *) rep.
    Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    ParOp (SegOp () rep -> SegOp () (Wise rep)
    forall rep. Informing rep => SegOp () rep -> SegOp () (Wise rep)
    forall (op :: * -> *) rep.
    (CanBeWise op, Informing rep) =>
    op rep -> op (Wise rep)
    addOpWisdom (SegOp () rep -> SegOp () (Wise rep))
    -> Maybe (SegOp () rep) -> Maybe (SegOp () (Wise rep))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe (SegOp () rep)
    par_op) (SegOp () rep -> SegOp () (Wise rep)
    forall rep. Informing rep => SegOp () rep -> SegOp () (Wise rep)
    forall (op :: * -> *) rep.
    (CanBeWise op, Informing rep) =>
    op rep -> op (Wise rep)
    addOpWisdom SegOp () rep
    op)
      addOpWisdom (OtherOp op rep
    op) =
        op (Wise rep) -> MCOp op (Wise rep)
    forall (op :: * -> *) rep. op rep -> MCOp op rep
    OtherOp (op (Wise rep) -> MCOp op (Wise rep))
    -> op (Wise rep) -> MCOp op (Wise rep)
    forall a b. (a -> b) -> a -> b
    $ op rep -> op (Wise rep)
    forall rep. Informing rep => op rep -> op (Wise rep)
    forall (op :: * -> *) rep.
    (CanBeWise op, Informing rep) =>
    op rep -> op (Wise rep)
    addOpWisdom op rep
    op

    instance (ASTRep rep, ST.IndexOp (op rep)) => ST.IndexOp (MCOp op rep) where
      indexOp :: forall rep.
    (ASTRep rep, IndexOp (Op rep)) =>
    SymbolTable rep
    -> Int -> MCOp op rep -> [TPrimExp Int64 VName] -> Maybe Indexed
    indexOp SymbolTable rep
    vtable Int
    k (ParOp Maybe (SegOp () rep)
    _ SegOp () rep
    op) [TPrimExp Int64 VName]
    is = SymbolTable rep
    -> Int -> SegOp () rep -> [TPrimExp Int64 VName] -> Maybe Indexed
    forall rep.
    (ASTRep rep, IndexOp (Op rep)) =>
    SymbolTable rep
    -> Int -> SegOp () rep -> [TPrimExp Int64 VName] -> Maybe Indexed
    forall op rep.
    (IndexOp op, ASTRep rep, IndexOp (Op rep)) =>
    SymbolTable rep
    -> Int -> op -> [TPrimExp Int64 VName] -> Maybe Indexed
    ST.indexOp SymbolTable rep
    vtable Int
    k SegOp () rep
    op [TPrimExp Int64 VName]
    is
      indexOp SymbolTable rep
    vtable Int
    k (OtherOp op rep
    op) [TPrimExp Int64 VName]
    is = SymbolTable rep
    -> Int -> op rep -> [TPrimExp Int64 VName] -> Maybe Indexed
    forall rep.
    (ASTRep rep, IndexOp (Op rep)) =>
    SymbolTable rep
    -> Int -> op rep -> [TPrimExp Int64 VName] -> Maybe Indexed
    forall op rep.
    (IndexOp op, ASTRep rep, IndexOp (Op rep)) =>
    SymbolTable rep
    -> Int -> op -> [TPrimExp Int64 VName] -> Maybe Indexed
    ST.indexOp SymbolTable rep
    vtable Int
    k op rep
    op [TPrimExp Int64 VName]
    is

    instance OpReturns (MCOp NoOp) where
      opReturns :: forall rep (inner :: * -> *) (m :: * -> *).
    (Mem rep inner, Monad m, HasScope rep m) =>
    MCOp NoOp rep -> m [ExpReturns]
    opReturns (ParOp Maybe (SegOp () rep)
    _ SegOp () rep
    op) = SegOp () rep -> m [ExpReturns]
    forall rep (inner :: * -> *) (m :: * -> *) lvl.
    (Mem rep inner, Monad m, HasScope rep m) =>
    SegOp lvl rep -> m [ExpReturns]
    segOpReturns SegOp () rep
    op
      opReturns (OtherOp NoOp rep
    NoOp) = [ExpReturns] -> m [ExpReturns]
    forall a. a -> m a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure []

    instance (PrettyRep rep, Pretty (op rep)) => Pretty (MCOp op rep) where
      pretty :: forall ann. MCOp op rep -> Doc ann
    pretty (ParOp Maybe (SegOp () rep)
    Nothing SegOp () rep
    op) = SegOp () rep -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    forall ann. SegOp () rep -> Doc ann
    pretty SegOp () rep
    op
      pretty (ParOp (Just SegOp () rep
    par_op) SegOp () rep
    op) =
        Doc ann
    "par"
          Doc ann -> Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann -> Doc ann
    <+> Doc ann -> Doc ann -> Doc ann -> Doc ann
    forall a. Doc a -> Doc a -> Doc a -> Doc a
    nestedBlock Doc ann
    "{" Doc ann
    "}" (SegOp () rep -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    forall ann. SegOp () rep -> Doc ann
    pretty SegOp () rep
    par_op)
          Doc ann -> Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann -> Doc ann
    </> Doc ann
    "seq"
          Doc ann -> Doc ann -> Doc ann
    forall ann. Doc ann -> Doc ann -> Doc ann
    <+> Doc ann -> Doc ann -> Doc ann -> Doc ann
    forall a. Doc a -> Doc a -> Doc a -> Doc a
    nestedBlock Doc ann
    "{" Doc ann
    "}" (SegOp () rep -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    forall ann. SegOp () rep -> Doc ann
    pretty SegOp () rep
    op)
      pretty (OtherOp op rep
    op) = op rep -> Doc ann
    forall ann. op rep -> Doc ann
    forall a ann. Pretty a => a -> Doc ann
    pretty op rep
    op

    instance (OpMetrics (Op rep), OpMetrics (op rep)) => OpMetrics (MCOp op rep) where
      opMetrics :: MCOp op rep -> MetricsM ()
    opMetrics (ParOp Maybe (SegOp () rep)
    par_op SegOp () rep
    op) = Maybe (SegOp () rep) -> MetricsM ()
    forall op. OpMetrics op => op -> MetricsM ()
    opMetrics Maybe (SegOp () rep)
    par_op MetricsM () -> MetricsM () -> MetricsM ()
    forall a b. MetricsM a -> MetricsM b -> MetricsM b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> SegOp () rep -> MetricsM ()
    forall op. OpMetrics op => op -> MetricsM ()
    opMetrics SegOp () rep
    op
      opMetrics (OtherOp op rep
    op) = op rep -> MetricsM ()
    forall op. OpMetrics op => op -> MetricsM ()
    opMetrics op rep
    op

    instance (RephraseOp op) => RephraseOp (MCOp op) where
      rephraseInOp :: forall (m :: * -> *) from to.
    Monad m =>
    Rephraser m from to -> MCOp op from -> m (MCOp op to)
    rephraseInOp Rephraser m from to
    r (ParOp Maybe (SegOp () from)
    par_op SegOp () from
    op) =
        Maybe (SegOp () to) -> SegOp () to -> MCOp op to
    forall (op :: * -> *) rep.
    Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    ParOp (Maybe (SegOp () to) -> SegOp () to -> MCOp op to)
    -> m (Maybe (SegOp () to)) -> m (SegOp () to -> MCOp op to)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (SegOp () from -> m (SegOp () to))
    -> Maybe (SegOp () from) -> m (Maybe (SegOp () to))
    forall (t :: * -> *) (f :: * -> *) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> Maybe a -> f (Maybe b)
    traverse (Rephraser m from to -> SegOp () from -> m (SegOp () to)
    forall (op :: * -> *) (m :: * -> *) from to.
    (RephraseOp op, Monad m) =>
    Rephraser m from to -> op from -> m (op to)
    forall (m :: * -> *) from to.
    Monad m =>
    Rephraser m from to -> SegOp () from -> m (SegOp () to)
    rephraseInOp Rephraser m from to
    r) Maybe (SegOp () from)
    par_op m (SegOp () to -> MCOp op to) -> m (SegOp () to) -> m (MCOp op to)
    forall a b. m (a -> b) -> m a -> m b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Rephraser m from to -> SegOp () from -> m (SegOp () to)
    forall (op :: * -> *) (m :: * -> *) from to.
    (RephraseOp op, Monad m) =>
    Rephraser m from to -> op from -> m (op to)
    forall (m :: * -> *) from to.
    Monad m =>
    Rephraser m from to -> SegOp () from -> m (SegOp () to)
    rephraseInOp Rephraser m from to
    r SegOp () from
    op
      rephraseInOp Rephraser m from to
    r (OtherOp op from
    op) = op to -> MCOp op to
    forall (op :: * -> *) rep. op rep -> MCOp op rep
    OtherOp (op to -> MCOp op to) -> m (op to) -> m (MCOp op to)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Rephraser m from to -> op from -> m (op to)
    forall (op :: * -> *) (m :: * -> *) from to.
    (RephraseOp op, Monad m) =>
    Rephraser m from to -> op from -> m (op to)
    forall (m :: * -> *) from to.
    Monad m =>
    Rephraser m from to -> op from -> m (op to)
    rephraseInOp Rephraser m from to
    r op from
    op

    typeCheckMCOp ::
      (TC.Checkable rep) =>
      (op (Aliases rep) -> TC.TypeM rep ()) ->
      MCOp op (Aliases rep) ->
      TC.TypeM rep ()
    typeCheckMCOp :: forall rep (op :: * -> *).
    Checkable rep =>
    (op (Aliases rep) -> TypeM rep ())
    -> MCOp op (Aliases rep) -> TypeM rep ()
    typeCheckMCOp op (Aliases rep) -> TypeM rep ()
    _ (ParOp (Just SegOp () (Aliases rep)
    par_op) SegOp () (Aliases rep)
    op) = do
      -- It is valid for the same array to be consumed in both par_op and op.
      ((), ())
    _ <- (() -> TypeM rep ()) -> SegOp () (Aliases rep) -> TypeM rep ()
    forall rep lvl.
    Checkable rep =>
    (lvl -> TypeM rep ()) -> SegOp lvl (Aliases rep) -> TypeM rep ()
    typeCheckSegOp () -> TypeM rep ()
    forall a. a -> TypeM rep a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure SegOp () (Aliases rep)
    par_op TypeM rep () -> TypeM rep () -> TypeM rep ((), ())
    forall rep a b. TypeM rep a -> TypeM rep b -> TypeM rep (a, b)
    `TC.alternative` (() -> TypeM rep ()) -> SegOp () (Aliases rep) -> TypeM rep ()
    forall rep lvl.
    Checkable rep =>
    (lvl -> TypeM rep ()) -> SegOp lvl (Aliases rep) -> TypeM rep ()
    typeCheckSegOp () -> TypeM rep ()
    forall a. a -> TypeM rep a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure SegOp () (Aliases rep)
    op
      () -> TypeM rep ()
    forall a. a -> TypeM rep a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure ()
    typeCheckMCOp op (Aliases rep) -> TypeM rep ()
    _ (ParOp Maybe (SegOp () (Aliases rep))
    Nothing SegOp () (Aliases rep)
    op) =
      (() -> TypeM rep ()) -> SegOp () (Aliases rep) -> TypeM rep ()
    forall rep lvl.
    Checkable rep =>
    (lvl -> TypeM rep ()) -> SegOp lvl (Aliases rep) -> TypeM rep ()
    typeCheckSegOp () -> TypeM rep ()
    forall a. a -> TypeM rep a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure SegOp () (Aliases rep)
    op
    typeCheckMCOp op (Aliases rep) -> TypeM rep ()
    f (OtherOp op (Aliases rep)
    op) = op (Aliases rep) -> TypeM rep ()
    f op (Aliases rep)
    op

    simplifyMCOp ::
      ( Engine.SimplifiableRep rep,
        BodyDec rep ~ ()
      ) =>
      Simplify.SimplifyOp rep (op (Wise rep)) ->
      MCOp op (Wise rep) ->
      Engine.SimpleM rep (MCOp op (Wise rep), Stms (Wise rep))
    simplifyMCOp :: forall rep (op :: * -> *).
    (SimplifiableRep rep, BodyDec rep ~ ()) =>
    SimplifyOp rep (op (Wise rep))
    -> MCOp op (Wise rep)
    -> SimpleM rep (MCOp op (Wise rep), Stms (Wise rep))
    simplifyMCOp SimplifyOp rep (op (Wise rep))
    f (OtherOp op (Wise rep)
    op) = do
      (op (Wise rep)
    op', Stms (Wise rep)
    stms) <- SimplifyOp rep (op (Wise rep))
    f op (Wise rep)
    op
      (MCOp op (Wise rep), Stms (Wise rep))
    -> SimpleM rep (MCOp op (Wise rep), Stms (Wise rep))
    forall a. a -> SimpleM rep a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (op (Wise rep) -> MCOp op (Wise rep)
    forall (op :: * -> *) rep. op rep -> MCOp op rep
    OtherOp op (Wise rep)
    op', Stms (Wise rep)
    stms)
    simplifyMCOp SimplifyOp rep (op (Wise rep))
    _ (ParOp Maybe (SegOp () (Wise rep))
    par_op SegOp () (Wise rep)
    op) = do
      (Maybe (SegOp () (Wise rep))
    par_op', Stms (Wise rep)
    par_op_hoisted) <-
        case Maybe (SegOp () (Wise rep))
    par_op of
          Maybe (SegOp () (Wise rep))
    Nothing -> (Maybe (SegOp () (Wise rep)), Stms (Wise rep))
    -> SimpleM rep (Maybe (SegOp () (Wise rep)), Stms (Wise rep))
    forall a. a -> SimpleM rep a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (Maybe (SegOp () (Wise rep))
    forall a. Maybe a
    Nothing, Stms (Wise rep)
    forall a. Monoid a => a
    mempty)
          Just SegOp () (Wise rep)
    x -> (SegOp () (Wise rep) -> Maybe (SegOp () (Wise rep)))
    -> (SegOp () (Wise rep), Stms (Wise rep))
    -> (Maybe (SegOp () (Wise rep)), Stms (Wise rep))
    forall a b c. (a -> b) -> (a, c) -> (b, c)
    forall (p :: * -> * -> *) a b c.
    Bifunctor p =>
    (a -> b) -> p a c -> p b c
    first SegOp () (Wise rep) -> Maybe (SegOp () (Wise rep))
    forall a. a -> Maybe a
    Just ((SegOp () (Wise rep), Stms (Wise rep))
     -> (Maybe (SegOp () (Wise rep)), Stms (Wise rep)))
    -> SimpleM rep (SegOp () (Wise rep), Stms (Wise rep))
    -> SimpleM rep (Maybe (SegOp () (Wise rep)), Stms (Wise rep))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> SegOp () (Wise rep)
    -> SimpleM rep (SegOp () (Wise rep), Stms (Wise rep))
    forall rep lvl.
    (SimplifiableRep rep, BodyDec rep ~ (), Simplifiable lvl) =>
    SegOp lvl (Wise rep)
    -> SimpleM rep (SegOp lvl (Wise rep), Stms (Wise rep))
    simplifySegOp SegOp () (Wise rep)
    x

      (SegOp () (Wise rep)
    op', Stms (Wise rep)
    op_hoisted) <- SegOp () (Wise rep)
    -> SimpleM rep (SegOp () (Wise rep), Stms (Wise rep))
    forall rep lvl.
    (SimplifiableRep rep, BodyDec rep ~ (), Simplifiable lvl) =>
    SegOp lvl (Wise rep)
    -> SimpleM rep (SegOp lvl (Wise rep), Stms (Wise rep))
    simplifySegOp SegOp () (Wise rep)
    op

      (MCOp op (Wise rep), Stms (Wise rep))
    -> SimpleM rep (MCOp op (Wise rep), Stms (Wise rep))
    forall a. a -> SimpleM rep a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (Maybe (SegOp () (Wise rep))
    -> SegOp () (Wise rep) -> MCOp op (Wise rep)
    forall (op :: * -> *) rep.
    Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
    ParOp Maybe (SegOp () (Wise rep))
    par_op' SegOp () (Wise rep)
    op', Stms (Wise rep)
    par_op_hoisted Stms (Wise rep) -> Stms (Wise rep) -> Stms (Wise rep)
    forall a. Semigroup a => a -> a -> a
    <> Stms (Wise rep)
    op_hoisted)