packages feed

accelerate-0.9.0.0: Data/Array/Accelerate/CUDA/CodeGen/Stencil.hs

-- |
-- Module      : Data.Array.Accelerate.CUDA.CodeGen.Tuple
-- Copyright   : [2010..2011] Ben Lever
-- License     : BSD3
--
-- Maintainer  : Manuel M T Chakravarty <chak@cse.unsw.edu.au>
-- Stability   : experimental
-- Portability : non-partable (GHC extensions)
--

module Data.Array.Accelerate.CUDA.CodeGen.Stencil (
  mkStencilType, mkStencilGet, mkStencilGather, mkStencilApply
)
where

import Language.C
import Data.Array.Accelerate.CUDA.CodeGen.Data
import Data.Array.Accelerate.CUDA.CodeGen.Util

import Data.Array.Accelerate.Type


-- Getter function for a single element of a stencil array. These arrays are
-- read via texture memory, and additionally we need to specify the boundary
-- condition handler.
--
mkStencilGet :: Int -> Boundary [CExpr] -> [CType] -> [CExtDecl]
mkStencilGet base bndy ty =
  case bndy of
    Constant e -> [mkConstant e, mkFun [constant]]
    Clamp      -> [mkFun (boundary "clamp")]
    Mirror     -> [mkFun (boundary "mirror")]
    Wrap       -> [mkFun (boundary "wrap")]
  where
    dim   = typename (subscript "DimIn")
    mkFun = mkDeviceFun' (subscript "get") (typename (subscript "TyIn")) [(dim, "sh"), (dim, "ix")]

    mkConstant = mkDeviceFun (subscript "constant") (typename (subscript "TyIn")) []

    constant   = CBlockStmt $
      CIf (ccall "inRange" [cvar "sh", cvar "ix"])
      (CCompound [] [ CBlockDecl (CDecl [CTypeQual (CConstQual internalNode), CTypeSpec (CTypeDef (internalIdent "Ix") internalNode)] [(Just (CDeclr (Just (internalIdent "i")) [] Nothing [] internalNode),Just (CInitExpr (ccall "toIndex" [cvar "sh", cvar "ix"]) internalNode),Nothing)] internalNode)
                    , initA
                    , CBlockStmt (CReturn (Just (cvar "r")) internalNode) ]
                    internalNode)
      (Just (CCompound [] [CBlockStmt (CReturn (Just (ccall (subscript "constant") [])) internalNode)] internalNode))
      internalNode

    boundary f =
      [ CBlockDecl (CDecl [CTypeQual (CConstQual internalNode), CTypeSpec (CTypeDef (internalIdent "Ix") internalNode)] [(Just (CDeclr (Just (internalIdent "i")) [] Nothing [] internalNode),Just (CInitExpr (ccall "toIndex" [cvar "sh", ccall f [cvar "sh", cvar "ix"]]) internalNode),Nothing)] internalNode)
      , initA
      , CBlockStmt (CReturn (Just (CVar (internalIdent "r") internalNode)) internalNode)
      ]

    subscript = (++ show base)
    ix        = cvar "i"
    arr c     = cvar (subscript "stencil" ++ "_a" ++ show c)

    initA = CBlockDecl
      (CDecl [CTypeSpec (CTypeDef (internalIdent (subscript "TyIn")) internalNode)]
             [( Just (CDeclr (Just (internalIdent "r")) [] Nothing [] internalNode)
              , Just . mkInitList . reverse $ zipWith indexA (reverse ty) (enumFrom 0 :: [Int])
              , Nothing)]
             internalNode)

    indexA [CDoubleType _] c = ccall "indexDArray" [arr c, ix]
    indexA _               c = ccall "indexArray"  [arr c, ix]


-- A structure to hold all components of a stencil, mimicking our nested-tuple
-- representation for neighbouring elements.
--
mkStencilType :: Int -> Int -> [CType] -> CExtDecl
mkStencilType subscript size
  = mkStruct ("Stencil" ++ show subscript) False False
  . concat . replicate size


-- Gather all neighbouring array elements for our stencil
--
mkStencilGather :: Int -> Int -> [CType] -> [[Int]] -> CExtDecl
mkStencilGather base dim ty ixs =
  mkDeviceFun' (subscript "gather") (typename (subscript "Stencil")) [(dimIn, "sh"), (dimIn, "ix")] body
  where
    dimIn     = typename (subscript "DimIn")
    subscript = (++ show base)

    plus a b  = CBinary CAddOp a b internalNode
    cint c    = CConst $ CIntConst (cInteger (toInteger c)) internalNode
    offset is
      | dim == 1  = [cvar "ix" `plus` cint (head is)]
      | otherwise = zipWith (\c i -> CMember (cvar "ix") (internalIdent ('a':show c)) False internalNode `plus` cint i) [dim-1, dim-2 ..] is

    initX x is = CBlockDecl
      (CDecl [CTypeQual (CConstQual internalNode), CTypeSpec (CTypeDef (internalIdent (subscript "TyIn")) internalNode)]
             [( Just (CDeclr (Just (internalIdent ('x':show x))) [] Nothing [] internalNode)
              , Just (CInitExpr (ccall (subscript "get") [cvar "sh", ccall "shape" (offset is)]) internalNode)
              , Nothing)]
             internalNode)

    initS =
      let xs    = let l = length ixs in [l-1, l-2 .. 0]
          names = case length ty of
            1 -> [ cvar ('x':show x) | x <- xs]
            n -> [ CMember (cvar ('x':show x)) (internalIdent ('a':show c)) False internalNode | x <- xs , c <- [n-1,n-2..0]]
      in
      CBlockDecl
      (CDecl [CTypeSpec (CTypeDef (internalIdent (subscript "Stencil")) internalNode)]
             [( Just (CDeclr (Just (internalIdent "r")) [] Nothing [] internalNode)
              , Just (mkInitList names)
              , Nothing)]
             internalNode)

    body =
      zipWith initX [0::Int ..] (reverse ixs) ++
      [ initS
      , CBlockStmt (CReturn (Just (CVar (internalIdent "r") internalNode)) internalNode) ]


mkStencilApply :: Int -> [CExpr] -> CExtDecl
mkStencilApply argc
  = mkDeviceFun "apply" (typename "TyOut")
  $ map (\n -> (typename ("Stencil" ++ show n), 'x':show n)) [argc-1, argc-2 .. 0]