{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

-- | Compile a 'GPUMem' program to imperative code with kernels.
-- This is mostly (but not entirely) the same process no matter if we
-- are targeting OpenCL or CUDA.  The important distinctions (the host
-- level code) are introduced later.
module Futhark.CodeGen.ImpGen.GPU
  ( compileProgOpenCL,
    compileProgCUDA,
    Warnings,
  )
where

import Control.Monad.Except
import Data.Bifunctor (second)
import Data.List (foldl')
import qualified Data.Map as M
import Data.Maybe
import Futhark.CodeGen.ImpCode.GPU (bytes)
import qualified Futhark.CodeGen.ImpCode.GPU as Imp
import Futhark.CodeGen.ImpGen hiding (compileProg)
import qualified Futhark.CodeGen.ImpGen
import Futhark.CodeGen.ImpGen.GPU.Base
import Futhark.CodeGen.ImpGen.GPU.SegHist
import Futhark.CodeGen.ImpGen.GPU.SegMap
import Futhark.CodeGen.ImpGen.GPU.SegRed
import Futhark.CodeGen.ImpGen.GPU.SegScan
import Futhark.CodeGen.ImpGen.GPU.Transpose
import Futhark.CodeGen.SetDefaultSpace
import Futhark.Error
import Futhark.IR.GPUMem
import qualified Futhark.IR.Mem.IxFun as IxFun
import Futhark.MonadFreshNames
import Futhark.Util.IntegralExp (IntegralExp, divUp, quot, rem)
import Prelude hiding (quot, rem)

callKernelOperations :: Operations GPUMem HostEnv Imp.HostOp
callKernelOperations :: Operations GPUMem HostEnv HostOp
callKernelOperations =
  Operations :: forall rep r op.
ExpCompiler rep r op
-> OpCompiler rep r op
-> StmsCompiler rep r op
-> CopyCompiler rep r op
-> Map Space (AllocCompiler rep r op)
-> Operations rep r op
Operations
    { opsExpCompiler :: ExpCompiler GPUMem HostEnv HostOp
opsExpCompiler = ExpCompiler GPUMem HostEnv HostOp
expCompiler,
      opsCopyCompiler :: CopyCompiler GPUMem HostEnv HostOp
opsCopyCompiler = CopyCompiler GPUMem HostEnv HostOp
callKernelCopy,
      opsOpCompiler :: OpCompiler GPUMem HostEnv HostOp
opsOpCompiler = OpCompiler GPUMem HostEnv HostOp
Pat LetDecMem -> Op GPUMem -> CallKernelGen ()
opCompiler,
      opsStmsCompiler :: StmsCompiler GPUMem HostEnv HostOp
opsStmsCompiler = StmsCompiler GPUMem HostEnv HostOp
forall rep inner op r.
(Mem rep inner, FreeIn op) =>
Names -> Stms rep -> ImpM rep r op () -> ImpM rep r op ()
defCompileStms,
      opsAllocCompilers :: Map Space (AllocCompiler GPUMem HostEnv HostOp)
opsAllocCompilers = Map Space (AllocCompiler GPUMem HostEnv HostOp)
forall a. Monoid a => a
mempty
    }

openclAtomics, cudaAtomics :: AtomicBinOp
(AtomicBinOp
openclAtomics, AtomicBinOp
cudaAtomics) = ((BinOp
 -> [(BinOp,
      VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
 -> Maybe
      (VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp))
-> [(BinOp,
     VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
-> AtomicBinOp
forall a b c. (a -> b -> c) -> b -> a -> c
flip BinOp
-> [(BinOp,
     VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
-> Maybe
     (VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
opencl, (BinOp
 -> [(BinOp,
      VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
 -> Maybe
      (VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp))
-> [(BinOp,
     VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
-> AtomicBinOp
forall a b c. (a -> b -> c) -> b -> a -> c
flip BinOp
-> [(BinOp,
     VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
-> Maybe
     (VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
cuda)
  where
    opencl64 :: [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
opencl64 =
      [ (IntType -> Overflow -> BinOp
Add IntType
Int64 Overflow
OverflowUndef, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicAdd IntType
Int64),
        (IntType -> BinOp
SMax IntType
Int64, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicSMax IntType
Int64),
        (IntType -> BinOp
SMin IntType
Int64, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicSMin IntType
Int64),
        (IntType -> BinOp
UMax IntType
Int64, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicUMax IntType
Int64),
        (IntType -> BinOp
UMin IntType
Int64, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicUMin IntType
Int64),
        (IntType -> BinOp
And IntType
Int64, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicAnd IntType
Int64),
        (IntType -> BinOp
Or IntType
Int64, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicOr IntType
Int64),
        (IntType -> BinOp
Xor IntType
Int64, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicXor IntType
Int64)
      ]
    opencl32 :: [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
opencl32 =
      [ (IntType -> Overflow -> BinOp
Add IntType
Int32 Overflow
OverflowUndef, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicAdd IntType
Int32),
        (IntType -> BinOp
SMax IntType
Int32, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicSMax IntType
Int32),
        (IntType -> BinOp
SMin IntType
Int32, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicSMin IntType
Int32),
        (IntType -> BinOp
UMax IntType
Int32, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicUMax IntType
Int32),
        (IntType -> BinOp
UMin IntType
Int32, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicUMin IntType
Int32),
        (IntType -> BinOp
And IntType
Int32, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicAnd IntType
Int32),
        (IntType -> BinOp
Or IntType
Int32, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicOr IntType
Int32),
        (IntType -> BinOp
Xor IntType
Int32, IntType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicXor IntType
Int32)
      ]
    opencl :: [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
opencl = [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
opencl32 [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
-> [(BinOp,
     VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
-> [(BinOp,
     VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
forall a. [a] -> [a] -> [a]
++ [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
opencl64
    cuda :: [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
cuda =
      [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
opencl
        [(BinOp,
  VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
-> [(BinOp,
     VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
-> [(BinOp,
     VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)]
forall a. [a] -> [a] -> [a]
++ [ (FloatType -> BinOp
FAdd FloatType
Float32, FloatType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicFAdd FloatType
Float32),
             (FloatType -> BinOp
FAdd FloatType
Float64, FloatType
-> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
Imp.AtomicFAdd FloatType
Float64)
           ]

compileProg ::
  MonadFreshNames m =>
  HostEnv ->
  Prog GPUMem ->
  m (Warnings, Imp.Program)
compileProg :: HostEnv -> Prog GPUMem -> m (Warnings, Program)
compileProg HostEnv
env Prog GPUMem
prog =
  (Program -> Program) -> (Warnings, Program) -> (Warnings, Program)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ((HostOp -> HostOp) -> Program -> Program
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap HostOp -> HostOp
setOpSpace (Program -> Program) -> (Program -> Program) -> Program -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program -> Program
forall op. Definitions op -> Definitions op
setDefsSpace)
    ((Warnings, Program) -> (Warnings, Program))
-> m (Warnings, Program) -> m (Warnings, Program)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HostEnv
-> Operations GPUMem HostEnv HostOp
-> Space
-> Prog GPUMem
-> m (Warnings, Program)
forall rep inner op (m :: * -> *) r.
(Mem rep inner, FreeIn op, MonadFreshNames m) =>
r
-> Operations rep r op
-> Space
-> Prog rep
-> m (Warnings, Definitions op)
Futhark.CodeGen.ImpGen.compileProg HostEnv
env Operations GPUMem HostEnv HostOp
callKernelOperations Space
device_space Prog GPUMem
prog
  where
    device_space :: Space
device_space = SpaceId -> Space
Imp.Space SpaceId
"device"
    global_space :: Space
global_space = SpaceId -> Space
Imp.Space SpaceId
"global"
    setDefsSpace :: Definitions op -> Definitions op
setDefsSpace = Space -> Definitions op -> Definitions op
forall op. Space -> Definitions op -> Definitions op
setDefaultSpace Space
device_space
    setOpSpace :: HostOp -> HostOp
setOpSpace (Imp.CallKernel Kernel
kernel) =
      Kernel -> HostOp
Imp.CallKernel
        Kernel
kernel
          { kernelBody :: Code KernelOp
Imp.kernelBody =
              Space -> Code KernelOp -> Code KernelOp
forall op. Space -> Code op -> Code op
setDefaultCodeSpace Space
global_space (Code KernelOp -> Code KernelOp) -> Code KernelOp -> Code KernelOp
forall a b. (a -> b) -> a -> b
$ Kernel -> Code KernelOp
Imp.kernelBody Kernel
kernel
          }
    setOpSpace HostOp
op = HostOp
op

-- | Compile a 'GPUMem' program to low-level parallel code, with
-- either CUDA or OpenCL characteristics.
compileProgOpenCL,
  compileProgCUDA ::
    MonadFreshNames m => Prog GPUMem -> m (Warnings, Imp.Program)
compileProgOpenCL :: Prog GPUMem -> m (Warnings, Program)
compileProgOpenCL = HostEnv -> Prog GPUMem -> m (Warnings, Program)
forall (m :: * -> *).
MonadFreshNames m =>
HostEnv -> Prog GPUMem -> m (Warnings, Program)
compileProg (HostEnv -> Prog GPUMem -> m (Warnings, Program))
-> HostEnv -> Prog GPUMem -> m (Warnings, Program)
forall a b. (a -> b) -> a -> b
$ AtomicBinOp -> Target -> Map VName Locks -> HostEnv
HostEnv AtomicBinOp
openclAtomics Target
OpenCL Map VName Locks
forall a. Monoid a => a
mempty
compileProgCUDA :: Prog GPUMem -> m (Warnings, Program)
compileProgCUDA = HostEnv -> Prog GPUMem -> m (Warnings, Program)
forall (m :: * -> *).
MonadFreshNames m =>
HostEnv -> Prog GPUMem -> m (Warnings, Program)
compileProg (HostEnv -> Prog GPUMem -> m (Warnings, Program))
-> HostEnv -> Prog GPUMem -> m (Warnings, Program)
forall a b. (a -> b) -> a -> b
$ AtomicBinOp -> Target -> Map VName Locks -> HostEnv
HostEnv AtomicBinOp
cudaAtomics Target
CUDA Map VName Locks
forall a. Monoid a => a
mempty

opCompiler ::
  Pat LetDecMem ->
  Op GPUMem ->
  CallKernelGen ()
opCompiler :: Pat LetDecMem -> Op GPUMem -> CallKernelGen ()
opCompiler Pat LetDecMem
dest (Alloc e space) =
  Pat (LetDec GPUMem) -> SubExp -> Space -> CallKernelGen ()
forall rep inner r op.
Mem rep inner =>
Pat (LetDec rep) -> SubExp -> Space -> ImpM rep r op ()
compileAlloc Pat (LetDec GPUMem)
Pat LetDecMem
dest SubExp
e Space
space
opCompiler (Pat [PatElem LetDecMem
pe]) (Inner (SizeOp (GetSize key size_class))) = do
  Maybe Name
fname <- ImpM GPUMem HostEnv HostOp (Maybe Name)
forall rep r op. ImpM rep r op (Maybe Name)
askFunction
  HostOp -> CallKernelGen ()
forall op rep r. op -> ImpM rep r op ()
sOp (HostOp -> CallKernelGen ()) -> HostOp -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$
    VName -> Name -> SizeClass -> HostOp
Imp.GetSize (PatElem LetDecMem -> VName
forall dec. PatElem dec -> VName
patElemName PatElem LetDecMem
pe) (Maybe Name -> Name -> Name
keyWithEntryPoint Maybe Name
fname Name
key) (SizeClass -> HostOp) -> SizeClass -> HostOp
forall a b. (a -> b) -> a -> b
$
      Maybe Name -> SizeClass -> SizeClass
sizeClassWithEntryPoint Maybe Name
fname SizeClass
size_class
opCompiler (Pat [PatElem LetDecMem
pe]) (Inner (SizeOp (CmpSizeLe key size_class x))) = do
  Maybe Name
fname <- ImpM GPUMem HostEnv HostOp (Maybe Name)
forall rep r op. ImpM rep r op (Maybe Name)
askFunction
  let size_class' :: SizeClass
size_class' = Maybe Name -> SizeClass -> SizeClass
sizeClassWithEntryPoint Maybe Name
fname SizeClass
size_class
  HostOp -> CallKernelGen ()
forall op rep r. op -> ImpM rep r op ()
sOp (HostOp -> CallKernelGen ())
-> (Exp -> HostOp) -> Exp -> CallKernelGen ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VName -> Name -> SizeClass -> Exp -> HostOp
Imp.CmpSizeLe (PatElem LetDecMem -> VName
forall dec. PatElem dec -> VName
patElemName PatElem LetDecMem
pe) (Maybe Name -> Name -> Name
keyWithEntryPoint Maybe Name
fname Name
key) SizeClass
size_class'
    (Exp -> CallKernelGen ())
-> ImpM GPUMem HostEnv HostOp Exp -> CallKernelGen ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< SubExp -> ImpM GPUMem HostEnv HostOp Exp
forall a rep r op. ToExp a => a -> ImpM rep r op Exp
toExp SubExp
x
opCompiler (Pat [PatElem LetDecMem
pe]) (Inner (SizeOp (GetSizeMax size_class))) =
  HostOp -> CallKernelGen ()
forall op rep r. op -> ImpM rep r op ()
sOp (HostOp -> CallKernelGen ()) -> HostOp -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ VName -> SizeClass -> HostOp
Imp.GetSizeMax (PatElem LetDecMem -> VName
forall dec. PatElem dec -> VName
patElemName PatElem LetDecMem
pe) SizeClass
size_class
opCompiler (Pat [PatElem LetDecMem
pe]) (Inner (SizeOp (CalcNumGroups w64 max_num_groups_key group_size))) = do
  Maybe Name
fname <- ImpM GPUMem HostEnv HostOp (Maybe Name)
forall rep r op. ImpM rep r op (Maybe Name)
askFunction
  TV Int32
max_num_groups :: TV Int32 <- SpaceId -> PrimType -> ImpM GPUMem HostEnv HostOp (TV Int32)
forall rep r op t. SpaceId -> PrimType -> ImpM rep r op (TV t)
dPrim SpaceId
"max_num_groups" PrimType
int32
  HostOp -> CallKernelGen ()
forall op rep r. op -> ImpM rep r op ()
sOp (HostOp -> CallKernelGen ()) -> HostOp -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$
    VName -> Name -> SizeClass -> HostOp
Imp.GetSize (TV Int32 -> VName
forall t. TV t -> VName
tvVar TV Int32
max_num_groups) (Maybe Name -> Name -> Name
keyWithEntryPoint Maybe Name
fname Name
max_num_groups_key) (SizeClass -> HostOp) -> SizeClass -> HostOp
forall a b. (a -> b) -> a -> b
$
      Maybe Name -> SizeClass -> SizeClass
sizeClassWithEntryPoint Maybe Name
fname SizeClass
SizeNumGroups

  -- If 'w' is small, we launch fewer groups than we normally would.
  -- We don't want any idle groups.
  --
  -- The calculations are done with 64-bit integers to avoid overflow
  -- issues.
  let num_groups_maybe_zero :: TExp Int64
num_groups_maybe_zero =
        TExp Int64 -> TExp Int64 -> TExp Int64
forall v. TPrimExp Int64 v -> TPrimExp Int64 v -> TPrimExp Int64 v
sMin64 (SubExp -> TExp Int64
forall a. ToExp a => a -> TExp Int64
toInt64Exp SubExp
w64 TExp Int64 -> TExp Int64 -> TExp Int64
forall e. IntegralExp e => e -> e -> e
`divUp` SubExp -> TExp Int64
forall a. ToExp a => a -> TExp Int64
toInt64Exp SubExp
group_size) (TExp Int64 -> TExp Int64) -> TExp Int64 -> TExp Int64
forall a b. (a -> b) -> a -> b
$
          TPrimExp Int32 VName -> TExp Int64
forall t v. IntExp t => TPrimExp t v -> TPrimExp Int64 v
sExt64 (TV Int32 -> TPrimExp Int32 VName
forall t. TV t -> TExp t
tvExp TV Int32
max_num_groups)
  -- We also don't want zero groups.
  let num_groups :: TExp Int64
num_groups = TExp Int64 -> TExp Int64 -> TExp Int64
forall v. TPrimExp Int64 v -> TPrimExp Int64 v -> TPrimExp Int64 v
sMax64 TExp Int64
1 TExp Int64
num_groups_maybe_zero
  VName -> PrimType -> TV Int32
forall t. VName -> PrimType -> TV t
mkTV (PatElem LetDecMem -> VName
forall dec. PatElem dec -> VName
patElemName PatElem LetDecMem
pe) PrimType
int32 TV Int32 -> TPrimExp Int32 VName -> CallKernelGen ()
forall t rep r op. TV t -> TExp t -> ImpM rep r op ()
<-- TExp Int64 -> TPrimExp Int32 VName
forall t v. IntExp t => TPrimExp t v -> TPrimExp Int32 v
sExt32 TExp Int64
num_groups
opCompiler Pat LetDecMem
dest (Inner (SegOp op)) =
  Pat LetDecMem -> SegOp SegLevel GPUMem -> CallKernelGen ()
segOpCompiler Pat LetDecMem
dest SegOp SegLevel GPUMem
op
opCompiler Pat LetDecMem
pat Op GPUMem
e =
  SpaceId -> CallKernelGen ()
forall a. SpaceId -> a
compilerBugS (SpaceId -> CallKernelGen ()) -> SpaceId -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$
    SpaceId
"opCompiler: Invalid pattern\n  "
      SpaceId -> SpaceId -> SpaceId
forall a. [a] -> [a] -> [a]
++ Pat LetDecMem -> SpaceId
forall a. Pretty a => a -> SpaceId
pretty Pat LetDecMem
pat
      SpaceId -> SpaceId -> SpaceId
forall a. [a] -> [a] -> [a]
++ SpaceId
"\nfor expression\n  "
      SpaceId -> SpaceId -> SpaceId
forall a. [a] -> [a] -> [a]
++ MemOp (HostOp GPUMem ()) -> SpaceId
forall a. Pretty a => a -> SpaceId
pretty Op GPUMem
MemOp (HostOp GPUMem ())
e

sizeClassWithEntryPoint :: Maybe Name -> Imp.SizeClass -> Imp.SizeClass
sizeClassWithEntryPoint :: Maybe Name -> SizeClass -> SizeClass
sizeClassWithEntryPoint Maybe Name
fname (Imp.SizeThreshold KernelPath
path Maybe Int64
def) =
  KernelPath -> Maybe Int64 -> SizeClass
Imp.SizeThreshold (((Name, Bool) -> (Name, Bool)) -> KernelPath -> KernelPath
forall a b. (a -> b) -> [a] -> [b]
map (Name, Bool) -> (Name, Bool)
f KernelPath
path) Maybe Int64
def
  where
    f :: (Name, Bool) -> (Name, Bool)
f (Name
name, Bool
x) = (Maybe Name -> Name -> Name
keyWithEntryPoint Maybe Name
fname Name
name, Bool
x)
sizeClassWithEntryPoint Maybe Name
_ SizeClass
size_class = SizeClass
size_class

segOpCompiler ::
  Pat LetDecMem ->
  SegOp SegLevel GPUMem ->
  CallKernelGen ()
segOpCompiler :: Pat LetDecMem -> SegOp SegLevel GPUMem -> CallKernelGen ()
segOpCompiler Pat LetDecMem
pat (SegMap SegLevel
lvl SegSpace
space [Type]
_ KernelBody GPUMem
kbody) =
  Pat LetDecMem
-> SegLevel -> SegSpace -> KernelBody GPUMem -> CallKernelGen ()
compileSegMap Pat LetDecMem
pat SegLevel
lvl SegSpace
space KernelBody GPUMem
kbody
segOpCompiler Pat LetDecMem
pat (SegRed lvl :: SegLevel
lvl@SegThread {} SegSpace
space [SegBinOp GPUMem]
reds [Type]
_ KernelBody GPUMem
kbody) =
  Pat LetDecMem
-> SegLevel
-> SegSpace
-> [SegBinOp GPUMem]
-> KernelBody GPUMem
-> CallKernelGen ()
compileSegRed Pat LetDecMem
pat SegLevel
lvl SegSpace
space [SegBinOp GPUMem]
reds KernelBody GPUMem
kbody
segOpCompiler Pat LetDecMem
pat (SegScan lvl :: SegLevel
lvl@SegThread {} SegSpace
space [SegBinOp GPUMem]
scans [Type]
_ KernelBody GPUMem
kbody) =
  Pat LetDecMem
-> SegLevel
-> SegSpace
-> [SegBinOp GPUMem]
-> KernelBody GPUMem
-> CallKernelGen ()
compileSegScan Pat LetDecMem
pat SegLevel
lvl SegSpace
space [SegBinOp GPUMem]
scans KernelBody GPUMem
kbody
segOpCompiler Pat LetDecMem
pat (SegHist (SegThread Count NumGroups SubExp
num_groups Count GroupSize SubExp
group_size SegVirt
_) SegSpace
space [HistOp GPUMem]
ops [Type]
_ KernelBody GPUMem
kbody) =
  Pat LetDecMem
-> Count NumGroups SubExp
-> Count GroupSize SubExp
-> SegSpace
-> [HistOp GPUMem]
-> KernelBody GPUMem
-> CallKernelGen ()
compileSegHist Pat LetDecMem
pat Count NumGroups SubExp
num_groups Count GroupSize SubExp
group_size SegSpace
space [HistOp GPUMem]
ops KernelBody GPUMem
kbody
segOpCompiler Pat LetDecMem
pat SegOp SegLevel GPUMem
segop =
  SpaceId -> CallKernelGen ()
forall a. SpaceId -> a
compilerBugS (SpaceId -> CallKernelGen ()) -> SpaceId -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ SpaceId
"segOpCompiler: unexpected " SpaceId -> SpaceId -> SpaceId
forall a. [a] -> [a] -> [a]
++ SegLevel -> SpaceId
forall a. Pretty a => a -> SpaceId
pretty (SegOp SegLevel GPUMem -> SegLevel
forall lvl rep. SegOp lvl rep -> lvl
segLevel SegOp SegLevel GPUMem
segop) SpaceId -> SpaceId -> SpaceId
forall a. [a] -> [a] -> [a]
++ SpaceId
" for rhs of pattern " SpaceId -> SpaceId -> SpaceId
forall a. [a] -> [a] -> [a]
++ Pat LetDecMem -> SpaceId
forall a. Pretty a => a -> SpaceId
pretty Pat LetDecMem
pat

-- Create boolean expression that checks whether all kernels in the
-- enclosed code do not use more local memory than we have available.
-- We look at *all* the kernels here, even those that might be
-- otherwise protected by their own multi-versioning branches deeper
-- down.  Currently the compiler will not generate multi-versioning
-- that makes this a problem, but it might in the future.
checkLocalMemoryReqs :: Imp.HostCode -> CallKernelGen (Maybe (Imp.TExp Bool))
checkLocalMemoryReqs :: HostCode -> CallKernelGen (Maybe (TExp Bool))
checkLocalMemoryReqs HostCode
code = do
  Scope SOACS
scope <- ImpM GPUMem HostEnv HostOp (Scope SOACS)
forall rep (m :: * -> *). HasScope rep m => m (Scope rep)
askScope
  let alloc_sizes :: [Count Bytes (TExp Int64)]
alloc_sizes = (Kernel -> Count Bytes (TExp Int64))
-> [Kernel] -> [Count Bytes (TExp Int64)]
forall a b. (a -> b) -> [a] -> [b]
map ([Count Bytes (TExp Int64)] -> Count Bytes (TExp Int64)
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Count Bytes (TExp Int64)] -> Count Bytes (TExp Int64))
-> (Kernel -> [Count Bytes (TExp Int64)])
-> Kernel
-> Count Bytes (TExp Int64)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Count Bytes (TExp Int64) -> Count Bytes (TExp Int64))
-> [Count Bytes (TExp Int64)] -> [Count Bytes (TExp Int64)]
forall a b. (a -> b) -> [a] -> [b]
map Count Bytes (TExp Int64) -> Count Bytes (TExp Int64)
forall e. IntegralExp e => e -> e
alignedSize ([Count Bytes (TExp Int64)] -> [Count Bytes (TExp Int64)])
-> (Kernel -> [Count Bytes (TExp Int64)])
-> Kernel
-> [Count Bytes (TExp Int64)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Code KernelOp -> [Count Bytes (TExp Int64)]
localAllocSizes (Code KernelOp -> [Count Bytes (TExp Int64)])
-> (Kernel -> Code KernelOp)
-> Kernel
-> [Count Bytes (TExp Int64)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Kernel -> Code KernelOp
Imp.kernelBody) ([Kernel] -> [Count Bytes (TExp Int64)])
-> [Kernel] -> [Count Bytes (TExp Int64)]
forall a b. (a -> b) -> a -> b
$ HostCode -> [Kernel]
getGPU HostCode
code

  -- If any of the sizes involve a variable that is not known at this
  -- point, then we cannot check the requirements.
  if (VName -> Bool) -> [VName] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (VName -> Scope SOACS -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`M.notMember` Scope SOACS
scope) (Names -> [VName]
namesToList (Names -> [VName]) -> Names -> [VName]
forall a b. (a -> b) -> a -> b
$ [Count Bytes (TExp Int64)] -> Names
forall a. FreeIn a => a -> Names
freeIn [Count Bytes (TExp Int64)]
alloc_sizes)
    then Maybe (TExp Bool) -> CallKernelGen (Maybe (TExp Bool))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (TExp Bool)
forall a. Maybe a
Nothing
    else do
      TV Int32
local_memory_capacity :: TV Int32 <- SpaceId -> PrimType -> ImpM GPUMem HostEnv HostOp (TV Int32)
forall rep r op t. SpaceId -> PrimType -> ImpM rep r op (TV t)
dPrim SpaceId
"local_memory_capacity" PrimType
int32
      HostOp -> CallKernelGen ()
forall op rep r. op -> ImpM rep r op ()
sOp (HostOp -> CallKernelGen ()) -> HostOp -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ VName -> SizeClass -> HostOp
Imp.GetSizeMax (TV Int32 -> VName
forall t. TV t -> VName
tvVar TV Int32
local_memory_capacity) SizeClass
SizeLocalMemory

      let local_memory_capacity_64 :: TExp Int64
local_memory_capacity_64 =
            TPrimExp Int32 VName -> TExp Int64
forall t v. IntExp t => TPrimExp t v -> TPrimExp Int64 v
sExt64 (TPrimExp Int32 VName -> TExp Int64)
-> TPrimExp Int32 VName -> TExp Int64
forall a b. (a -> b) -> a -> b
$ TV Int32 -> TPrimExp Int32 VName
forall t. TV t -> TExp t
tvExp TV Int32
local_memory_capacity
          fits :: Count Bytes (TExp Int64) -> TExp Bool
fits Count Bytes (TExp Int64)
size =
            Count Bytes (TExp Int64) -> TExp Int64
forall u e. Count u e -> e
unCount Count Bytes (TExp Int64)
size TExp Int64 -> TExp Int64 -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.<=. TExp Int64
local_memory_capacity_64
      Maybe (TExp Bool) -> CallKernelGen (Maybe (TExp Bool))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (TExp Bool) -> CallKernelGen (Maybe (TExp Bool)))
-> Maybe (TExp Bool) -> CallKernelGen (Maybe (TExp Bool))
forall a b. (a -> b) -> a -> b
$ TExp Bool -> Maybe (TExp Bool)
forall a. a -> Maybe a
Just (TExp Bool -> Maybe (TExp Bool)) -> TExp Bool -> Maybe (TExp Bool)
forall a b. (a -> b) -> a -> b
$ (TExp Bool -> TExp Bool -> TExp Bool)
-> TExp Bool -> [TExp Bool] -> TExp Bool
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
(.&&.) TExp Bool
forall v. TPrimExp Bool v
true ((Count Bytes (TExp Int64) -> TExp Bool)
-> [Count Bytes (TExp Int64)] -> [TExp Bool]
forall a b. (a -> b) -> [a] -> [b]
map Count Bytes (TExp Int64) -> TExp Bool
fits [Count Bytes (TExp Int64)]
alloc_sizes)
  where
    getGPU :: HostCode -> [Kernel]
getGPU = (HostOp -> [Kernel]) -> HostCode -> [Kernel]
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap HostOp -> [Kernel]
getKernel
    getKernel :: HostOp -> [Kernel]
getKernel (Imp.CallKernel Kernel
k) | Kernel -> Bool
Imp.kernelCheckLocalMemory Kernel
k = [Kernel
k]
    getKernel HostOp
_ = []

    localAllocSizes :: Code KernelOp -> [Count Bytes (TExp Int64)]
localAllocSizes = (KernelOp -> [Count Bytes (TExp Int64)])
-> Code KernelOp -> [Count Bytes (TExp Int64)]
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap KernelOp -> [Count Bytes (TExp Int64)]
localAllocSize
    localAllocSize :: KernelOp -> [Count Bytes (TExp Int64)]
localAllocSize (Imp.LocalAlloc VName
_ Count Bytes (TExp Int64)
size) = [Count Bytes (TExp Int64)
size]
    localAllocSize KernelOp
_ = []

    -- These allocations will actually be padded to an 8-byte aligned
    -- size, so we should take that into account when checking whether
    -- they fit.
    alignedSize :: e -> e
alignedSize e
x = e
x e -> e -> e
forall a. Num a => a -> a -> a
+ ((e
8 e -> e -> e
forall a. Num a => a -> a -> a
- (e
x e -> e -> e
forall e. IntegralExp e => e -> e -> e
`rem` e
8)) e -> e -> e
forall e. IntegralExp e => e -> e -> e
`rem` e
8)

withAcc ::
  Pat LetDecMem ->
  [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))] ->
  Lambda GPUMem ->
  CallKernelGen ()
withAcc :: Pat LetDecMem
-> [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
-> Lambda GPUMem
-> CallKernelGen ()
withAcc Pat LetDecMem
pat [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
inputs Lambda GPUMem
lam = do
  AtomicBinOp
atomics <- HostEnv -> AtomicBinOp
hostAtomics (HostEnv -> AtomicBinOp)
-> ImpM GPUMem HostEnv HostOp HostEnv
-> ImpM GPUMem HostEnv HostOp AtomicBinOp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ImpM GPUMem HostEnv HostOp HostEnv
forall rep r op. ImpM rep r op r
askEnv
  AtomicBinOp
-> [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
-> CallKernelGen ()
locksForInputs AtomicBinOp
atomics ([(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
 -> CallKernelGen ())
-> [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
-> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ [VName]
-> [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
-> [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
forall a b. [a] -> [b] -> [(a, b)]
zip [VName]
accs [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
inputs
  where
    accs :: [VName]
accs = (Param LetDecMem -> VName) -> [Param LetDecMem] -> [VName]
forall a b. (a -> b) -> [a] -> [b]
map Param LetDecMem -> VName
forall dec. Param dec -> VName
paramName ([Param LetDecMem] -> [VName]) -> [Param LetDecMem] -> [VName]
forall a b. (a -> b) -> a -> b
$ Lambda GPUMem -> [LParam GPUMem]
forall rep. Lambda rep -> [LParam rep]
lambdaParams Lambda GPUMem
lam
    locksForInputs :: AtomicBinOp
-> [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
-> CallKernelGen ()
locksForInputs AtomicBinOp
_ [] =
      ExpCompiler GPUMem HostEnv HostOp
forall rep inner r op.
Mem rep inner =>
Pat (LetDec rep) -> Exp rep -> ImpM rep r op ()
defCompileExp Pat (LetDec GPUMem)
Pat LetDecMem
pat (Exp GPUMem -> CallKernelGen ()) -> Exp GPUMem -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
-> Lambda GPUMem -> Exp GPUMem
forall rep. [WithAccInput rep] -> Lambda rep -> Exp rep
WithAcc [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
inputs Lambda GPUMem
lam
    locksForInputs AtomicBinOp
atomics ((VName
c, (Shape
_, [VName]
_, Maybe (Lambda GPUMem, [SubExp])
op)) : [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
inputs')
      | Just (Lambda GPUMem
op_lam, [SubExp]
_) <- Maybe (Lambda GPUMem, [SubExp])
op,
        AtomicLocking Locking -> DoAtomicUpdate GPUMem KernelEnv
_ <- AtomicBinOp -> Lambda GPUMem -> AtomicUpdate GPUMem KernelEnv
atomicUpdateLocking AtomicBinOp
atomics Lambda GPUMem
op_lam = do
        let num_locks :: Int
num_locks = Int
100151
        VName
locks_arr <-
          SpaceId
-> Space
-> PrimType
-> ArrayContents
-> ImpM GPUMem HostEnv HostOp VName
forall rep r op.
SpaceId
-> Space -> PrimType -> ArrayContents -> ImpM rep r op VName
sStaticArray SpaceId
"withacc_locks" (SpaceId -> Space
Space SpaceId
"device") PrimType
int32 (ArrayContents -> ImpM GPUMem HostEnv HostOp VName)
-> ArrayContents -> ImpM GPUMem HostEnv HostOp VName
forall a b. (a -> b) -> a -> b
$
            Int -> ArrayContents
Imp.ArrayZeros Int
num_locks
        let locks :: Locks
locks = VName -> Int -> Locks
Locks VName
locks_arr Int
num_locks
            extend :: HostEnv -> HostEnv
extend HostEnv
env = HostEnv
env {hostLocks :: Map VName Locks
hostLocks = VName -> Locks -> Map VName Locks -> Map VName Locks
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert VName
c Locks
locks (Map VName Locks -> Map VName Locks)
-> Map VName Locks -> Map VName Locks
forall a b. (a -> b) -> a -> b
$ HostEnv -> Map VName Locks
hostLocks HostEnv
env}
        (HostEnv -> HostEnv) -> CallKernelGen () -> CallKernelGen ()
forall r rep op a. (r -> r) -> ImpM rep r op a -> ImpM rep r op a
localEnv HostEnv -> HostEnv
extend (CallKernelGen () -> CallKernelGen ())
-> CallKernelGen () -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ AtomicBinOp
-> [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
-> CallKernelGen ()
locksForInputs AtomicBinOp
atomics [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
inputs'
      | Bool
otherwise =
        AtomicBinOp
-> [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
-> CallKernelGen ()
locksForInputs AtomicBinOp
atomics [(VName, (Shape, [VName], Maybe (Lambda GPUMem, [SubExp])))]
inputs'

expCompiler :: ExpCompiler GPUMem HostEnv Imp.HostOp
-- We generate a simple kernel for itoa and replicate.
expCompiler :: ExpCompiler GPUMem HostEnv HostOp
expCompiler (Pat [PatElem (LetDec GPUMem)
pe]) (BasicOp (Iota SubExp
n SubExp
x SubExp
s IntType
et)) = do
  Exp
x' <- SubExp -> ImpM GPUMem HostEnv HostOp Exp
forall a rep r op. ToExp a => a -> ImpM rep r op Exp
toExp SubExp
x
  Exp
s' <- SubExp -> ImpM GPUMem HostEnv HostOp Exp
forall a rep r op. ToExp a => a -> ImpM rep r op Exp
toExp SubExp
s

  VName -> TExp Int64 -> Exp -> Exp -> IntType -> CallKernelGen ()
sIota (PatElem LetDecMem -> VName
forall dec. PatElem dec -> VName
patElemName PatElem (LetDec GPUMem)
PatElem LetDecMem
pe) (SubExp -> TExp Int64
forall a. ToExp a => a -> TExp Int64
toInt64Exp SubExp
n) Exp
x' Exp
s' IntType
et
expCompiler (Pat [PatElem (LetDec GPUMem)
pe]) (BasicOp (Replicate Shape
_ SubExp
se))
  | Acc {} <- PatElem LetDecMem -> Type
forall dec. Typed dec => PatElem dec -> Type
patElemType PatElem (LetDec GPUMem)
PatElem LetDecMem
pe = () -> CallKernelGen ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  | Bool
otherwise =
    VName -> SubExp -> CallKernelGen ()
sReplicate (PatElem LetDecMem -> VName
forall dec. PatElem dec -> VName
patElemName PatElem (LetDec GPUMem)
PatElem LetDecMem
pe) SubExp
se
-- Allocation in the "local" space is just a placeholder.
expCompiler Pat (LetDec GPUMem)
_ (Op (Alloc _ (Space "local"))) =
  () -> CallKernelGen ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
expCompiler Pat (LetDec GPUMem)
pat (WithAcc [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
inputs Lambda GPUMem
lam) =
  Pat LetDecMem
-> [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
-> Lambda GPUMem
-> CallKernelGen ()
withAcc Pat (LetDec GPUMem)
Pat LetDecMem
pat [(Shape, [VName], Maybe (Lambda GPUMem, [SubExp]))]
inputs Lambda GPUMem
lam
-- This is a multi-versioning If created by incremental flattening.
-- We need to augment the conditional with a check that any local
-- memory requirements in tbranch are compatible with the hardware.
-- We do not check anything for fbranch, as we assume that it will
-- always be safe (and what would we do if none of the branches would
-- work?).
expCompiler Pat (LetDec GPUMem)
dest (If SubExp
cond Body GPUMem
tbranch Body GPUMem
fbranch (IfDec [BranchType GPUMem]
_ IfSort
IfEquiv)) = do
  HostCode
tcode <- CallKernelGen () -> ImpM GPUMem HostEnv HostOp HostCode
forall rep r op. ImpM rep r op () -> ImpM rep r op (Code op)
collect (CallKernelGen () -> ImpM GPUMem HostEnv HostOp HostCode)
-> CallKernelGen () -> ImpM GPUMem HostEnv HostOp HostCode
forall a b. (a -> b) -> a -> b
$ Pat (LetDec GPUMem) -> Body GPUMem -> CallKernelGen ()
forall rep r op. Pat (LetDec rep) -> Body rep -> ImpM rep r op ()
compileBody Pat (LetDec GPUMem)
dest Body GPUMem
tbranch
  HostCode
fcode <- CallKernelGen () -> ImpM GPUMem HostEnv HostOp HostCode
forall rep r op. ImpM rep r op () -> ImpM rep r op (Code op)
collect (CallKernelGen () -> ImpM GPUMem HostEnv HostOp HostCode)
-> CallKernelGen () -> ImpM GPUMem HostEnv HostOp HostCode
forall a b. (a -> b) -> a -> b
$ Pat (LetDec GPUMem) -> Body GPUMem -> CallKernelGen ()
forall rep r op. Pat (LetDec rep) -> Body rep -> ImpM rep r op ()
compileBody Pat (LetDec GPUMem)
dest Body GPUMem
fbranch
  Maybe (TExp Bool)
check <- HostCode -> CallKernelGen (Maybe (TExp Bool))
checkLocalMemoryReqs HostCode
tcode
  HostCode -> CallKernelGen ()
forall op rep r. Code op -> ImpM rep r op ()
emit (HostCode -> CallKernelGen ()) -> HostCode -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ case Maybe (TExp Bool)
check of
    Maybe (TExp Bool)
Nothing -> HostCode
fcode
    Just TExp Bool
ok -> TExp Bool -> HostCode -> HostCode -> HostCode
forall a. TExp Bool -> Code a -> Code a -> Code a
Imp.If (TExp Bool
ok TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
.&&. SubExp -> TExp Bool
forall a. ToExp a => a -> TExp Bool
toBoolExp SubExp
cond) HostCode
tcode HostCode
fcode
expCompiler Pat (LetDec GPUMem)
dest Exp GPUMem
e =
  ExpCompiler GPUMem HostEnv HostOp
forall rep inner r op.
Mem rep inner =>
Pat (LetDec rep) -> Exp rep -> ImpM rep r op ()
defCompileExp Pat (LetDec GPUMem)
dest Exp GPUMem
e

callKernelCopy :: CopyCompiler GPUMem HostEnv Imp.HostOp
callKernelCopy :: CopyCompiler GPUMem HostEnv HostOp
callKernelCopy PrimType
bt destloc :: MemLoc
destloc@(MemLoc VName
destmem [SubExp]
_ IxFun (TExp Int64)
destIxFun) srcloc :: MemLoc
srcloc@(MemLoc VName
srcmem [SubExp]
srcshape IxFun (TExp Int64)
srcIxFun)
  | Just (TExp Int64
destoffset, TExp Int64
srcoffset, TExp Int64
num_arrays, TExp Int64
size_x, TExp Int64
size_y) <-
      PrimType
-> MemLoc
-> MemLoc
-> Maybe
     (TExp Int64, TExp Int64, TExp Int64, TExp Int64, TExp Int64)
isMapTransposeCopy PrimType
bt MemLoc
destloc MemLoc
srcloc = do
    Name
fname <- PrimType -> CallKernelGen Name
mapTransposeForType PrimType
bt
    HostCode -> CallKernelGen ()
forall op rep r. Code op -> ImpM rep r op ()
emit (HostCode -> CallKernelGen ()) -> HostCode -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$
      [VName] -> Name -> [Arg] -> HostCode
forall a. [VName] -> Name -> [Arg] -> Code a
Imp.Call
        []
        Name
fname
        [ VName -> Arg
Imp.MemArg VName
destmem,
          Exp -> Arg
Imp.ExpArg (Exp -> Arg) -> Exp -> Arg
forall a b. (a -> b) -> a -> b
$ TExp Int64 -> Exp
forall t v. TPrimExp t v -> PrimExp v
untyped TExp Int64
destoffset,
          VName -> Arg
Imp.MemArg VName
srcmem,
          Exp -> Arg
Imp.ExpArg (Exp -> Arg) -> Exp -> Arg
forall a b. (a -> b) -> a -> b
$ TExp Int64 -> Exp
forall t v. TPrimExp t v -> PrimExp v
untyped TExp Int64
srcoffset,
          Exp -> Arg
Imp.ExpArg (Exp -> Arg) -> Exp -> Arg
forall a b. (a -> b) -> a -> b
$ TExp Int64 -> Exp
forall t v. TPrimExp t v -> PrimExp v
untyped TExp Int64
num_arrays,
          Exp -> Arg
Imp.ExpArg (Exp -> Arg) -> Exp -> Arg
forall a b. (a -> b) -> a -> b
$ TExp Int64 -> Exp
forall t v. TPrimExp t v -> PrimExp v
untyped TExp Int64
size_x,
          Exp -> Arg
Imp.ExpArg (Exp -> Arg) -> Exp -> Arg
forall a b. (a -> b) -> a -> b
$ TExp Int64 -> Exp
forall t v. TPrimExp t v -> PrimExp v
untyped TExp Int64
size_y
        ]
  | TExp Int64
bt_size <- PrimType -> TExp Int64
forall a. Num a => PrimType -> a
primByteSize PrimType
bt,
    Just TExp Int64
destoffset <- IxFun (TExp Int64) -> TExp Int64 -> Maybe (TExp Int64)
forall num.
(Eq num, IntegralExp num) =>
IxFun num -> num -> Maybe num
IxFun.linearWithOffset IxFun (TExp Int64)
destIxFun TExp Int64
bt_size,
    Just TExp Int64
srcoffset <- IxFun (TExp Int64) -> TExp Int64 -> Maybe (TExp Int64)
forall num.
(Eq num, IntegralExp num) =>
IxFun num -> num -> Maybe num
IxFun.linearWithOffset IxFun (TExp Int64)
srcIxFun TExp Int64
bt_size = do
    let num_elems :: Count Elements (TExp Int64)
num_elems = TExp Int64 -> Count Elements (TExp Int64)
forall a. a -> Count Elements a
Imp.elements (TExp Int64 -> Count Elements (TExp Int64))
-> TExp Int64 -> Count Elements (TExp Int64)
forall a b. (a -> b) -> a -> b
$ [TExp Int64] -> TExp Int64
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
product ([TExp Int64] -> TExp Int64) -> [TExp Int64] -> TExp Int64
forall a b. (a -> b) -> a -> b
$ (SubExp -> TExp Int64) -> [SubExp] -> [TExp Int64]
forall a b. (a -> b) -> [a] -> [b]
map SubExp -> TExp Int64
forall a. ToExp a => a -> TExp Int64
toInt64Exp [SubExp]
srcshape
    Space
srcspace <- MemEntry -> Space
entryMemSpace (MemEntry -> Space)
-> ImpM GPUMem HostEnv HostOp MemEntry
-> ImpM GPUMem HostEnv HostOp Space
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VName -> ImpM GPUMem HostEnv HostOp MemEntry
forall rep r op. VName -> ImpM rep r op MemEntry
lookupMemory VName
srcmem
    Space
destspace <- MemEntry -> Space
entryMemSpace (MemEntry -> Space)
-> ImpM GPUMem HostEnv HostOp MemEntry
-> ImpM GPUMem HostEnv HostOp Space
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VName -> ImpM GPUMem HostEnv HostOp MemEntry
forall rep r op. VName -> ImpM rep r op MemEntry
lookupMemory VName
destmem
    HostCode -> CallKernelGen ()
forall op rep r. Code op -> ImpM rep r op ()
emit (HostCode -> CallKernelGen ()) -> HostCode -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$
      VName
-> Count Bytes (TExp Int64)
-> Space
-> VName
-> Count Bytes (TExp Int64)
-> Space
-> Count Bytes (TExp Int64)
-> HostCode
forall a.
VName
-> Count Bytes (TExp Int64)
-> Space
-> VName
-> Count Bytes (TExp Int64)
-> Space
-> Count Bytes (TExp Int64)
-> Code a
Imp.Copy
        VName
destmem
        (TExp Int64 -> Count Bytes (TExp Int64)
forall a. a -> Count Bytes a
bytes (TExp Int64 -> Count Bytes (TExp Int64))
-> TExp Int64 -> Count Bytes (TExp Int64)
forall a b. (a -> b) -> a -> b
$ TExp Int64 -> TExp Int64
forall t v. IntExp t => TPrimExp t v -> TPrimExp Int64 v
sExt64 TExp Int64
destoffset)
        Space
destspace
        VName
srcmem
        (TExp Int64 -> Count Bytes (TExp Int64)
forall a. a -> Count Bytes a
bytes (TExp Int64 -> Count Bytes (TExp Int64))
-> TExp Int64 -> Count Bytes (TExp Int64)
forall a b. (a -> b) -> a -> b
$ TExp Int64 -> TExp Int64
forall t v. IntExp t => TPrimExp t v -> TPrimExp Int64 v
sExt64 TExp Int64
srcoffset)
        Space
srcspace
        (Count Bytes (TExp Int64) -> HostCode)
-> Count Bytes (TExp Int64) -> HostCode
forall a b. (a -> b) -> a -> b
$ Count Elements (TExp Int64)
num_elems Count Elements (TExp Int64) -> PrimType -> Count Bytes (TExp Int64)
`Imp.withElemType` PrimType
bt
  | Bool
otherwise = CopyCompiler GPUMem HostEnv HostOp
sCopy PrimType
bt MemLoc
destloc MemLoc
srcloc

mapTransposeForType :: PrimType -> CallKernelGen Name
mapTransposeForType :: PrimType -> CallKernelGen Name
mapTransposeForType PrimType
bt = do
  let fname :: Name
fname = SpaceId -> Name
nameFromString (SpaceId -> Name) -> SpaceId -> Name
forall a b. (a -> b) -> a -> b
$ SpaceId
"builtin#" SpaceId -> SpaceId -> SpaceId
forall a. Semigroup a => a -> a -> a
<> PrimType -> SpaceId
mapTransposeName PrimType
bt

  Bool
exists <- Name -> ImpM GPUMem HostEnv HostOp Bool
forall rep r op. Name -> ImpM rep r op Bool
hasFunction Name
fname
  Bool -> CallKernelGen () -> CallKernelGen ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
exists (CallKernelGen () -> CallKernelGen ())
-> CallKernelGen () -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ Name -> Function HostOp -> CallKernelGen ()
forall op rep r. Name -> Function op -> ImpM rep r op ()
emitFunction Name
fname (Function HostOp -> CallKernelGen ())
-> Function HostOp -> CallKernelGen ()
forall a b. (a -> b) -> a -> b
$ PrimType -> Function HostOp
mapTransposeFunction PrimType
bt

  Name -> CallKernelGen Name
forall (m :: * -> *) a. Monad m => a -> m a
return Name
fname

mapTransposeName :: PrimType -> String
mapTransposeName :: PrimType -> SpaceId
mapTransposeName PrimType
bt = SpaceId
"gpu_map_transpose_" SpaceId -> SpaceId -> SpaceId
forall a. [a] -> [a] -> [a]
++ PrimType -> SpaceId
forall a. Pretty a => a -> SpaceId
pretty PrimType
bt

mapTransposeFunction :: PrimType -> Imp.Function Imp.HostOp
mapTransposeFunction :: PrimType -> Function HostOp
mapTransposeFunction PrimType
bt =
  Maybe Name
-> [Param]
-> [Param]
-> HostCode
-> [ExternalValue]
-> [(Name, ExternalValue)]
-> Function HostOp
forall a.
Maybe Name
-> [Param]
-> [Param]
-> Code a
-> [ExternalValue]
-> [(Name, ExternalValue)]
-> FunctionT a
Imp.Function Maybe Name
forall a. Maybe a
Nothing [] [Param]
params HostCode
transpose_code [] []
  where
    params :: [Param]
params =
      [ VName -> Param
memparam VName
destmem,
        VName -> Param
intparam VName
destoffset,
        VName -> Param
memparam VName
srcmem,
        VName -> Param
intparam VName
srcoffset,
        VName -> Param
intparam VName
num_arrays,
        VName -> Param
intparam VName
x,
        VName -> Param
intparam VName
y
      ]

    space :: Space
space = SpaceId -> Space
Space SpaceId
"device"
    memparam :: VName -> Param
memparam VName
v = VName -> Space -> Param
Imp.MemParam VName
v Space
space
    intparam :: VName -> Param
intparam VName
v = VName -> PrimType -> Param
Imp.ScalarParam VName
v (PrimType -> Param) -> PrimType -> Param
forall a b. (a -> b) -> a -> b
$ IntType -> PrimType
IntType IntType
Int32

    [ VName
destmem,
      VName
destoffset,
      VName
srcmem,
      VName
srcoffset,
      VName
num_arrays,
      VName
x,
      VName
y,
      VName
mulx,
      VName
muly,
      VName
block
      ] =
        (SpaceId -> Int -> VName) -> [SpaceId] -> [Int] -> [VName]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith
          (Name -> Int -> VName
VName (Name -> Int -> VName)
-> (SpaceId -> Name) -> SpaceId -> Int -> VName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SpaceId -> Name
nameFromString)
          [ SpaceId
"destmem",
            SpaceId
"destoffset",
            SpaceId
"srcmem",
            SpaceId
"srcoffset",
            SpaceId
"num_arrays",
            SpaceId
"x_elems",
            SpaceId
"y_elems",
            -- The following is only used for low width/height
            -- transpose kernels
            SpaceId
"mulx",
            SpaceId
"muly",
            SpaceId
"block"
          ]
          [Int
0 ..]

    block_dim_int :: Integer
block_dim_int = Integer
16

    block_dim :: IntegralExp a => a
    block_dim :: a
block_dim = a
16

    -- When an input array has either width==1 or height==1, performing a
    -- transpose will be the same as performing a copy.
    can_use_copy :: TExp Bool
can_use_copy =
      let onearr :: TExp Bool
onearr = VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
num_arrays TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.==. TPrimExp Int32 VName
1
          height_is_one :: TExp Bool
height_is_one = VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
y TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.==. TPrimExp Int32 VName
1
          width_is_one :: TExp Bool
width_is_one = VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
x TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.==. TPrimExp Int32 VName
1
       in TExp Bool
onearr TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
.&&. (TExp Bool
width_is_one TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
.||. TExp Bool
height_is_one)

    transpose_code :: HostCode
transpose_code =
      TExp Bool -> HostCode -> HostCode -> HostCode
forall a. TExp Bool -> Code a -> Code a -> Code a
Imp.If TExp Bool
input_is_empty HostCode
forall a. Monoid a => a
mempty (HostCode -> HostCode) -> HostCode -> HostCode
forall a b. (a -> b) -> a -> b
$
        [HostCode] -> HostCode
forall a. Monoid a => [a] -> a
mconcat
          [ VName -> Volatility -> PrimType -> HostCode
forall a. VName -> Volatility -> PrimType -> Code a
Imp.DeclareScalar VName
muly Volatility
Imp.Nonvolatile (IntType -> PrimType
IntType IntType
Int32),
            VName -> Exp -> HostCode
forall a. VName -> Exp -> Code a
Imp.SetScalar VName
muly (Exp -> HostCode) -> Exp -> HostCode
forall a b. (a -> b) -> a -> b
$ TPrimExp Int32 VName -> Exp
forall t v. TPrimExp t v -> PrimExp v
untyped (TPrimExp Int32 VName -> Exp) -> TPrimExp Int32 VName -> Exp
forall a b. (a -> b) -> a -> b
$ TPrimExp Int32 VName
forall a. IntegralExp a => a
block_dim TPrimExp Int32 VName
-> TPrimExp Int32 VName -> TPrimExp Int32 VName
forall e. IntegralExp e => e -> e -> e
`quot` VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
x,
            VName -> Volatility -> PrimType -> HostCode
forall a. VName -> Volatility -> PrimType -> Code a
Imp.DeclareScalar VName
mulx Volatility
Imp.Nonvolatile (IntType -> PrimType
IntType IntType
Int32),
            VName -> Exp -> HostCode
forall a. VName -> Exp -> Code a
Imp.SetScalar VName
mulx (Exp -> HostCode) -> Exp -> HostCode
forall a b. (a -> b) -> a -> b
$ TPrimExp Int32 VName -> Exp
forall t v. TPrimExp t v -> PrimExp v
untyped (TPrimExp Int32 VName -> Exp) -> TPrimExp Int32 VName -> Exp
forall a b. (a -> b) -> a -> b
$ TPrimExp Int32 VName
forall a. IntegralExp a => a
block_dim TPrimExp Int32 VName
-> TPrimExp Int32 VName -> TPrimExp Int32 VName
forall e. IntegralExp e => e -> e -> e
`quot` VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
y,
            TExp Bool -> HostCode -> HostCode -> HostCode
forall a. TExp Bool -> Code a -> Code a -> Code a
Imp.If TExp Bool
can_use_copy HostCode
copy_code (HostCode -> HostCode) -> HostCode -> HostCode
forall a b. (a -> b) -> a -> b
$
              TExp Bool -> HostCode -> HostCode -> HostCode
forall a. TExp Bool -> Code a -> Code a -> Code a
Imp.If TExp Bool
should_use_lowwidth (TransposeType -> HostCode
callTransposeKernel TransposeType
TransposeLowWidth) (HostCode -> HostCode) -> HostCode -> HostCode
forall a b. (a -> b) -> a -> b
$
                TExp Bool -> HostCode -> HostCode -> HostCode
forall a. TExp Bool -> Code a -> Code a -> Code a
Imp.If TExp Bool
should_use_lowheight (TransposeType -> HostCode
callTransposeKernel TransposeType
TransposeLowHeight) (HostCode -> HostCode) -> HostCode -> HostCode
forall a b. (a -> b) -> a -> b
$
                  TExp Bool -> HostCode -> HostCode -> HostCode
forall a. TExp Bool -> Code a -> Code a -> Code a
Imp.If TExp Bool
should_use_small (TransposeType -> HostCode
callTransposeKernel TransposeType
TransposeSmall) (HostCode -> HostCode) -> HostCode -> HostCode
forall a b. (a -> b) -> a -> b
$
                    TransposeType -> HostCode
callTransposeKernel TransposeType
TransposeNormal
          ]

    input_is_empty :: TExp Bool
input_is_empty =
      VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
num_arrays TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.==. TPrimExp Int32 VName
0 TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
.||. VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
x TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.==. TPrimExp Int32 VName
0 TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
.||. VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
y TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.==. TPrimExp Int32 VName
0

    should_use_small :: TExp Bool
should_use_small =
      VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
x TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.<=. (TPrimExp Int32 VName
forall a. IntegralExp a => a
block_dim TPrimExp Int32 VName
-> TPrimExp Int32 VName -> TPrimExp Int32 VName
forall e. IntegralExp e => e -> e -> e
`quot` TPrimExp Int32 VName
2)
        TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
.&&. VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
y TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.<=. (TPrimExp Int32 VName
forall a. IntegralExp a => a
block_dim TPrimExp Int32 VName
-> TPrimExp Int32 VName -> TPrimExp Int32 VName
forall e. IntegralExp e => e -> e -> e
`quot` TPrimExp Int32 VName
2)

    should_use_lowwidth :: TExp Bool
should_use_lowwidth =
      VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
x TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.<=. (TPrimExp Int32 VName
forall a. IntegralExp a => a
block_dim TPrimExp Int32 VName
-> TPrimExp Int32 VName -> TPrimExp Int32 VName
forall e. IntegralExp e => e -> e -> e
`quot` TPrimExp Int32 VName
2)
        TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
.&&. TPrimExp Int32 VName
forall a. IntegralExp a => a
block_dim TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.<. VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
y

    should_use_lowheight :: TExp Bool
should_use_lowheight =
      VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
y TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.<=. (TPrimExp Int32 VName
forall a. IntegralExp a => a
block_dim TPrimExp Int32 VName
-> TPrimExp Int32 VName -> TPrimExp Int32 VName
forall e. IntegralExp e => e -> e -> e
`quot` TPrimExp Int32 VName
2)
        TExp Bool -> TExp Bool -> TExp Bool
forall v. TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
.&&. TPrimExp Int32 VName
forall a. IntegralExp a => a
block_dim TPrimExp Int32 VName -> TPrimExp Int32 VName -> TExp Bool
forall t v. TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
.<. VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
x

    copy_code :: HostCode
copy_code =
      let num_bytes :: TExp Int64
num_bytes = TPrimExp Int32 VName -> TExp Int64
forall t v. IntExp t => TPrimExp t v -> TPrimExp Int64 v
sExt64 (TPrimExp Int32 VName -> TExp Int64)
-> TPrimExp Int32 VName -> TExp Int64
forall a b. (a -> b) -> a -> b
$ VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
x TPrimExp Int32 VName
-> TPrimExp Int32 VName -> TPrimExp Int32 VName
forall a. Num a => a -> a -> a
* VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
y TPrimExp Int32 VName
-> TPrimExp Int32 VName -> TPrimExp Int32 VName
forall a. Num a => a -> a -> a
* PrimType -> TPrimExp Int32 VName
forall a. Num a => PrimType -> a
primByteSize PrimType
bt
       in VName
-> Count Bytes (TExp Int64)
-> Space
-> VName
-> Count Bytes (TExp Int64)
-> Space
-> Count Bytes (TExp Int64)
-> HostCode
forall a.
VName
-> Count Bytes (TExp Int64)
-> Space
-> VName
-> Count Bytes (TExp Int64)
-> Space
-> Count Bytes (TExp Int64)
-> Code a
Imp.Copy
            VName
destmem
            (TExp Int64 -> Count Bytes (TExp Int64)
forall u e. e -> Count u e
Imp.Count (TExp Int64 -> Count Bytes (TExp Int64))
-> TExp Int64 -> Count Bytes (TExp Int64)
forall a b. (a -> b) -> a -> b
$ TPrimExp Int32 VName -> TExp Int64
forall t v. IntExp t => TPrimExp t v -> TPrimExp Int64 v
sExt64 (TPrimExp Int32 VName -> TExp Int64)
-> TPrimExp Int32 VName -> TExp Int64
forall a b. (a -> b) -> a -> b
$ VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
destoffset)
            Space
space
            VName
srcmem
            (TExp Int64 -> Count Bytes (TExp Int64)
forall u e. e -> Count u e
Imp.Count (TExp Int64 -> Count Bytes (TExp Int64))
-> TExp Int64 -> Count Bytes (TExp Int64)
forall a b. (a -> b) -> a -> b
$ TPrimExp Int32 VName -> TExp Int64
forall t v. IntExp t => TPrimExp t v -> TPrimExp Int64 v
sExt64 (TPrimExp Int32 VName -> TExp Int64)
-> TPrimExp Int32 VName -> TExp Int64
forall a b. (a -> b) -> a -> b
$ VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
srcoffset)
            Space
space
            (TExp Int64 -> Count Bytes (TExp Int64)
forall u e. e -> Count u e
Imp.Count TExp Int64
num_bytes)

    callTransposeKernel :: TransposeType -> HostCode
callTransposeKernel =
      HostOp -> HostCode
forall a. a -> Code a
Imp.Op (HostOp -> HostCode)
-> (TransposeType -> HostOp) -> TransposeType -> HostCode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Kernel -> HostOp
Imp.CallKernel
        (Kernel -> HostOp)
-> (TransposeType -> Kernel) -> TransposeType -> HostOp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SpaceId
-> Integer -> TransposeArgs -> PrimType -> TransposeType -> Kernel
mapTransposeKernel
          (PrimType -> SpaceId
mapTransposeName PrimType
bt)
          Integer
block_dim_int
          ( VName
destmem,
            VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
destoffset,
            VName
srcmem,
            VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
srcoffset,
            VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
x,
            VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
y,
            VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
mulx,
            VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
muly,
            VName -> TPrimExp Int32 VName
forall a. a -> TPrimExp Int32 a
Imp.le32 VName
num_arrays,
            VName
block
          )
          PrimType
bt