packages feed

futhark 0.21.4 → 0.21.5

raw patch · 28 files changed

+650/−298 lines, 28 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Futhark.CodeGen.ImpGen.GPU.Base: groupLoop :: TExp Int64 -> (TExp Int64 -> InKernelGen ()) -> InKernelGen ()
- Futhark.CodeGen.ImpGen.GPU.Base: precomputeSegOpIDs :: Stms GPUMem -> InKernelGen a -> InKernelGen a
+ Futhark.Analysis.PrimExp: expFloatType :: FloatExp t => TPrimExp t v -> FloatType
+ Futhark.Analysis.PrimExp: expIntType :: IntExp t => TPrimExp t v -> IntType
+ Futhark.Analysis.PrimExp: sExtAs :: (IntExp to, IntExp from) => TPrimExp from v -> TPrimExp to v -> TPrimExp to v
+ Futhark.CodeGen.ImpCode.GPU: expFloatType :: FloatExp t => TPrimExp t v -> FloatType
+ Futhark.CodeGen.ImpCode.GPU: expIntType :: IntExp t => TPrimExp t v -> IntType
+ Futhark.CodeGen.ImpCode.GPU: sExtAs :: (IntExp to, IntExp from) => TPrimExp from v -> TPrimExp to v -> TPrimExp to v
+ Futhark.CodeGen.ImpCode.Multicore: expFloatType :: FloatExp t => TPrimExp t v -> FloatType
+ Futhark.CodeGen.ImpCode.Multicore: expIntType :: IntExp t => TPrimExp t v -> IntType
+ Futhark.CodeGen.ImpCode.Multicore: sExtAs :: (IntExp to, IntExp from) => TPrimExp from v -> TPrimExp to v -> TPrimExp to v
+ Futhark.CodeGen.ImpCode.OpenCL: expFloatType :: FloatExp t => TPrimExp t v -> FloatType
+ Futhark.CodeGen.ImpCode.OpenCL: expIntType :: IntExp t => TPrimExp t v -> IntType
+ Futhark.CodeGen.ImpCode.OpenCL: sExtAs :: (IntExp to, IntExp from) => TPrimExp from v -> TPrimExp to v -> TPrimExp to v
+ Futhark.CodeGen.ImpCode.Sequential: expFloatType :: FloatExp t => TPrimExp t v -> FloatType
+ Futhark.CodeGen.ImpCode.Sequential: expIntType :: IntExp t => TPrimExp t v -> IntType
+ Futhark.CodeGen.ImpCode.Sequential: sExtAs :: (IntExp to, IntExp from) => TPrimExp from v -> TPrimExp to v -> TPrimExp to v
+ Futhark.CodeGen.ImpGen.GPU.Base: [kernelChunkItersMap] :: KernelConstants -> Map [SubExp] (TExp Int32)
+ Futhark.CodeGen.ImpGen.GPU.Base: data Precomputed
+ Futhark.CodeGen.ImpGen.GPU.Base: precomputeConstants :: Count GroupSize (TExp Int64) -> Stms GPUMem -> CallKernelGen Precomputed
+ Futhark.CodeGen.ImpGen.GPU.Base: precomputedConstants :: Precomputed -> InKernelGen a -> InKernelGen a
+ Futhark.CodeGen.RTS.C: errorsH :: Text
+ Futhark.IR.SegOp: SegSeqDims :: [Int] -> SegSeqDims
+ Futhark.IR.SegOp: [segSeqDims] :: SegSeqDims -> [Int]
+ Futhark.IR.SegOp: instance GHC.Classes.Eq Futhark.IR.SegOp.SegSeqDims
+ Futhark.IR.SegOp: instance GHC.Classes.Ord Futhark.IR.SegOp.SegSeqDims
+ Futhark.IR.SegOp: instance GHC.Show.Show Futhark.IR.SegOp.SegSeqDims
+ Futhark.IR.SegOp: newtype SegSeqDims
+ Futhark.Optimise.TileLoops.Shared: TileFull :: TileKind
+ Futhark.Optimise.TileLoops.Shared: TilePartial :: TileKind
+ Futhark.Optimise.TileLoops.Shared: data TileKind
- Futhark.CodeGen.ImpGen.GPU.Base: KernelConstants :: TExp Int32 -> TExp Int32 -> TExp Int32 -> VName -> VName -> VName -> TExp Int64 -> TExp Int64 -> TExp Int32 -> TExp Int32 -> TExp Bool -> Map [SubExp] [TExp Int32] -> KernelConstants
+ Futhark.CodeGen.ImpGen.GPU.Base: KernelConstants :: TExp Int32 -> TExp Int32 -> TExp Int32 -> VName -> VName -> VName -> TExp Int64 -> TExp Int64 -> TExp Int32 -> TExp Int32 -> TExp Bool -> Map [SubExp] [TExp Int32] -> Map [SubExp] (TExp Int32) -> KernelConstants
- Futhark.CodeGen.ImpGen.GPU.Base: groupCoverSpace :: [TExp Int64] -> ([TExp Int64] -> InKernelGen ()) -> InKernelGen ()
+ Futhark.CodeGen.ImpGen.GPU.Base: groupCoverSpace :: IntExp t => [TExp t] -> ([TExp t] -> InKernelGen ()) -> InKernelGen ()
- Futhark.IR.SegOp: SegNoVirtFull :: SegVirt
+ Futhark.IR.SegOp: SegNoVirtFull :: SegSeqDims -> SegVirt
- Futhark.Optimise.TileLoops.Shared: segScatter2D :: String -> SubExp -> VName -> SegLevel -> (SubExp, SubExp) -> ((VName, VName) -> Builder GPU (SubExp, SubExp)) -> Builder GPU [VName]
+ Futhark.Optimise.TileLoops.Shared: segScatter2D :: String -> SubExp -> VName -> SegLevel -> [SubExp] -> (SubExp, SubExp) -> ([VName] -> (VName, VName) -> Builder GPU (SubExp, SubExp)) -> Builder GPU VName

Files

