packages feed

accelerate-llvm-1.4.0.0: src/Data/Array/Accelerate/LLVM/Execute/Marshal.hs

{-# LANGUAGE AllowAmbiguousTypes   #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE LambdaCase            #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeApplications      #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE TypeOperators         #-}
{-# LANGUAGE UndecidableInstances  #-}
{-# OPTIONS_HADDOCK hide #-}
-- |
-- Module      : Data.Array.Accelerate.LLVM.Execute.Marshal
-- Copyright   : [2014..2020] The Accelerate Team
-- License     : BSD3
--
-- Maintainer  : Trevor L. McDonell <trevor.mcdonell@gmail.com>
-- Stability   : experimental
-- Portability : non-portable (GHC extensions)
--

module Data.Array.Accelerate.LLVM.Execute.Marshal
  where

import Data.Array.Accelerate.Array.Data
import Data.Array.Accelerate.Representation.Array
import Data.Array.Accelerate.Representation.Shape
import Data.Array.Accelerate.Representation.Type
import Data.Array.Accelerate.Type

import Data.Array.Accelerate.LLVM.CodeGen.Environment           ( Gamma, Idx'(..) )
import Data.Array.Accelerate.LLVM.Execute.Environment
import Data.Array.Accelerate.LLVM.Execute.Async

import Data.Bifunctor                                           ( first )
import Data.DList                                               ( DList )
import qualified Data.DList                                     as DL
import qualified Data.IntMap                                    as IM


-- Marshalling arguments
-- ---------------------
class (Async arch, Monoid (MarshalCleanup arch)) => Marshal arch where
  -- | A type family that is used to specify a concrete kernel argument and
  -- stream/context type for a given backend target.
  --
  type ArgR arch

  -- | A cleanup action for a marshalled argument. On PTX this is an IO action;
  -- on Native, no cleanup is necessary.
  type MarshalCleanup arch

  -- | Used to pass shapes as arguments to kernels.
  marshalInt :: Int -> ArgR arch

  -- | Pass arrays to kernels
  marshalScalarData' :: SingleType e -> ScalarArrayData e -> Par arch (DList (ArgR arch), MarshalCleanup arch)

-- | Convert function arguments into stream a form suitable for function calls
-- The functions ending in a prime return a DList, other functions return lists.
--
marshalArrays :: forall arch arrs. Marshal arch => ArraysR arrs -> arrs -> Par arch ([ArgR arch], MarshalCleanup arch)
marshalArrays repr arrs = first DL.toList <$> marshalArrays' @arch repr arrs

marshalArrays' :: forall arch arrs. Marshal arch => ArraysR arrs -> arrs -> Par arch (DList (ArgR arch), MarshalCleanup arch)
marshalArrays' = marshalTupR' @arch (marshalArray' @arch)

marshalArray' :: forall arch a. Marshal arch => ArrayR a -> a -> Par arch (DList (ArgR arch), MarshalCleanup arch)
marshalArray' (ArrayR shr tp) (Array sh a) = do
  (arg1, c1) <- marshalArrayData' @arch tp a
  let arg2 = marshalShape' @arch shr sh
  return (arg1 `DL.append` arg2, c1)

marshalArrayData' :: forall arch t. Marshal arch => TypeR t -> ArrayData t -> Par arch (DList (ArgR arch), MarshalCleanup arch)
marshalArrayData' TupRunit ()               = return (DL.empty, mempty)
marshalArrayData' (TupRpair t1 t2) (a1, a2) = do
  (l1, c1) <- marshalArrayData' t1 a1
  (l2, c2) <- marshalArrayData' t2 a2
  return (l1 `DL.append` l2, c1 <> c2)
marshalArrayData' (TupRsingle t) ad
  | ScalarArrayDict _ s <- scalarArrayDict t
  = marshalScalarData' @arch s ad

marshalEnv :: forall arch aenv. Marshal arch => Gamma aenv -> ValR arch aenv -> Par arch ([ArgR arch], MarshalCleanup arch)
marshalEnv g a = first DL.toList <$> marshalEnv' g a

marshalEnv' :: forall arch aenv. Marshal arch => Gamma aenv -> ValR arch aenv -> Par arch (DList (ArgR arch), MarshalCleanup arch)
marshalEnv' gamma aenv
    = fmap mconcat
    $ mapM (\(_, Idx' repr idx) -> marshalArray' @arch repr =<< get (prj idx aenv)) (IM.elems gamma)

marshalShape :: forall arch sh. Marshal arch => ShapeR sh -> sh -> [ArgR arch]
marshalShape shr sh = DL.toList $ marshalShape' @arch shr sh

marshalShape' :: forall arch sh. Marshal arch => ShapeR sh -> sh -> DList (ArgR arch)
marshalShape' ShapeRz () = DL.empty
marshalShape' (ShapeRsnoc shr) (sh, n) = marshalShape' @arch shr sh `DL.snoc` marshalInt @arch n

type ParamsR arch = TupR (ParamR arch)

data ParamR arch a where
  ParamRarray  :: ArrayR (Array sh e) -> ParamR arch (Array sh e)
  ParamRmaybe  :: ParamR arch a       -> ParamR arch (Maybe a)
  ParamRfuture :: ParamR arch a       -> ParamR arch (FutureR arch a)
  ParamRenv    :: Gamma aenv          -> ParamR arch (ValR arch aenv)
  ParamRint    ::                        ParamR arch Int
  ParamRshape  :: ShapeR sh           -> ParamR arch sh
  ParamRargs   ::                        ParamR arch (DList (ArgR arch))

marshalParam' :: forall arch a. Marshal arch => ParamR arch a -> a -> Par arch (DList (ArgR arch), MarshalCleanup arch)
marshalParam' (ParamRarray repr)  a        = marshalArray' repr a
marshalParam' (ParamRmaybe _   )  Nothing  = return (DL.empty, mempty)
marshalParam' (ParamRmaybe repr)  (Just a) = marshalParam' repr a
marshalParam' (ParamRfuture repr) future   = marshalParam' repr =<< get future
marshalParam' (ParamRenv gamma)   aenv     = marshalEnv'   gamma aenv
marshalParam'  ParamRint          x        = return (DL.singleton (marshalInt @arch x), mempty)
marshalParam' (ParamRshape shr)   sh       = return (marshalShape' @arch shr sh, mempty)
marshalParam'  ParamRargs         args     = return (args, mempty)

marshalParams' :: forall arch a. Marshal arch => ParamsR arch a -> a -> Par arch (DList (ArgR arch), MarshalCleanup arch)
marshalParams' = marshalTupR' @arch (marshalParam' @arch)

{-# INLINE marshalTupR' #-}
marshalTupR' :: forall arch s a. Marshal arch => (forall b. s b -> b -> Par arch (DList (ArgR arch), MarshalCleanup arch)) -> TupR s a -> a -> Par arch (DList (ArgR arch), MarshalCleanup arch)
marshalTupR' _ TupRunit         ()       = return (DL.empty, mempty)
marshalTupR' f (TupRsingle t)   x        = f t x
marshalTupR' f (TupRpair t1 t2) (x1, x2) = (<>) <$> marshalTupR' @arch f t1 x1 <*> marshalTupR' @arch f t2 x2