docs/c-api.rst view
@@ -13,9 +13,9 @@ most other operations, such as calling Futhark functions.  Most functions that can fail return an integer: 0 on success and a-non-zero value on error.  Others return a ``NULL`` pointer.  Use-:c:func:`futhark_context_get_error` to get a (possibly) more precise-error message.+non-zero value on error, as documented below.  Others return a+``NULL`` pointer.  Use :c:func:`futhark_context_get_error` to get a+(possibly) more precise error message.  .. c:macro:: FUTHARK_BACKEND_foo @@ -23,6 +23,29 @@    generate the code; e.g. ``c``, ``opencl``, or ``cuda``.  This can    be used for conditional compilation of code that only works with    specific backends.++Error codes+-----------++Most errors are result in a not otherwise specified nonzero return+code, but a few classes of errors have distinct error codes.++.. c:macro:: FUTHARK_SUCCESS++   Defined as ``0``.  Returned in case of success.++.. c:macro:: FUTHARK_PROGRAM_ERROR++   Defined as ``2``.  Returned when the program fails due to+   out-of-bounds, an invalid size coercion, invalid entry point+   arguments, or similar misuse.++.. c:macro:: FUTHARK_OUT_OF_MEMORY++   Defined as ``3``.  Returned when the program fails to allocate+   memory.  This is (somewhat) reliable only for GPU memory - due to+   overcommit and other VM tricks, you should not expect running out+   of main memory to be reported gracefully.  Configuration -------------
docs/conf.py view
@@ -118,7 +118,7 @@  lexers['futhark'] = FutharkLexer() -highlight_language = 'futhark'+highlight_language = 'text'  # A list of ignored prefixes for module index sorting. #modindex_common_prefix = []
docs/performance.rst view
@@ -45,14 +45,18 @@ The ``scan`` and ``reduce`` SOACs are rather inefficient when their operators are on arrays.  If possible, use tuples instead (see :ref:`performance-small-arrays`).  The one exception is when the-operator is a ``map2`` or equivalent.  Example::+operator is a ``map2`` or equivalent.  Example: +.. code-block:: futhark+   reduce (map2 (+)) (replicate n 0) xss  Such "vectorised" operators are typically handled quite efficiently. Although to be on the safe side, you can rewrite the above by-interchanging the ``reduce`` and ``map``::+interchanging the ``reduce`` and ``map``: +.. code-block:: futhark+   map (reduce (+) 0) (transpose xss)  Avoid reductions over tiny arrays, e.g. ``reduce (+) 0 [x,y,z]``.  In@@ -85,8 +89,10 @@  Futhark allows nested parallelism, understood as a parallel construct used inside some other parallel construct.  The simplest example is-nested SOACs.  Example::+nested SOACs.  Example: +.. code-block:: futhark+   map (\xs -> reduce (+) 0 xs) xss  Nested parallelism is allowed and encouraged, but its compilation to@@ -126,8 +132,10 @@ The main restriction is that the GPU backends can only handle *regular* nested parallelism, meaning that the sizes of inner parallel dimensions are invariant to the outer parallel dimensions.  For-example, this expression contains *irregular* nested parallelism::+example, this expression contains *irregular* nested parallelism: +.. code-block:: futhark+   map (\i -> reduce (+) 0 (iota i)) is  This is because the size of the nested parallel construct is ``i``,@@ -182,8 +190,8 @@ Sum Types ~~~~~~~~~ -A starting point, a sum type is turned into a tuple containing all the-payload components in order, prefixed with an `i8` tag to identify the+A sum type value is represented as a tuple containing all the payload+components in order, prefixed with an `i8` tag to identify the constructor.  For example,  .. code-block:: futhark@@ -345,8 +353,10 @@  *Horizontal fusion* occurs when two SOACs take as input the same array, but are not themselves in a producer-consumer relationship.-Example::+Example: +.. code-block:: futhark+    (map f xs, map g xs)  Such cases are fused into a single operation that traverses ``xs``@@ -418,7 +428,9 @@ performance.  In many cases this is currently unavoidable, but sometimes the program can be rewritten such that instead of calling the same function in multiple places, it is called in a single place,-in a loop.  E.g. we might rewrite ``f x (f y (f z v))`` as::+in a loop.  E.g. we might rewrite ``f x (f y (f z v))`` as:++.. code-block:: futhark    loop acc = v for a in [z,y,x] do     f a acc
docs/server-protocol.rst view
@@ -16,7 +16,7 @@ server executables.  A server executable is started like any other executable, and supports-most of the same command line options.+most of the same command line options (:ref:`executable-options`).  Basics ------@@ -33,8 +33,8 @@ command fails, the server will print ``%%% FAILURE`` followed by the error message, and then ``%%% OK`` when it is ready for more input. Some output may also precede ``%%% FAILURE``, e.g. logging statements-that occured before failure was detected.  Fatal errors (that lead to-server shutdown) may be printed to stderr.+that occured before failure was detected.  Fatal errors that lead to+server shutdown may be printed to stderr.  Variables ---------
docs/usage.rst view
@@ -333,7 +333,7 @@  Return types follow the rules, with one addition: -* If the return type is an *m*-element tuple, then the the function+* If the return type is an *m*-element tuple, then the function   returns *m* values, mapped according to the rules above (but not   including this one - nested tuples are not mapped directly).  This   rule does not apply when the entry point has been given a return
futhark.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name:           futhark-version:        0.21.4+version:        0.21.5 synopsis:       An optimising compiler for a functional, array-oriented language.  description:    Futhark is a small programming language designed to be compiled to
rts/c/cuda.h view
@@ -4,8 +4,9 @@ #define CUDA_SUCCEED_NONFATAL(x) cuda_api_succeed_nonfatal(x, #x, __FILE__, __LINE__) #define NVRTC_SUCCEED_FATAL(x) nvrtc_api_succeed_fatal(x, #x, __FILE__, __LINE__) #define NVRTC_SUCCEED_NONFATAL(x) nvrtc_api_succeed_nonfatal(x, #x, __FILE__, __LINE__)--#define SUCCEED_OR_RETURN(serror) {               \+// Take care not to override an existing error.+#define CUDA_SUCCEED_OR_RETURN(e) {               \+    char *serror = CUDA_SUCCEED_NONFATAL(e);      \     if (serror) {                                 \       if (!ctx->error) {                          \         ctx->error = serror;                      \@@ -15,8 +16,6 @@       }                                           \     }                                             \   }--#define CUDA_SUCCEED_OR_RETURN(e) SUCCEED_OR_RETURN(CUDA_SUCCEED_NONFATAL(e))  // CUDA_SUCCEED_OR_RETURN returns the value of the variable 'bad' in // scope.  By default, it will be this one.  Create a local variable
+ rts/c/errors.h view
@@ -0,0 +1,3 @@+#define FUTHARK_SUCCESS 0+#define FUTHARK_PROGRAM_ERROR 2+#define FUTHARK_OUT_OF_MEMORY 3
src/Futhark/Analysis/PrimExp.hs view
@@ -28,7 +28,7 @@     -- * Construction     module Futhark.IR.Primitive,     NumExp (..),-    IntExp,+    IntExp (..),     FloatExp (..),     sExt,     zExt,@@ -53,6 +53,7 @@     sExt64,     zExt32,     zExt64,+    sExtAs,     fMin64,     fMax64,   )@@ -231,31 +232,37 @@  -- | The class of integer types that can be used for constructing -- 'TPrimExp's.-class NumExp t => IntExp t+class NumExp t => IntExp t where+  -- | The type of an expression, known to be an integer type.+  expIntType :: TPrimExp t v -> IntType  instance NumExp Int8 where   fromInteger' = isInt8 . ValueExp . IntValue . Int8Value . fromInteger   fromBoolExp = isInt8 . ConvOpExp (BToI Int8) . untyped -instance IntExp Int8+instance IntExp Int8 where+  expIntType = const Int8  instance NumExp Int16 where   fromInteger' = isInt16 . ValueExp . IntValue . Int16Value . fromInteger   fromBoolExp = isInt16 . ConvOpExp (BToI Int16) . untyped -instance IntExp Int16+instance IntExp Int16 where+  expIntType = const Int16  instance NumExp Int32 where   fromInteger' = isInt32 . ValueExp . IntValue . Int32Value . fromInteger   fromBoolExp = isInt32 . ConvOpExp (BToI Int32) . untyped -instance IntExp Int32+instance IntExp Int32 where+  expIntType = const Int32  instance NumExp Int64 where   fromInteger' = isInt64 . ValueExp . IntValue . Int64Value . fromInteger   fromBoolExp = isInt64 . ConvOpExp (BToI Int64) . untyped -instance IntExp Int64+instance IntExp Int64 where+  expIntType = const Int64  -- | The class of floating-point types that can be used for -- constructing 'TPrimExp's.@@ -263,6 +270,9 @@   -- | Construct a typed expression from a rational.   fromRational' :: Rational -> TPrimExp t v +  -- | The type of an expression, known to be a floating-point type.+  expFloatType :: TPrimExp t v -> FloatType+ instance NumExp Half where   fromInteger' = isF16 . ValueExp . FloatValue . Float16Value . fromInteger   fromBoolExp = isF16 . ConvOpExp (SIToFP Int16 Float16) . ConvOpExp (BToI Int16) . untyped@@ -277,12 +287,15 @@  instance FloatExp Half where   fromRational' = TPrimExp . ValueExp . FloatValue . Float16Value . fromRational+  expFloatType = const Float16  instance FloatExp Float where   fromRational' = TPrimExp . ValueExp . FloatValue . Float32Value . fromRational+  expFloatType = const Float32  instance FloatExp Double where   fromRational' = TPrimExp . ValueExp . FloatValue . Float64Value . fromRational+  expFloatType = const Float64  instance (NumExp t, Pretty v) => Num (TPrimExp t v) where   TPrimExp x + TPrimExp y@@ -617,6 +630,15 @@ -- | 64-bit float maximum. fMax64 :: TPrimExp Double v -> TPrimExp Double v -> TPrimExp Double v fMax64 x y = TPrimExp $ BinOpExp (FMax Float64) (untyped x) (untyped y)++-- | Convert result of some integer expression to have the same type+-- as another, using sign extension.+sExtAs ::+  (IntExp to, IntExp from) =>+  TPrimExp from v ->+  TPrimExp to v ->+  TPrimExp to v+sExtAs from to = TPrimExp $ sExt (expIntType to) (untyped from)  -- Prettyprinting instances 
src/Futhark/CodeGen/Backends/CCUDA.hs view
@@ -177,7 +177,7 @@  allocateCUDABuffer :: GC.Allocate OpenCL () allocateCUDABuffer mem size tag "device" =-  GC.stm [C.cstm|CUDA_SUCCEED_OR_RETURN(cuda_alloc(&ctx->cuda, (size_t)$exp:size, $exp:tag, &$exp:mem));|]+  GC.stm [C.cstm|ctx->error = CUDA_SUCCEED_NONFATAL(cuda_alloc(&ctx->cuda, (size_t)$exp:size, $exp:tag, &$exp:mem));|] allocateCUDABuffer _ _ _ space =   error $ "Cannot allocate in '" ++ space ++ "' memory space." 
src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs view
@@ -420,6 +420,8 @@       [C.cedecl|void $id:s(struct $id:ctx* ctx) {                                  $stms:free_fields                                  free_constants(ctx);+                                 cuMemFree(ctx->global_failure);+                                 cuMemFree(ctx->global_failure_args);                                  cuda_cleanup(&ctx->cuda);                                  free_lock(&ctx->lock);                                  ctx->cfg->in_use = 0;@@ -458,7 +460,7 @@                       $stm:(failureSwitch failures) -                     return 1;+                     return FUTHARK_PROGRAM_ERROR;                    }                  }                  CUDA_SUCCEED_OR_RETURN(cuCtxPopCurrent(&ctx->cuda.cu_ctx));
src/Futhark/CodeGen/Backends/COpenCL.hs view
@@ -213,7 +213,7 @@  allocateOpenCLBuffer :: GC.Allocate OpenCL () allocateOpenCLBuffer mem size tag "device" =-  GC.stm [C.cstm|OPENCL_SUCCEED_OR_RETURN(opencl_alloc(&ctx->opencl, (size_t)$exp:size, $exp:tag, &$exp:mem));|]+  GC.stm [C.cstm|ctx->error = OPENCL_SUCCEED_NONFATAL(opencl_alloc(&ctx->opencl, (size_t)$exp:size, $exp:tag, &$exp:mem));|] allocateOpenCLBuffer _ _ _ space =   error $ "Cannot allocate in '" ++ space ++ "' space." 
src/Futhark/CodeGen/Backends/COpenCL/Boilerplate.hs view
@@ -450,6 +450,8 @@                                  free_constants(ctx);                                  free_lock(&ctx->lock);                                  $stms:(map releaseKernel (M.toList kernels))+                                 OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->global_failure));+                                 OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->global_failure_args));                                  teardown_opencl(&ctx->opencl);                                  ctx->cfg->in_use = 0;                                  free(ctx);@@ -492,7 +494,7 @@                     $stm:(failureSwitch failures) -                   return 1;+                   return FUTHARK_PROGRAM_ERROR;                  }                  return 0;                }|]
src/Futhark/CodeGen/Backends/GenericC.hs view
@@ -96,7 +96,7 @@ import Futhark.CodeGen.Backends.GenericC.Server (serverDefs) import Futhark.CodeGen.Backends.SimpleRep import Futhark.CodeGen.ImpCode-import Futhark.CodeGen.RTS.C (halfH, lockH, timingH, utilH)+import Futhark.CodeGen.RTS.C (errorsH, halfH, lockH, timingH, utilH) import Futhark.IR.Prop (isBuiltInFunction) import qualified Futhark.Manifest as Manifest import Futhark.MonadFreshNames@@ -258,7 +258,7 @@   items     [C.citems|ctx->error = msgprintf($string:formatstr', $args:formatargs, $string:stacktrace);               $items:free_all_mem-              err = 1;+              err = FUTHARK_PROGRAM_ERROR;               goto cleanup;|]  defCall :: CallCompiler op s@@ -673,12 +673,15 @@   }   int ret = $id:(fatMemUnRef space)(ctx, block, desc); -  ctx->$id:usagename += size;+  if (ret != FUTHARK_SUCCESS) {+    return ret;+  }+   if (ctx->detail_memory) {     fprintf(ctx->log, "Allocating %lld bytes for %s in %s (then allocated: %lld bytes)",             (long long) size,             desc, $string:spacedesc,-            (long long) ctx->$id:usagename);+            (long long) ctx->$id:usagename + size);   }   if (ctx->$id:usagename > ctx->$id:peakname) {     ctx->$id:peakname = ctx->$id:usagename;@@ -690,11 +693,28 @@   }    $items:alloc-  block->references = (int*) malloc(sizeof(int));-  *(block->references) = 1;-  block->size = size;-  block->desc = desc;-  return ret;++  if (ctx->error == NULL) {+    block->references = (int*) malloc(sizeof(int));+    *(block->references) = 1;+    block->size = size;+    block->desc = desc;+    ctx->$id:usagename += size;+    return FUTHARK_SUCCESS;+  } else {+    // We are naively assuming that any memory allocation error is due to OOM.+    // We preserve the original error so that a savvy user can perhaps find+    // glory despite our naiveté.++    char *old_error = ctx->error;+    ctx->error = msgprintf("Failed to allocate memory in %s.\nAttempted allocation: %12lld bytes\nCurrently allocated:  %12lld bytes\n%s",+                           $string:spacedesc,+                           (long long) size,+                           (long long) ctx->$id:usagename,+                           old_error);+    free(old_error);+    return FUTHARK_OUT_OF_MEMORY;+  }   }|]    -- Memory setting - unreference the destination and increase the@@ -1066,7 +1086,7 @@             shapearr = "shape_" ++ show i             dims = [[C.cexp|$id:shapearr[$int:j]|] | j <- [0 .. rank - 1]]             num_elems = cproduct dims-        item [C.citem|typename int64_t $id:shapearr[$int:rank];|]+        item [C.citem|typename int64_t $id:shapearr[$int:rank] = {0};|]         stms $ loadValueHeader sign pt rank [C.cexp|$id:shapearr|] [C.cexp|src|]         item [C.citem|const void* $id:dataptr = src;|]         stm [C.cstm|obj->$id:field = NULL;|]@@ -1543,6 +1563,7 @@ // Miscellaneous $miscdecls #define FUTHARK_BACKEND_$backend+$errorsH  #ifdef __cplusplus }
src/Futhark/CodeGen/Backends/MulticoreC.hs view
@@ -597,7 +597,7 @@         [C.citems|int $id:ftask_err = scheduler_prepare_task(&ctx->scheduler, &$id:ftask_name);                   if ($id:ftask_err != 0) {                     $items:free_all_mem;-                    err = 1;+                    err = $id:ftask_err;                     goto cleanup;                   }|] @@ -665,7 +665,7 @@       [C.citems|int $id:ftask_err = scheduler_execute_task(&ctx->scheduler,                                                            &$id:ftask_name);                if ($id:ftask_err != 0) {-                 err = 1;+                 err = $id:ftask_err;                  goto cleanup;                }|] 
src/Futhark/CodeGen/ImpGen/GPU/Base.hs view
@@ -23,10 +23,11 @@     compileThreadResult,     compileGroupResult,     virtualiseGroups,-    groupLoop,     kernelLoop,     groupCoverSpace,-    precomputeSegOpIDs,+    Precomputed,+    precomputeConstants,+    precomputedConstants,     atomicUpdateLocking,     AtomicBinOp,     Locking (..),@@ -36,12 +37,14 @@ where  import Control.Monad.Except-import Data.List (foldl', zip4)+import Data.Bifunctor+import Data.List (foldl', partition, zip4) import qualified Data.Map.Strict as M import Data.Maybe import qualified Data.Set as S import qualified Futhark.CodeGen.ImpCode.GPU as Imp import Futhark.CodeGen.ImpGen+import Futhark.Construct (fullSliceNum) import Futhark.Error import Futhark.IR.GPUMem import qualified Futhark.IR.Mem.IxFun as IxFun@@ -92,30 +95,64 @@     kernelWaveSize :: Imp.TExp Int32,     kernelThreadActive :: Imp.TExp Bool,     -- | A mapping from dimensions of nested SegOps to already-    -- computed local thread IDs.-    kernelLocalIdMap :: M.Map [SubExp] [Imp.TExp Int32]+    -- computed local thread IDs.  Only valid in non-virtualised case.+    kernelLocalIdMap :: M.Map [SubExp] [Imp.TExp Int32],+    -- | Mapping from dimensions of nested SegOps to how many+    -- iterations the virtualisation loop needs.+    kernelChunkItersMap :: M.Map [SubExp] (Imp.TExp Int32)   } -segOpSizes :: Stms GPUMem -> S.Set [SubExp]+-- | The sizes of nested iteration spaces in the kernel.+type SegOpSizes = S.Set [SubExp]++-- | Find the sizes of nested parallelism in a 'SegOp' body.+segOpSizes :: Stms GPUMem -> SegOpSizes segOpSizes = onStms   where     onStms = foldMap (onExp . stmExp)     onExp (Op (Inner (SegOp op))) =-      S.singleton $ map snd $ unSegSpace $ segSpace op+      case segVirt $ segLevel op of+        SegNoVirtFull seq_dims ->+          S.singleton $ map snd $ snd $ partitionSeqDims seq_dims $ segSpace op+        _ -> S.singleton $ map snd $ unSegSpace $ segSpace op+    onExp (BasicOp (Replicate shape _)) =+      S.singleton $ shapeDims shape     onExp (If _ tbranch fbranch _) =       onStms (bodyStms tbranch) <> onStms (bodyStms fbranch)     onExp (DoLoop _ _ body) =       onStms (bodyStms body)     onExp _ = mempty -precomputeSegOpIDs :: Stms GPUMem -> InKernelGen a -> InKernelGen a-precomputeSegOpIDs stms m = do+-- | Various useful precomputed information.+data Precomputed = Precomputed+  { pcSegOpSizes :: SegOpSizes,+    pcChunkItersMap :: M.Map [SubExp] (Imp.TExp Int32)+  }++-- | Precompute various constants and useful information.+precomputeConstants :: Count GroupSize (Imp.TExp Int64) -> Stms GPUMem -> CallKernelGen Precomputed+precomputeConstants group_size stms = do+  let sizes = segOpSizes stms+  iters_map <- M.fromList <$> mapM mkMap (S.toList sizes)+  pure $ Precomputed sizes iters_map+  where+    mkMap dims = do+      let n = product $ map Imp.pe64 dims+      num_chunks <- dPrimVE "num_chunks" $ sExt32 $ n `divUp` unCount group_size+      pure (dims, num_chunks)++-- | Make use of various precomputed constants.+precomputedConstants :: Precomputed -> InKernelGen a -> InKernelGen a+precomputedConstants pre m = do   ltid <- kernelLocalThreadId . kernelConstants <$> askEnv-  new_ids <- M.fromList <$> mapM (mkMap ltid) (S.toList (segOpSizes stms))+  new_ids <- M.fromList <$> mapM (mkMap ltid) (S.toList (pcSegOpSizes pre))   let f env =         env           { kernelConstants =-              (kernelConstants env) {kernelLocalIdMap = new_ids}+              (kernelConstants env)+                { kernelLocalIdMap = new_ids,+                  kernelChunkItersMap = pcChunkItersMap pre+                }           }   localEnv f m   where@@ -221,24 +258,24 @@     if n == num_threads       then f tid       else do-        -- Compute how many elements this thread is responsible for.-        -- Formula: (n - tid) / num_threads (rounded up).-        let elems_for_this = (n - tid) `divUp` num_threads--        sFor "i" elems_for_this $ \i -> f $ i * num_threads + tid+        num_chunks <- dPrimVE "num_chunks" $ n `divUp` num_threads+        sFor "chunk_i" num_chunks $ \chunk_i -> do+          i <- dPrimVE "i" $ chunk_i * num_threads + tid+          sWhen (i .<. n) $ f i  -- | Assign iterations of a for-loop to threads in the workgroup.  The -- passed-in function is invoked with the (symbolic) iteration.  For -- multidimensional loops, use 'groupCoverSpace'. groupLoop ::-  Imp.TExp Int64 ->-  (Imp.TExp Int64 -> InKernelGen ()) ->+  IntExp t =>+  Imp.TExp t ->+  (Imp.TExp t -> InKernelGen ()) ->   InKernelGen () groupLoop n f = do   constants <- kernelConstants <$> askEnv   kernelLoop-    (sExt64 $ kernelLocalThreadId constants)-    (kernelGroupSize constants)+    (kernelLocalThreadId constants `sExtAs` n)+    (kernelGroupSize constants `sExtAs` n)     n     f @@ -246,12 +283,65 @@ -- all threads in the group participate.  The passed-in function is -- invoked with a (symbolic) point in the index space. groupCoverSpace ::-  [Imp.TExp Int64] ->-  ([Imp.TExp Int64] -> InKernelGen ()) ->+  IntExp t =>+  [Imp.TExp t] ->+  ([Imp.TExp t] -> InKernelGen ()) ->   InKernelGen () groupCoverSpace ds f =   groupLoop (product ds) $ f . unflattenIndex ds +localThreadIDs :: [SubExp] -> InKernelGen [Imp.TExp Int64]+localThreadIDs dims = do+  ltid <- sExt64 . kernelLocalThreadId . kernelConstants <$> askEnv+  let dims' = map toInt64Exp dims+  maybe (dIndexSpace' "ltid" dims' ltid) (pure . map sExt64)+    . M.lookup dims+    . kernelLocalIdMap+    . kernelConstants+    =<< askEnv++partitionSeqDims :: SegSeqDims -> SegSpace -> ([(VName, SubExp)], [(VName, SubExp)])+partitionSeqDims (SegSeqDims seq_is) space =+  bimap (map fst) (map fst) $+    partition ((`elem` seq_is) . snd) (zip (unSegSpace space) [0 ..])++groupCoverSegSpace :: SegVirt -> SegSpace -> InKernelGen () -> InKernelGen ()+groupCoverSegSpace virt space m = do+  let (ltids, dims) = unzip $ unSegSpace space+      dims' = map pe64 dims++  constants <- kernelConstants <$> askEnv+  let group_size = kernelGroupSize constants+  -- Maybe we can statically detect that this is actually a+  -- SegNoVirtFull and generate ever-so-slightly simpler code.+  let virt' = if dims' == [group_size] then SegNoVirtFull (SegSeqDims []) else virt+  case virt' of+    SegVirt -> do+      iters <- M.lookup dims . kernelChunkItersMap . kernelConstants <$> askEnv+      case iters of+        Nothing -> do+          iterations <- dPrimVE "iterations" $ product $ map sExt32 dims'+          groupLoop iterations $ \i -> do+            dIndexSpace (zip ltids dims') $ sExt64 i+            m+        Just num_chunks -> do+          let ltid = kernelLocalThreadId constants+          sFor "chunk_i" num_chunks $ \chunk_i -> do+            i <- dPrimVE "i" $ chunk_i * sExt32 group_size + ltid+            dIndexSpace (zip ltids dims') $ sExt64 i+            sWhen (inBounds (Slice (map (DimFix . le64) ltids)) dims') m+    SegNoVirt -> localOps threadOperations $ do+      zipWithM_ dPrimV_ ltids =<< localThreadIDs dims+      sWhen (isActive $ zip ltids dims) m+    SegNoVirtFull seq_dims -> do+      let ((ltids_seq, dims_seq), (ltids_par, dims_par)) =+            bimap unzip unzip $ partitionSeqDims seq_dims space+      sLoopNest (Shape dims_seq) $ \is_seq -> do+        zipWithM_ dPrimV_ ltids_seq is_seq+        localOps threadOperations $ do+          zipWithM_ dPrimV_ ltids_par =<< localThreadIDs dims_par+          m+ compileGroupExp :: ExpCompiler GPUMem KernelEnv Imp.KernelOp compileGroupExp (Pat [pe]) (BasicOp (Opaque _ se)) =   -- Cannot print in GPU code.@@ -263,9 +353,11 @@ compileGroupExp _ (BasicOp (UpdateAcc acc is vs)) =   updateAcc acc is vs compileGroupExp (Pat [dest]) (BasicOp (Replicate ds se)) = do-  let ds' = map toInt64Exp $ shapeDims ds-  groupCoverSpace ds' $ \is ->-    copyDWIMFix (patElemName dest) is se (drop (shapeRank ds) is)+  flat <- newVName "rep_flat"+  is <- replicateM (shapeRank ds) (newVName "rep_i")+  let is' = map le64 is+  groupCoverSegSpace SegVirt (SegSpace flat $ zip is $ shapeDims ds) $+    copyDWIMFix (patElemName dest) is' se []   sOp $ Imp.Barrier Imp.FenceLocal compileGroupExp (Pat [dest]) (BasicOp (Iota n e s it)) = do   n' <- toExp n@@ -305,21 +397,9 @@ sanityCheckLevel SegGroup {} =   error "compileGroupOp: unexpected group-level SegOp." -localThreadIDs :: [SubExp] -> InKernelGen [Imp.TExp Int64]-localThreadIDs dims = do-  ltid <- sExt64 . kernelLocalThreadId . kernelConstants <$> askEnv-  let dims' = map toInt64Exp dims-  maybe (unflattenIndex dims' ltid) (map sExt64)-    . M.lookup dims-    . kernelLocalIdMap-    . kernelConstants-    <$> askEnv--compileGroupSpace :: SegLevel -> SegSpace -> InKernelGen ()-compileGroupSpace lvl space = do+compileFlatId :: SegLevel -> SegSpace -> InKernelGen ()+compileFlatId lvl space = do   sanityCheckLevel lvl-  let (ltids, dims) = unzip $ unSegSpace space-  zipWithM_ dPrimV_ ltids =<< localThreadIDs dims   ltid <- kernelLocalThreadId . kernelConstants <$> askEnv   dPrimV_ (segFlat space) ltid @@ -359,17 +439,6 @@            return (Just l', f l' (Space "local") local_subhistos) -whenActive :: SegLevel -> SegSpace -> InKernelGen () -> InKernelGen ()-whenActive lvl space m-  | SegNoVirtFull <- segVirt lvl = m-  | otherwise = do-    group_size <- kernelGroupSize . kernelConstants <$> askEnv-    -- XXX: the following check is too naive - we should also handle-    -- the multi-dimensional case.-    if [group_size] == map (toInt64Exp . snd) (unSegSpace space)-      then m-      else sWhen (isActive $ unSegSpace space) m- -- Which fence do we need to protect shared access to this memory space? fenceForSpace :: Space -> Imp.Fence fenceForSpace (Space "local") = Imp.FenceLocal@@ -385,26 +454,144 @@         . entryArrayLoc         =<< lookupArray arr +groupChunkLoop ::+  Imp.TExp Int32 ->+  (Imp.TExp Int32 -> TV Int64 -> InKernelGen ()) ->+  InKernelGen ()+groupChunkLoop w m = do+  constants <- kernelConstants <$> askEnv+  let max_chunk_size = sExt32 $ kernelGroupSize constants+  num_chunks <- dPrimVE "num_chunks" $ w `divUp` max_chunk_size+  sFor "chunk_i" num_chunks $ \chunk_i -> do+    chunk_start <-+      dPrimVE "chunk_start" $ chunk_i * max_chunk_size+    chunk_end <-+      dPrimVE "chunk_end" $ sMin32 w (chunk_start + max_chunk_size)+    chunk_size <-+      dPrimV "chunk_size" $ sExt64 $ chunk_end - chunk_start+    m chunk_start chunk_size++sliceArray :: Imp.TExp Int64 -> TV Int64 -> VName -> ImpM rep r op VName+sliceArray start size arr = do+  MemLoc mem _ ixfun <- entryArrayLoc <$> lookupArray arr+  arr_t <- lookupType arr+  let slice =+        fullSliceNum+          (map Imp.pe64 (arrayDims arr_t))+          [DimSlice start (tvExp size) 1]+  sArray+    (baseString arr ++ "_chunk")+    (elemType arr_t)+    (arrayShape arr_t `setOuterDim` Var (tvVar size))+    mem+    $ IxFun.slice ixfun slice++-- | @flattenArray k flat arr@ flattens the outer @k@ dimensions of+-- @arr@ to @flat@.  (Make sure @flat@ is the sum of those dimensions+-- or you'll have a bad time.)+flattenArray :: Int -> TV Int64 -> VName -> ImpM rep r op VName+flattenArray k flat arr = do+  ArrayEntry arr_loc pt <- lookupArray arr+  let flat_shape = Shape $ Var (tvVar flat) : drop k (memLocShape arr_loc)+  sArray (baseString arr ++ "_flat") pt flat_shape (memLocName arr_loc) $+    IxFun.reshape (memLocIxFun arr_loc) $ map (DimNew . pe64) $ shapeDims flat_shape++-- | @applyLambda lam dests args@ emits code that:+--+-- 1. Binds each parameter of @lam@ to the corresponding element of+--    @args@, interpreted as a (name,slice) pair (as in 'copyDWIM').+--    Use an empty list for a scalar.+--+-- 2. Executes the body of @lam@.+--+-- 3. Binds the 'SubExp's that are the 'Result' of @lam@ to the+-- provided @dest@s, again interpreted as the destination for a+-- 'copyDWIM'.+applyLambda ::+  Mem rep inner =>+  Lambda rep ->+  [(VName, [DimIndex (Imp.TExp Int64)])] ->+  [(SubExp, [DimIndex (Imp.TExp Int64)])] ->+  ImpM rep r op ()+applyLambda lam dests args = do+  dLParams $ lambdaParams lam+  forM_ (zip (lambdaParams lam) args) $ \(p, (arg, arg_slice)) ->+    copyDWIM (paramName p) [] arg arg_slice+  compileStms mempty (bodyStms $ lambdaBody lam) $ do+    let res = map resSubExp $ bodyResult $ lambdaBody lam+    forM_ (zip dests res) $ \((dest, dest_slice), se) ->+      copyDWIM dest dest_slice se []++-- | As 'applyLambda', but first rename the names in the lambda.  This+-- makes it safe to apply it in multiple places.  (It might be safe+-- anyway, but you have to be more careful - use this if you are in+-- doubt.)+applyRenamedLambda ::+  Mem rep inner =>+  Lambda rep ->+  [(VName, [DimIndex (Imp.TExp Int64)])] ->+  [(SubExp, [DimIndex (Imp.TExp Int64)])] ->+  ImpM rep r op ()+applyRenamedLambda lam dests args = do+  lam_renamed <- renameLambda lam+  applyLambda lam_renamed dests args++virtualisedGroupScan ::+  Maybe (Imp.TExp Int32 -> Imp.TExp Int32 -> Imp.TExp Bool) ->+  Imp.TExp Int32 ->+  Lambda GPUMem ->+  [VName] ->+  InKernelGen ()+virtualisedGroupScan seg_flag w lam arrs = do+  groupChunkLoop w $ \chunk_start chunk_size -> do+    constants <- kernelConstants <$> askEnv+    let ltid = kernelLocalThreadId constants+        crosses_segment =+          case seg_flag of+            Nothing -> false+            Just flag_true ->+              flag_true (sExt32 (chunk_start -1)) (sExt32 chunk_start)+    sComment "possibly incorporate carry" $+      sWhen (chunk_start .>. 0 .&&. ltid .==. 0 .&&. bNot crosses_segment) $ do+        carry_idx <- dPrimVE "carry_idx" $ sExt64 chunk_start - 1+        applyRenamedLambda+          lam+          (zip arrs $ repeat [DimFix $ sExt64 chunk_start])+          ( zip (map Var arrs) (repeat [DimFix carry_idx])+              ++ zip (map Var arrs) (repeat [DimFix $ sExt64 chunk_start])+          )++    arrs_chunks <- mapM (sliceArray (sExt64 chunk_start) chunk_size) arrs++    sOp $ Imp.ErrorSync Imp.FenceLocal++    groupScan+      seg_flag+      (sExt64 w)+      (tvExp chunk_size)+      lam+      arrs_chunks+ compileGroupOp :: OpCompiler GPUMem KernelEnv Imp.KernelOp compileGroupOp pat (Alloc size space) =   kernelAlloc pat size space compileGroupOp pat (Inner (SizeOp (SplitSpace o w i elems_per_thread))) =   splitSpace pat o w i elems_per_thread compileGroupOp pat (Inner (SegOp (SegMap lvl space _ body))) = do-  void $ compileGroupSpace lvl space+  compileFlatId lvl space -  whenActive lvl space . localOps threadOperations $+  groupCoverSegSpace (segVirt lvl) space $     compileStms mempty (kernelBodyStms body) $       zipWithM_ (compileThreadResult space) (patElems pat) $         kernelBodyResult body-   sOp $ Imp.ErrorSync Imp.FenceLocal compileGroupOp pat (Inner (SegOp (SegScan lvl space scans _ body))) = do-  compileGroupSpace lvl space+  compileFlatId lvl space+   let (ltids, dims) = unzip $ unSegSpace space       dims' = map toInt64Exp dims -  whenActive lvl space . localOps threadOperations $+  groupCoverSegSpace (segVirt lvl) space $     compileStms mempty (kernelBodyStms body) $       forM_ (zip (patNames pat) $ kernelBodyResult body) $ \(dest, res) ->         copyDWIMFix@@ -424,41 +611,35 @@   -- array of scan elements, so we invent some new flattened arrays   -- here.   dims_flat <- dPrimV "dims_flat" $ product dims'-  let flattened pe = do-        MemLoc mem _ ixfun <--          entryArrayLoc <$> lookupArray (patElemName pe)-        let pe_t = typeOf pe-            arr_dims = Var (tvVar dims_flat) : drop (length dims') (arrayDims pe_t)-        sArray-          (baseString (patElemName pe) ++ "_flat")-          (elemType pe_t)-          (Shape arr_dims)-          mem-          $ IxFun.reshape ixfun $ map (DimNew . pe64) arr_dims--      num_scan_results = sum $ map (length . segBinOpNeutral) scans--  arrs_flat <- mapM flattened $ take num_scan_results $ patElems pat+  let scan = head scans+      num_scan_results = length $ segBinOpNeutral scan+  arrs_flat <-+    mapM (flattenArray (length dims') dims_flat) $+      take num_scan_results $ patNames pat -  forM_ scans $ \scan -> do-    let scan_op = segBinOpLambda scan-    groupScan (Just crossesSegment) (product dims') (product dims') scan_op arrs_flat+  case segVirt lvl of+    SegVirt ->+      virtualisedGroupScan+        (Just crossesSegment)+        (sExt32 $ tvExp dims_flat)+        (segBinOpLambda scan)+        arrs_flat+    _ ->+      groupScan+        (Just crossesSegment)+        (product dims')+        (product dims')+        (segBinOpLambda scan)+        arrs_flat compileGroupOp pat (Inner (SegOp (SegRed lvl space ops _ body))) = do-  compileGroupSpace lvl space--  let (ltids, dims) = unzip $ unSegSpace space-      (red_pes, map_pes) =-        splitAt (segBinOpResults ops) $ patElems pat--      dims' = map toInt64Exp dims+  compileFlatId lvl space +  let dims' = map toInt64Exp dims       mkTempArr t =         sAllocArray "red_arr" (elemType t) (Shape dims <> arrayShape t) $ Space "local"    tmp_arrs <- mapM mkTempArr $ concatMap (lambdaReturnType . segBinOpLambda) ops-  let tmps_for_ops = chunks (map (length . segBinOpNeutral) ops) tmp_arrs--  whenActive lvl space . localOps threadOperations $+  groupCoverSegSpace (segVirt lvl) space $     compileStms mempty (kernelBodyStms body) $ do       let (red_res, map_res) =             splitAt (segBinOpResults ops) $ kernelBodyResult body@@ -468,18 +649,72 @@    sOp $ Imp.ErrorSync Imp.FenceLocal -  case dims' of-    -- Nonsegmented case (or rather, a single segment) - this we can-    -- handle directly with a group-level reduction.-    [dim'] -> do-      forM_ (zip ops tmps_for_ops) $ \(op, tmps) ->-        groupReduce (sExt32 dim') (segBinOpLambda op) tmps+  let tmps_for_ops = chunks (map (length . segBinOpNeutral) ops) tmp_arrs+  case segVirt lvl of+    SegVirt -> virtCase dims' tmps_for_ops+    _ -> nonvirtCase dims' tmps_for_ops+  where+    (ltids, dims) = unzip $ unSegSpace space+    (red_pes, map_pes) = splitAt (segBinOpResults ops) $ patElems pat +    virtCase [dim'] tmps_for_ops = do+      ltid <- kernelLocalThreadId . kernelConstants <$> askEnv+      groupChunkLoop (sExt32 dim') $ \chunk_start chunk_size -> do+        sComment "possibly incorporate carry" $+          sWhen (chunk_start .>. 0 .&&. ltid .==. 0) $+            forM_ (zip ops tmps_for_ops) $ \(op, tmps) ->+              applyRenamedLambda+                (segBinOpLambda op)+                (zip tmps $ repeat [DimFix $ sExt64 chunk_start])+                ( zip (map (Var . patElemName) red_pes) (repeat [])+                    ++ zip (map Var tmps) (repeat [DimFix $ sExt64 chunk_start])+                )++        sOp $ Imp.ErrorSync Imp.FenceLocal++        forM_ (zip ops tmps_for_ops) $ \(op, tmps) -> do+          tmps_chunks <- mapM (sliceArray (sExt64 chunk_start) chunk_size) tmps+          groupReduce (sExt32 (tvExp chunk_size)) (segBinOpLambda op) tmps_chunks++        sOp $ Imp.ErrorSync Imp.FenceLocal++        forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->+          copyDWIMFix (patElemName pe) [] (Var arr) [sExt64 chunk_start]+    virtCase dims' tmps_for_ops = do+      dims_flat <- dPrimV "dims_flat" $ product dims'+      let segment_size = last dims'+          crossesSegment from to =+            (sExt64 to - sExt64 from) .>. (sExt64 to `rem` sExt64 segment_size)++      forM_ (zip ops tmps_for_ops) $ \(op, tmps) -> do+        tmps_flat <- mapM (flattenArray (length dims') dims_flat) tmps+        virtualisedGroupScan+          (Just crossesSegment)+          (sExt32 $ tvExp dims_flat)+          (segBinOpLambda op)+          tmps_flat+       sOp $ Imp.ErrorSync Imp.FenceLocal -      forM_ (zip red_pes tmp_arrs) $ \(pe, arr) ->+      forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->+        copyDWIM+          (patElemName pe)+          []+          (Var arr)+          (map (unitSlice 0) (init dims') ++ [DimFix $ last dims' -1])++      sOp $ Imp.Barrier Imp.FenceLocal++    nonvirtCase [dim'] tmps_for_ops = do+      -- Nonsegmented case (or rather, a single segment) - this we can+      -- handle directly with a group-level reduction.+      forM_ (zip ops tmps_for_ops) $ \(op, tmps) ->+        groupReduce (sExt32 dim') (segBinOpLambda op) tmps+      sOp $ Imp.ErrorSync Imp.FenceLocal+      forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->         copyDWIMFix (patElemName pe) [] (Var arr) [0]-    _ -> do+    --+    nonvirtCase dims' tmps_for_ops = do       -- Segmented intra-group reductions are turned into (regular)       -- segmented scans.  It is possible that this can be done       -- better, but at least this approach is simple.@@ -488,21 +723,12 @@       -- involve copying anything; merely playing with the index       -- function.       dims_flat <- dPrimV "dims_flat" $ product dims'-      let flatten arr = do-            ArrayEntry arr_loc pt <- lookupArray arr-            let flat_shape =-                  Shape $-                    Var (tvVar dims_flat) :-                    drop (length ltids) (memLocShape arr_loc)-            sArray "red_arr_flat" pt flat_shape (memLocName arr_loc) $-              IxFun.iota $ map pe64 $ shapeDims flat_shape-       let segment_size = last dims'           crossesSegment from to =             (sExt64 to - sExt64 from) .>. (sExt64 to `rem` sExt64 segment_size)        forM_ (zip ops tmps_for_ops) $ \(op, tmps) -> do-        tmps_flat <- mapM flatten tmps+        tmps_flat <- mapM (flattenArray (length dims') dims_flat) tmps         groupScan           (Just crossesSegment)           (product dims')@@ -512,7 +738,7 @@        sOp $ Imp.ErrorSync Imp.FenceLocal -      forM_ (zip red_pes tmp_arrs) $ \(pe, arr) ->+      forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->         copyDWIM           (patElemName pe)           []@@ -521,8 +747,8 @@        sOp $ Imp.Barrier Imp.FenceLocal compileGroupOp pat (Inner (SegOp (SegHist lvl space ops _ kbody))) = do-  compileGroupSpace lvl space-  let ltids = map fst $ unSegSpace space+  compileFlatId lvl space+  let (ltids, _dims) = unzip $ unSegSpace space    -- We don't need the red_pes, because it is guaranteed by our type   -- rules that they occupy the same memory as the destinations for@@ -536,7 +762,7 @@   -- Ensure that all locks have been initialised.   sOp $ Imp.Barrier Imp.FenceLocal -  whenActive lvl space . localOps threadOperations $+  groupCoverSegSpace (segVirt lvl) space $     compileStms mempty (kernelBodyStms kbody) $ do       let (red_res, map_res) = splitAt num_red_res $ kernelBodyResult kbody           (red_is, red_vs) = splitAt (length ops) $ map kernelResultSubExp red_res@@ -908,6 +1134,7 @@           (Imp.le32 wave_size)           true           mempty+          mempty    let set_constants = do         dPrim_ global_tid int32@@ -1333,6 +1560,7 @@         (sExt32 (group_size * num_groups))         0         (Imp.le64 thread_gtid .<. kernel_size)+        mempty         mempty,       set_constants     )@@ -1452,11 +1680,11 @@         (sliceMemLoc destloc destslice')         (sliceMemLoc srcloc srcslice')     _ -> do-      groupCoverSpace dims $ \is ->+      groupCoverSpace (map sExt32 dims) $ \is ->         copyElementWise           pt-          (sliceMemLoc destloc (Slice $ map DimFix is))-          (sliceMemLoc srcloc (Slice $ map DimFix is))+          (sliceMemLoc destloc (Slice $ map (DimFix . sExt64) is))+          (sliceMemLoc srcloc (Slice $ map (DimFix . sExt64) is))       sOp $ Imp.Barrier Imp.FenceLocal  threadOperations, groupOperations :: Operations GPUMem KernelEnv Imp.KernelOp
src/Futhark/CodeGen/ImpGen/GPU/SegMap.hs view
@@ -48,10 +48,11 @@             compileStms mempty (kernelBodyStms kbody) $               zipWithM_ (compileThreadResult space) (patElems pat) $                 kernelBodyResult kbody-    SegGroup {} ->+    SegGroup {} -> do+      pc <- precomputeConstants group_size' $ kernelBodyStms kbody       sKernelGroup "segmap_intragroup" num_groups' group_size' (segFlat space) $ do         let virt_num_groups = sExt32 $ product dims'-        precomputeSegOpIDs (kernelBodyStms kbody) $+        precomputedConstants pc $           virtualiseGroups (segVirt lvl) virt_num_groups $ \group_id -> do             dIndexSpace (zip is dims') $ sExt64 group_id 
src/Futhark/CodeGen/ImpGen/Multicore/Base.hs view
@@ -312,29 +312,27 @@   -- Critical section   let try_acquire_lock = do         old <-- (0 :: Imp.TExp Int32)-        sOp $-          Imp.Atomic $-            Imp.AtomicCmpXchg-              int32-              (tvVar old)-              locks'-              (sExt32 <$> locks_offset)-              (tvVar continue)-              (untyped (lockingToLock locking))+        sOp . Imp.Atomic $+          Imp.AtomicCmpXchg+            int32+            (tvVar old)+            locks'+            (sExt32 <$> locks_offset)+            (tvVar continue)+            (untyped (lockingToLock locking))       lock_acquired = tvExp continue       -- Even the releasing is done with an atomic rather than a       -- simple write, for memory coherency reasons.       release_lock = do         old <-- lockingToLock locking-        sOp $-          Imp.Atomic $-            Imp.AtomicCmpXchg-              int32-              (tvVar old)-              locks'-              (sExt32 <$> locks_offset)-              (tvVar continue)-              (untyped (lockingToUnlock locking))+        sOp . Imp.Atomic $+          Imp.AtomicCmpXchg+            int32+            (tvVar old)+            locks'+            (sExt32 <$> locks_offset)+            (tvVar continue)+            (untyped (lockingToUnlock locking))    -- Preparing parameters. It is assumed that the caller has already   -- filled the arr_params. We copy the current value to the
src/Futhark/CodeGen/RTS/C.hs view
@@ -17,6 +17,7 @@     tuningH,     utilH,     valuesH,+    errorsH,   ) where @@ -100,3 +101,8 @@ valuesH :: T.Text valuesH = $(embedStringFile "rts/c/values.h") {-# NOINLINE valuesH #-}++-- | @rts/c/errors.h@+errorsH :: T.Text+errorsH = $(embedStringFile "rts/c/errors.h")+{-# NOINLINE errorsH #-}
src/Futhark/IR/GPU/Op.hs view
@@ -74,7 +74,7 @@         SegGroup {} -> "group"       virt = case segVirt lvl of         SegNoVirt -> mempty-        SegNoVirtFull -> PP.semi <+> text "full"+        SegNoVirtFull dims -> PP.semi <+> text "full" <+> ppr (segSeqDims dims)         SegVirt -> PP.semi <+> text "virtualise"  instance Engine.Simplifiable SegLevel where
src/Futhark/IR/Parse.hs view
@@ -826,7 +826,8 @@       <*> choice         [ pSemi             *> choice-              [ keyword "full" $> SegOp.SegNoVirtFull,+              [ keyword "full" $> SegOp.SegNoVirtFull+                  <*> (SegOp.SegSeqDims <$> brackets (pInt `sepBy` pComma)),                 keyword "virtualise" $> SegOp.SegVirt               ],           pure SegOp.SegNoVirt
src/Futhark/IR/SOACS/Simplify.hs view
@@ -746,20 +746,20 @@ replaceArrayOps ::   forall rep.   (Buildable rep, BuilderOps rep, HasSOAC rep) =>-  M.Map ArrayOp ArrayOp ->+  M.Map (AST.Pat rep, ArrayOp) ArrayOp ->   AST.Body rep ->   AST.Body rep replaceArrayOps substs (Body _ stms res) =   mkBody (fmap onStm stms) res   where     onStm (Let pat aux e) =-      let (cs', e') = onExp (stmAuxCerts aux) e+      let (cs', e') = onExp pat (stmAuxCerts aux) e        in certify cs' $ mkLet' (patIdents pat) aux e'-    onExp cs e+    onExp pat cs e       | Just op <- isArrayOp cs e,-        Just op' <- M.lookup op substs =+        Just op' <- M.lookup (pat, op) substs =         fromArrayOp op'-    onExp cs e = (cs, mapExp mapper e)+    onExp _ cs e = (cs, mapExp mapper e)     mapper =       identityMapper         { mapOnBody = const $ return . replaceArrayOps substs,@@ -792,11 +792,11 @@   forall rep.   (Buildable rep, BuilderOps rep, HasSOAC rep) =>   TopDownRuleOp rep-simplifyMapIota vtable pat aux op+simplifyMapIota vtable screma_pat aux op   | Just (Screma w arrs (ScremaForm scan reduce map_lam) :: SOAC rep) <- asSOAC op,     Just (p, _) <- find isIota (zip (lambdaParams map_lam) arrs),     indexings <--      mapMaybe (indexesWith (paramName p) . snd) . S.toList $+      mapMaybe (indexesWith (paramName p)) . S.toList $         arrayOps $ lambdaBody map_lam,     not $ null indexings = Simplify $ do     -- For each indexing with iota, add the corresponding array to@@ -810,7 +810,7 @@               lambdaBody = replaceArrayOps substs $ lambdaBody map_lam             } -    auxing aux . letBind pat . Op . soacOp $+    auxing aux . letBind screma_pat . Op . soacOp $       Screma w (arrs <> more_arrs) (ScremaForm scan reduce map_lam')   where     isIota (_, arr) = case ST.lookupBasicOp arr vtable of@@ -825,12 +825,12 @@       | otherwise = (j :) <$> fixWith i slice     fixWith _ _ = Nothing -    indexesWith v idx@(ArrayIndexing cs arr (Slice js))+    indexesWith v (pat, idx@(ArrayIndexing cs arr (Slice js)))       | arr `ST.elem` vtable,         all (`ST.elem` vtable) $ unCerts cs,         Just js' <- fixWith v js,         all (`ST.elem` vtable) $ namesToList $ freeIn js' =-        Just (js', idx)+        Just (pat, js', idx)     indexesWith _ _ = Nothing      properArr [] arr = pure arr@@ -838,7 +838,7 @@       arr_t <- lookupType arr       letExp (baseString arr) $ BasicOp $ Index arr $ fullSlice arr_t $ map DimFix js -    mapOverArr w (js, ArrayIndexing cs arr slice) = do+    mapOverArr w (pat, js, ArrayIndexing cs arr slice) = do       arr' <- properArr js arr       arr_t <- lookupType arr'       arr'' <-@@ -852,7 +852,7 @@         Just           ( arr'',             arr_elem_param,-            ( ArrayIndexing cs arr slice,+            ( (pat, ArrayIndexing cs arr slice),               ArrayIndexing cs (paramName arr_elem_param) (Slice (drop (length js + 1) (unSlice slice)))             )           )@@ -864,8 +864,8 @@ -- corresponding to that transformation performed on the rows of the -- full array. moveTransformToInput :: TopDownRuleOp (Wise SOACS)-moveTransformToInput vtable pat aux soac@(Screma w arrs (ScremaForm scan reduce map_lam))-  | ops <- map snd $ filter arrayIsMapParam $ S.toList $ arrayOps $ lambdaBody map_lam,+moveTransformToInput vtable screma_pat aux soac@(Screma w arrs (ScremaForm scan reduce map_lam))+  | ops <- filter arrayIsMapParam $ S.toList $ arrayOps $ lambdaBody map_lam,     not $ null ops = Simplify $ do     (more_arrs, more_params, replacements) <-       unzip3 . catMaybes <$> mapM mapOverArr ops@@ -879,7 +879,7 @@             }      auxing aux $-      letBind pat $ Op $ Screma w (arrs <> more_arrs) (ScremaForm scan reduce map_lam')+      letBind screma_pat $ Op $ Screma w (arrs <> more_arrs) (ScremaForm scan reduce map_lam')   where     -- It is not safe to move the transform if the root array is being     -- consumed by the Screma.  This is a bit too conservative - it's@@ -913,7 +913,7 @@     arrayIsMapParam (_, ArrayVar {}) =       False -    mapOverArr op+    mapOverArr (pat, op)       | Just (_, arr) <- find ((== arrayOpArr op) . fst) (zip map_param_names arrs),         not $ arr `nameIn` consumed = do         arr_t <- lookupType arr@@ -937,7 +937,7 @@           Just             ( arr_transformed,               Param mempty arr_transformed_row (rowType arr_transformed_t),-              (op, ArrayVar mempty arr_transformed_row)+              ((pat, op), ArrayVar mempty arr_transformed_row)             )     mapOverArr _ = return Nothing moveTransformToInput _ _ _ _ =
src/Futhark/IR/SegOp.hs view
@@ -13,6 +13,7 @@ module Futhark.IR.SegOp   ( SegOp (..),     SegVirt (..),+    SegSeqDims (..),     segLevel,     segBody,     segSpace,@@ -494,6 +495,24 @@       onDim (dim, blk_tile, reg_tile) =         ppr dim <+> "/" <+> parens (ppr blk_tile <+> "*" <+> ppr reg_tile) +-- | These dimensions (indexed from 0, outermost) of the corresponding+-- 'SegSpace' should not be parallelised, but instead iterated+-- sequentially.  For example, with a 'SegSeqDims' of @[0]@ and a+-- 'SegSpace' with dimensions @[n][m]@, there will be an outer loop+-- with @n@ iterations, while the @m@ dimension will be parallelised.+--+-- Semantically, this has no effect, but it may allow reductions in+-- memory usage or other low-level optimisations.  Operationally, the+-- guarantee is that for a SegSeqDims of e.g. @[i,j,k]@, threads+-- running at any given moment will always have the same indexes along+-- the dimensions specified by @[i,j,k]@.+--+-- At the moment, this is only supported for 'SegNoVirtFull'+-- intra-group parallelism in GPU code, as we have not yet found it+-- useful anywhere else.+newtype SegSeqDims = SegSeqDims {segSeqDims :: [Int]}+  deriving (Eq, Ord, Show)+ -- | Do we need group-virtualisation when generating code for the -- segmented operation?  In most cases, we do, but for some simple -- kernels, we compute the full number of groups in advance, and then@@ -507,7 +526,7 @@   | -- | Not only do we not need virtualisation, but we _guarantee_     -- that all physical threads participate in the work.  This can     -- save some checks in code generation.-    SegNoVirtFull+    SegNoVirtFull SegSeqDims   deriving (Eq, Ord, Show)  -- | Index space of a 'SegOp'.
src/Futhark/Optimise/BlkRegTiling.hs view
@@ -126,7 +126,7 @@               map snd rem_outer_dims_rev       grid_size <- letSubExp "grid_size" =<< toExp grid_pexp       group_size <- letSubExp "group_size" =<< toExp (pe64 ty * pe64 tx)-      let segthd_lvl = SegThread (Count grid_size) (Count group_size) SegNoVirtFull+      let segthd_lvl = SegThread (Count grid_size) (Count group_size) (SegNoVirtFull (SegSeqDims []))        gid_x <- newVName "gid_x"       gid_y <- newVName "gid_y"@@ -151,90 +151,90 @@         a_loc_init <- scratch "A_loc" map_t1 [a_loc_sz]         b_loc_init <- scratch "B_loc" map_t2 [b_loc_sz] -        let kkLoopBody kk0 (thd_res_merge, a_loc_init', b_loc_init') epilogue = do+        let kkLoopBody tkind kk0 (thd_res_merge, a_loc_init', b_loc_init') epilogue = do               kk <- letExp "kk" =<< toExp (le64 kk0 * pe64 tk)-              a_loc <- forLoop ry [a_loc_init'] $ \i0 [a_loc_merge] -> do-                loop_a_loc <- forLoop tk_div_tx [a_loc_merge] $ \k0 [a_loc_merge'] -> do-                  scatter_a_loc <- segScatter2D "A_glb2loc" a_loc_sz a_loc_merge' segthd_lvl (ty, tx) $-                    \(thd_y, thd_x) -> do-                      k <- letExp "k" =<< toExp (le64 thd_x + le64 k0 * pe64 tx)-                      i <- letExp "i" =<< toExp (le64 thd_y + le64 i0 * pe64 ty)+              a_loc <- segScatter2D+                "A_glb2loc"+                a_loc_sz+                a_loc_init'+                segthd_lvl+                [ry, tk_div_tx]+                (ty, tx)+                $ \[i0, k0] (thd_y, thd_x) -> do+                  k <- letExp "k" =<< toExp (le64 thd_x + le64 k0 * pe64 tx)+                  i <- letExp "i" =<< toExp (le64 thd_y + le64 i0 * pe64 ty) -                      letBindNames [gtid_y] =<< toExp (le64 iii + le64 i)-                      a_col_idx <- letExp "A_col_idx" =<< toExp (le64 kk + le64 k)+                  letBindNames [gtid_y] =<< toExp (le64 iii + le64 i)+                  a_col_idx <- letExp "A_col_idx" =<< toExp (le64 kk + le64 k) -                      a_elem <--                        letSubExp "A_elem"-                          =<< eIf-                            ( toExp $-                                le64 gtid_y .<. pe64 height_A-                                  .&&. if epilogue-                                    then le64 a_col_idx .<. pe64 common_dim-                                    else true-                            )-                            ( do-                                addStm load_A-                                res <- index "A_elem" inp_A [a_col_idx]-                                resultBodyM [Var res]-                            )-                            (eBody [eBlank $ Prim map_t1])-                      a_loc_ind <--                        letSubExp "a_loc_ind"-                          =<< eIf-                            (toExp $ le64 k .<. pe64 tk)-                            ( toExp (le64 k + le64 i * pe64 tk)-                                >>= letTupExp' "loc_fi"-                                >>= resultBodyM-                            )-                            (eBody [pure $ BasicOp $ SubExp $ intConst Int64 (-1)])-                      return (a_elem, a_loc_ind)-                  resultBodyM $ map Var scatter_a_loc-                resultBodyM [Var loop_a_loc]+                  a_elem <-+                    letSubExp "A_elem"+                      =<< eIf+                        ( toExp $+                            le64 gtid_y .<. pe64 height_A+                              .&&. if epilogue+                                then le64 a_col_idx .<. pe64 common_dim+                                else true+                        )+                        ( do+                            addStm load_A+                            res <- index "A_elem" inp_A [a_col_idx]+                            resultBodyM [Var res]+                        )+                        (eBody [eBlank $ Prim map_t1])+                  a_loc_ind <-+                    letSubExp "a_loc_ind"+                      =<< eIf+                        (toExp $ le64 k .<. pe64 tk)+                        ( toExp (le64 k + le64 i * pe64 tk)+                            >>= letTupExp' "loc_fi"+                            >>= resultBodyM+                        )+                        (eBody [pure $ BasicOp $ SubExp $ intConst Int64 (-1)])+                  return (a_elem, a_loc_ind)                -- copy B from global to shared memory-              b_loc <- forLoop tk_div_ty [b_loc_init'] $ \k0 [b_loc_merge] -> do-                loop_b_loc <- forLoop rx [b_loc_merge] $ \j0 [b_loc_merge'] -> do-                  scatter_b_loc <- segScatter2D-                    "B_glb2loc"-                    b_loc_sz-                    b_loc_merge'-                    segthd_lvl-                    (ty, tx)-                    $ \(thd_y, thd_x) -> do-                      k <- letExp "k" =<< toExp (le64 thd_y + le64 k0 * pe64 ty)-                      j <- letExp "j" =<< toExp (le64 thd_x + le64 j0 * pe64 tx)+              b_loc <- segScatter2D+                "B_glb2loc"+                b_loc_sz+                b_loc_init'+                segthd_lvl+                [tk_div_ty, rx]+                (ty, tx)+                $ \[k0, j0] (thd_y, thd_x) ->+                  do+                    k <- letExp "k" =<< toExp (le64 thd_y + le64 k0 * pe64 ty)+                    j <- letExp "j" =<< toExp (le64 thd_x + le64 j0 * pe64 tx) -                      letBindNames [gtid_x] =<< toExp (le64 jjj + le64 j)-                      b_row_idx <- letExp "B_row_idx" =<< toExp (le64 kk + le64 k)+                    letBindNames [gtid_x] =<< toExp (le64 jjj + le64 j)+                    b_row_idx <- letExp "B_row_idx" =<< toExp (le64 kk + le64 k) -                      b_elem <--                        letSubExp "B_elem"-                          =<< eIf-                            ( toExp $-                                le64 gtid_x .<. pe64 width_B-                                  .&&. if epilogue-                                    then le64 b_row_idx .<. pe64 common_dim-                                    else true-                            )-                            ( do-                                addStm load_B-                                res <- index "B_elem" inp_B [b_row_idx]-                                resultBodyM [Var res]-                            )-                            (eBody [eBlank $ Prim map_t2])+                    b_elem <-+                      letSubExp "B_elem"+                        =<< eIf+                          ( toExp $+                              le64 gtid_x .<. pe64 width_B+                                .&&. if epilogue+                                  then le64 b_row_idx .<. pe64 common_dim+                                  else true+                          )+                          ( do+                              addStm load_B+                              res <- index "B_elem" inp_B [b_row_idx]+                              resultBodyM [Var res]+                          )+                          (eBody [eBlank $ Prim map_t2]) -                      b_loc_ind <--                        letSubExp "b_loc_ind"-                          =<< eIf-                            (toExp $ le64 k .<. pe64 tk)-                            ( toExp (le64 j + le64 k * pe64 tx_rx)-                                >>= letTupExp' "loc_fi"-                                >>= resultBodyM-                            )-                            (eBody [pure $ BasicOp $ SubExp $ intConst Int64 (-1)])-                      return (b_elem, b_loc_ind)-                  resultBodyM $ map Var scatter_b_loc-                resultBodyM [Var loop_b_loc]+                    b_loc_ind <-+                      letSubExp "b_loc_ind"+                        =<< eIf+                          (toExp $ le64 k .<. pe64 tk)+                          ( toExp (le64 j + le64 k * pe64 tx_rx)+                              >>= letTupExp' "loc_fi"+                              >>= resultBodyM+                          )+                          (eBody [pure $ BasicOp $ SubExp $ intConst Int64 (-1)])+                    return (b_elem, b_loc_ind)                -- inner loop updating this thread's accumulator (loop k in mmm_kernels).               thd_acc <- forLoop tk [thd_res_merge] $ \k [acc_merge] ->@@ -291,15 +291,18 @@                             css_init <- index "css_init" acc_merge [ltid_y, ltid_x]                              css <- forLoop ry [css_init] $ \i [css_merge] -> do-                              css <- forLoop rx [css_merge] $ \j [css_merge'] ->+                              css <- forLoop rx [css_merge] $ \j [css_merge'] -> do+                                let cond =+                                      toExp $ case tkind of+                                        TileFull -> true+                                        TilePartial ->+                                          le64 iii + le64 i + pe64 ry * le64 ltid_y+                                            .<. pe64 height_A+                                              .&&. le64 jjj + le64 j + pe64 rx * le64 ltid_x+                                            .<. pe64 width_B                                 resultBodyM =<< letTupExp' "foo"                                   =<< eIf-                                    ( toExp $-                                        le64 iii + le64 i + pe64 ry * le64 ltid_y-                                          .<. pe64 height_A-                                            .&&. le64 jjj + le64 j + pe64 rx * le64 ltid_x-                                          .<. pe64 width_B-                                    )+                                    cond                                     ( do                                         a <- index "a" as [i]                                         b <- index "b" bs [j]@@ -339,14 +342,14 @@           forLoop' (Var full_tiles) [cssss, a_loc_init, b_loc_init] $             \kk0 [thd_res_merge, a_loc_merge, b_loc_merge] -> do               process_full_tiles <--                kkLoopBody kk0 (thd_res_merge, a_loc_merge, b_loc_merge) False+                kkLoopBody TileFull kk0 (thd_res_merge, a_loc_merge, b_loc_merge) False                resultBodyM $ map Var process_full_tiles          let prologue_res : a_loc_reuse : b_loc_reuse : _ = prologue_res_list          -- build epilogue.-        epilogue_res_list <- kkLoopBody full_tiles (prologue_res, a_loc_reuse, b_loc_reuse) True+        epilogue_res_list <- kkLoopBody TilePartial full_tiles (prologue_res, a_loc_reuse, b_loc_reuse) True          let redomap_res : _ = epilogue_res_list @@ -779,7 +782,7 @@       let grid_pexp = product $ gridxyz_pexp : map (pe64 . snd) rem_outer_dims_rev       grid_size <- letSubExp "grid_size_tile3d" =<< toExp grid_pexp       group_size <- letSubExp "group_size_tile3d" =<< toExp (pe64 ty * pe64 tx)-      let segthd_lvl = SegThread (Count grid_size) (Count group_size) SegNoVirtFull+      let segthd_lvl = SegThread (Count grid_size) (Count group_size) (SegNoVirtFull (SegSeqDims []))        count_shmem <- letSubExp "count_shmem" =<< ceilDiv rz group_size 
src/Futhark/Optimise/InPlaceLowering/LowerIntoStm.hs view
@@ -248,11 +248,9 @@     mkMerge summary       | Just (update, mergename, mergedec) <- relatedUpdate summary = do         source <- newVName "modified_source"+        precopy <- newVName $ baseString (updateValue update) <> "_precopy"         let source_t = snd $ updateType update-            elmident =-              Ident-                (updateValue update)-                (source_t `setArrayDims` sliceDims (updateIndices update))+            elm_t = source_t `setArrayDims` sliceDims (updateIndices update)         tell           ( [ mkLet [Ident source source_t] . BasicOp $                 Update@@ -261,10 +259,11 @@                   (fullSlice source_t $ unSlice $ updateIndices update)                   $ snd $ mergeParam summary             ],-            [ mkLet [elmident] . BasicOp $+            [ mkLet [Ident precopy elm_t] . BasicOp $                 Index                   (updateName update)-                  (fullSlice source_t $ unSlice $ updateIndices update)+                  (fullSlice source_t $ unSlice $ updateIndices update),+              mkLet [Ident (updateValue update) elm_t] $ BasicOp $ Copy precopy             ]           )         return $
src/Futhark/Optimise/TileLoops.hs view
@@ -723,8 +723,6 @@       -- Create a SegMap that takes care of the postlude for every thread.       postludeGeneric tiling privstms pat accs' poststms poststms_res res_ts -data TileKind = TilePartial | TileFull- mkReadPreludeValues :: [VName] -> [VName] -> ReadPrelude mkReadPreludeValues prestms_live_arrs prestms_live slice =   fmap mconcat $@@ -1012,7 +1010,7 @@   fmap (inputsToTiles inputs)     . segMap2D       "full_tile"-      (SegThread num_groups group_size SegNoVirtFull)+      (SegThread num_groups group_size (SegNoVirtFull (SegSeqDims [])))       ResultNoSimplify       (tile_size, tile_size)     $ \(ltid_x, ltid_y) -> do@@ -1092,7 +1090,7 @@    segMap2D     "acc"-    (SegThread num_groups group_size SegNoVirtFull)+    (SegThread num_groups group_size (SegNoVirtFull (SegSeqDims [])))     ResultPrivate     (tile_size, tile_size)     $ \(ltid_x, ltid_y) -> do@@ -1227,7 +1225,7 @@         (num_groups_y : map snd dims_on_top)    gid_flat <- newVName "gid_flat"-  let lvl = SegGroup (Count num_groups) (Count group_size) SegNoVirtFull+  let lvl = SegGroup (Count num_groups) (Count group_size) (SegNoVirtFull (SegSeqDims []))       space =         SegSpace gid_flat $           dims_on_top ++ [(gid_x, num_groups_x), (gid_y, num_groups_y)]
src/Futhark/Optimise/TileLoops/Shared.hs view
@@ -7,6 +7,7 @@     VarianceTable,     varianceInStms,     isTileableRedomap,+    TileKind (..),   ) where @@ -99,24 +100,36 @@   SubExp -> -- arr_size   VName ->   SegLevel -> -- lvl+  [SubExp] -> -- dims of sequential loop on top   (SubExp, SubExp) -> -- (dim_y, dim_x)-  ((VName, VName) -> Builder GPU (SubExp, SubExp)) -> -- f-  Builder GPU [VName]-segScatter2D desc arr_size updt_arr lvl (dim_x, dim_y) f = do+  ([VName] -> (VName, VName) -> Builder GPU (SubExp, SubExp)) -> -- f+  Builder GPU VName+segScatter2D desc arr_size updt_arr lvl seq_dims (dim_x, dim_y) f = do   ltid_x <- newVName "ltid_x"   ltid_y <- newVName "ltid_y"   ltid_flat <- newVName "ltid_flat"-  let segspace = SegSpace ltid_flat [(ltid_x, dim_x), (ltid_y, dim_y)] +  seq_is <- replicateM (length seq_dims) (newVName "ltid_seq")+  let seq_space = zip seq_is seq_dims++  let segspace = SegSpace ltid_flat $ seq_space ++ [(ltid_x, dim_x), (ltid_y, dim_y)]+      lvl' =+        SegThread+          (segNumGroups lvl)+          (segGroupSize lvl)+          (SegNoVirtFull (SegSeqDims [0 .. length seq_dims -1]))+   ((t_v, res_v, res_i), stms) <- runBuilder $ do-    (res_v, res_i) <- f (ltid_x, ltid_y)+    (res_v, res_i) <-+      localScope (scopeOfSegSpace segspace) $+        f seq_is (ltid_x, ltid_y)     t_v <- subExpType res_v     return (t_v, res_v, res_i)    let ret = WriteReturns mempty (Shape [arr_size]) updt_arr [(Slice [DimFix res_i], res_v)]   let body = KernelBody () stms [ret] -  letTupExp desc <=< renameExp $ Op $ SegOp $ SegMap lvl segspace [t_v] body+  letExp desc <=< renameExp $ Op $ SegOp $ SegMap lvl' segspace [t_v] body  -- | The variance table keeps a mapping from a variable name -- (something produced by a 'Stm') to the kernel thread indices@@ -181,3 +194,6 @@  varianceInStms :: VarianceTable -> Stms GPU -> VarianceTable varianceInStms = foldl' varianceInStm++-- | Are we working with full or partial tiles?+data TileKind = TilePartial | TileFull
src/Language/Futhark/Parser/Parser.y view
@@ -445,8 +445,6 @@            { TEUnique $2 (srcspan $1 $>) }          | '[' DimExp ']' TypeExpTerm %prec indexprec            { TEArray $4 $2 (srcspan $1 $>) }-         | '['  ']' TypeExpTerm %prec indexprec-           { TEArray $3 DimExpAny (srcspan $1 $>) }          | TypeExpApply %prec sumprec { $1 }           -- Errors@@ -498,7 +496,6 @@  TypeArg :: { TypeArgExp Name }          : '[' DimExp ']' { TypeArgExpDim $2 (srcspan $1 $>) }-         | '[' ']'         { TypeArgExpDim DimExpAny (srcspan $1 $>) }          | TypeExpAtom     { TypeArgExpType $1 }  FieldType :: { (Name, UncheckedTypeExp) }@@ -518,6 +515,8 @@         | intlit           { let L loc (INTLIT n) = $1             in DimExpConst (fromIntegral n) loc }+        |+          { DimExpAny }  FunParam :: { PatBase NoInfo Name } FunParam : InnerPat { $1 }