packages feed

futhark 0.22.2 → 0.22.3

raw patch · 58 files changed

+937/−733 lines, 58 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Futhark.IR.GPU.Op: [segGroupSize] :: SegLevel -> Count GroupSize SubExp
- Futhark.IR.GPU.Op: [segNumGroups] :: SegLevel -> Count NumGroups SubExp
- Futhark.IR.GPU.Op: [segVirt] :: SegLevel -> SegVirt
- Futhark.IR.SegOp: SegNoVirt :: SegVirt
- Futhark.IR.SegOp: SegNoVirtFull :: SegSeqDims -> SegVirt
- Futhark.IR.SegOp: SegSeqDims :: [Int] -> SegSeqDims
- Futhark.IR.SegOp: SegVirt :: SegVirt
- Futhark.IR.SegOp: [segSeqDims] :: SegSeqDims -> [Int]
- Futhark.IR.SegOp: data SegVirt
- Futhark.IR.SegOp: instance GHC.Classes.Eq Futhark.IR.SegOp.SegSeqDims
- Futhark.IR.SegOp: instance GHC.Classes.Eq Futhark.IR.SegOp.SegVirt
- Futhark.IR.SegOp: instance GHC.Classes.Ord Futhark.IR.SegOp.SegSeqDims
- Futhark.IR.SegOp: instance GHC.Classes.Ord Futhark.IR.SegOp.SegVirt
- Futhark.IR.SegOp: instance GHC.Show.Show Futhark.IR.SegOp.SegSeqDims
- Futhark.IR.SegOp: instance GHC.Show.Show Futhark.IR.SegOp.SegVirt
- Futhark.IR.SegOp: newtype SegSeqDims
- Language.Futhark.TypeChecker.Match: instance GHC.Classes.Eq Language.Futhark.TypeChecker.Match.Match
- Language.Futhark.TypeChecker.Match: instance GHC.Classes.Ord Language.Futhark.TypeChecker.Match.Match
- Language.Futhark.TypeChecker.Match: instance GHC.Show.Show Language.Futhark.TypeChecker.Match.Match
- Language.Futhark.TypeChecker.Match: instance Prettyprinter.Internal.Pretty Language.Futhark.TypeChecker.Match.Match
- Language.Futhark.TypeChecker.Terms.Monad: notConsumable :: MonadTypeChecker m => SrcLoc -> Doc () -> m b
+ Futhark.Actions: printFusionGraph :: Action SOACS
+ Futhark.Analysis.UsageTable: usageInPat :: FreeIn t => Pat t -> UsageTable
+ Futhark.CodeGen.ImpGen: sCopy :: VName -> TExp Int64 -> Space -> VName -> TExp Int64 -> Space -> Count Elements (TExp Int64) -> PrimType -> ImpM rep r op ()
+ Futhark.CodeGen.ImpGen.GPU.Base: lvlKernelAttrs :: SegLevel -> CallKernelGen KernelAttrs
+ Futhark.CodeGen.ImpGen.GPU.Base: sCopyKernel :: CopyCompiler GPUMem HostEnv HostOp
+ Futhark.Construct: eIndex :: MonadBuilder m => VName -> m (Exp (Rep m)) -> m (Exp (Rep m))
+ Futhark.Construct: eLast :: MonadBuilder m => VName -> m (Exp (Rep m))
+ Futhark.IR.GPU.Op: KernelGrid :: Count NumGroups SubExp -> Count GroupSize SubExp -> KernelGrid
+ Futhark.IR.GPU.Op: SegNoVirt :: SegVirt
+ Futhark.IR.GPU.Op: SegNoVirtFull :: SegSeqDims -> SegVirt
+ Futhark.IR.GPU.Op: SegSeqDims :: [Int] -> SegSeqDims
+ Futhark.IR.GPU.Op: SegThreadInGroup :: SegVirt -> SegLevel
+ Futhark.IR.GPU.Op: SegVirt :: SegVirt
+ Futhark.IR.GPU.Op: [gridGroupSize] :: KernelGrid -> Count GroupSize SubExp
+ Futhark.IR.GPU.Op: [gridNumGroups] :: KernelGrid -> Count NumGroups SubExp
+ Futhark.IR.GPU.Op: [segSeqDims] :: SegSeqDims -> [Int]
+ Futhark.IR.GPU.Op: data KernelGrid
+ Futhark.IR.GPU.Op: data SegVirt
+ Futhark.IR.GPU.Op: instance Futhark.IR.Prop.Names.FreeIn Futhark.IR.GPU.Op.KernelGrid
+ Futhark.IR.GPU.Op: instance Futhark.Optimise.Simplify.Engine.Simplifiable Futhark.IR.GPU.Op.KernelGrid
+ Futhark.IR.GPU.Op: instance Futhark.Transform.Substitute.Substitute Futhark.IR.GPU.Op.KernelGrid
+ Futhark.IR.GPU.Op: instance GHC.Classes.Eq Futhark.IR.GPU.Op.KernelGrid
+ Futhark.IR.GPU.Op: instance GHC.Classes.Eq Futhark.IR.GPU.Op.SegSeqDims
+ Futhark.IR.GPU.Op: instance GHC.Classes.Eq Futhark.IR.GPU.Op.SegVirt
+ Futhark.IR.GPU.Op: instance GHC.Classes.Ord Futhark.IR.GPU.Op.KernelGrid
+ Futhark.IR.GPU.Op: instance GHC.Classes.Ord Futhark.IR.GPU.Op.SegSeqDims
+ Futhark.IR.GPU.Op: instance GHC.Classes.Ord Futhark.IR.GPU.Op.SegVirt
+ Futhark.IR.GPU.Op: instance GHC.Show.Show Futhark.IR.GPU.Op.KernelGrid
+ Futhark.IR.GPU.Op: instance GHC.Show.Show Futhark.IR.GPU.Op.SegSeqDims
+ Futhark.IR.GPU.Op: instance GHC.Show.Show Futhark.IR.GPU.Op.SegVirt
+ Futhark.IR.GPU.Op: instance Prettyprinter.Internal.Pretty Futhark.IR.GPU.Op.KernelGrid
+ Futhark.IR.GPU.Op: instance Prettyprinter.Internal.Pretty Futhark.IR.GPU.Op.SegVirt
+ Futhark.IR.GPU.Op: newtype SegSeqDims
+ Futhark.IR.GPU.Op: segVirt :: SegLevel -> SegVirt
+ Futhark.IR.Prop.Names: instance Futhark.IR.Prop.Names.FreeIn a => Futhark.IR.Prop.Names.FreeIn (Data.Set.Internal.Set a)
+ Futhark.IR.Syntax: class Pretty a
+ Futhark.Optimise.Fusion.GraphRep: mkDepGraphForFun :: FunDef SOACS -> DepGraph
+ Futhark.Util: cartesian :: (Monoid m, Foldable t) => (a -> a -> m) -> t a -> t a -> m
+ Futhark.Util.Pretty: ppTupleLines' :: [Doc a] -> Doc a
+ Language.Futhark.TypeChecker.Match: instance GHC.Classes.Eq t => GHC.Classes.Eq (Language.Futhark.TypeChecker.Match.Match t)
+ Language.Futhark.TypeChecker.Match: instance GHC.Classes.Ord t => GHC.Classes.Ord (Language.Futhark.TypeChecker.Match.Match t)
+ Language.Futhark.TypeChecker.Match: instance GHC.Show.Show t => GHC.Show.Show (Language.Futhark.TypeChecker.Match.Match t)
+ Language.Futhark.TypeChecker.Match: instance Prettyprinter.Internal.Pretty (Language.Futhark.TypeChecker.Match.Match t)
- Futhark.CodeGen.ImpGen.GPU.Base: sCopy :: CopyCompiler GPUMem HostEnv HostOp
+ Futhark.CodeGen.ImpGen.GPU.Base: sCopy :: VName -> TExp Int64 -> Space -> VName -> TExp Int64 -> Space -> Count Elements (TExp Int64) -> PrimType -> ImpM rep r op ()
- Futhark.CodeGen.ImpGen.GPU.SegHist: compileSegHist :: Pat LetDecMem -> Count NumGroups SubExp -> Count GroupSize SubExp -> SegSpace -> [HistOp GPUMem] -> KernelBody GPUMem -> CallKernelGen ()
+ Futhark.CodeGen.ImpGen.GPU.SegHist: compileSegHist :: Pat LetDecMem -> SegLevel -> SegSpace -> [HistOp GPUMem] -> KernelBody GPUMem -> CallKernelGen ()
- Futhark.CodeGen.ImpGen.GPU.SegRed: compileSegRed' :: Pat LetDecMem -> SegLevel -> SegSpace -> [SegBinOp GPUMem] -> DoSegBody -> CallKernelGen ()
+ Futhark.CodeGen.ImpGen.GPU.SegRed: compileSegRed' :: Pat LetDecMem -> KernelGrid -> SegSpace -> [SegBinOp GPUMem] -> DoSegBody -> CallKernelGen ()
- Futhark.IR.GPU.Op: SegGroup :: Count NumGroups SubExp -> Count GroupSize SubExp -> SegVirt -> SegLevel
+ Futhark.IR.GPU.Op: SegGroup :: SegVirt -> Maybe KernelGrid -> SegLevel
- Futhark.IR.GPU.Op: SegThread :: Count NumGroups SubExp -> Count GroupSize SubExp -> SegVirt -> SegLevel
+ Futhark.IR.GPU.Op: SegThread :: SegVirt -> Maybe KernelGrid -> SegLevel
- Futhark.Optimise.Simplify.Engine: simplifyLambda :: SimplifiableRep rep => Lambda (Wise rep) -> SimpleM rep (Lambda (Wise rep), Stms (Wise rep))
+ Futhark.Optimise.Simplify.Engine: simplifyLambda :: SimplifiableRep rep => Names -> Lambda (Wise rep) -> SimpleM rep (Lambda (Wise rep), Stms (Wise rep))
- Futhark.Optimise.TileLoops.Shared: segMap1D :: String -> SegLevel -> ResultManifest -> (VName -> Builder GPU Result) -> Builder GPU [VName]
+ Futhark.Optimise.TileLoops.Shared: segMap1D :: String -> SegLevel -> ResultManifest -> SubExp -> (VName -> Builder GPU Result) -> 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
+ Futhark.Optimise.TileLoops.Shared: segScatter2D :: String -> SubExp -> VName -> [SubExp] -> (SubExp, SubExp) -> ([VName] -> (VName, VName) -> Builder GPU (SubExp, SubExp)) -> Builder GPU VName
- Language.Futhark.TypeChecker.Match: data Match
+ Language.Futhark.TypeChecker.Match: data Match t
- Language.Futhark.TypeChecker.Match: unmatched :: [Pat] -> [Match]
+ Language.Futhark.TypeChecker.Match: unmatched :: [Pat] -> [Match ()]

Files

docs/installation.rst view
@@ -197,7 +197,7 @@ have installed otherwise.  * On NixOS, for OpenCL, you should import ``opencl-headers`` and-  ``opencl-icd``.  You also need some form of OpenCL backend.  If you+  ``ocl-icd``.  You also need some form of OpenCL backend.  If you   have an AMD GPU and use ROCm, you may also need   ``rocm-opencl-runtime``. @@ -212,4 +212,4 @@  These can be easily made available with e.g:: -  nix-shell -p opencl-headers -p opencl-icd+  nix-shell -p opencl-headers -p ocl-icd
futhark.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name:           futhark-version:        0.22.2+version:        0.22.3 synopsis:       An optimising compiler for a functional, array-oriented language.  description:    Futhark is a small programming language designed to be compiled to
src/Futhark/AD/Rev/Scan.hs view
@@ -79,12 +79,7 @@ -- but insert explicit indexing to reverse inside the map. mkScan2ndMaps :: SubExp -> (Type, VName, (VName, VName)) -> ADM VName mkScan2ndMaps w (arr_tp, y_adj, (ds, cs)) = do-  nm1 <- letSubExp "nm1" =<< toExp (pe64 w - 1)-  y_adj_last <--    letExp (baseString y_adj ++ "_last") $-      BasicOp $-        Index y_adj $-          fullSlice arr_tp [DimFix nm1]+  y_adj_last <- letExp (baseString y_adj <> "_last") =<< eLast y_adj    par_i <- newParam "i" $ Prim int64   lam <- mkLambda [par_i] $ do@@ -121,9 +116,8 @@           (resultBodyM $ map (Var . paramName) par_r)           ( buildBody_ $ do               im1 <- letSubExp "im1" =<< toExp (le64 i - 1)-              ys_im1 <- forM ys $ \y -> do-                y_t <- lookupType y-                letSubExp (baseString y ++ "_last") $ BasicOp $ Index y $ fullSlice y_t [DimFix im1]+              ys_im1 <- forM ys $ \y ->+                letSubExp (baseString y <> "_im1") =<< eIndex y (eSubExp im1)                lam_res <-                 mapM (letExp "const" . BasicOp . SubExp . resSubExp)
src/Futhark/Actions.hs view
@@ -4,6 +4,7 @@   ( printAction,     printAliasesAction,     printLastUseGPU,+    printFusionGraph,     printInterferenceGPU,     printMemAliasGPU,     callGraphAction,@@ -54,6 +55,7 @@ import Futhark.IR.Prop.Aliases import Futhark.IR.SOACS (SOACS) import Futhark.IR.SeqMem (SeqMem)+import Futhark.Optimise.Fusion.GraphRep qualified import Futhark.Util (runProgramWithExitCode, unixEnvironment) import Futhark.Version (versionString) import System.Directory@@ -86,6 +88,22 @@     { actionName = "print last use gpu",       actionDescription = "Print last use information on gpu.",       actionProcedure = liftIO . print . LastUse.analyseGPUMem+    }++-- | Print fusion graph to stdout.+printFusionGraph :: Action SOACS+printFusionGraph =+  Action+    { actionName = "print fusion graph",+      actionDescription = "Print fusion graph in Graphviz format.",+      actionProcedure =+        liftIO+          . mapM_+            ( putStrLn+                . Futhark.Optimise.Fusion.GraphRep.pprg+                . Futhark.Optimise.Fusion.GraphRep.mkDepGraphForFun+            )+          . progFuns     }  -- | Print interference information to stdout.
src/Futhark/Analysis/Interference.hs view
@@ -16,7 +16,7 @@ import Futhark.Analysis.LastUse qualified as LastUse import Futhark.Analysis.MemAlias qualified as MemAlias import Futhark.IR.GPUMem-import Futhark.Util (invertMap)+import Futhark.Util (cartesian, invertMap)  -- | The set of 'VName' currently in use. type InUse = Names@@ -36,12 +36,6 @@ makeEdge v1 v2   | v1 == v2 = mempty   | otherwise = S.singleton (min v1 v2, max v1 v2)---- | Compute the cartesian product of two foldable collections, using the given--- combinator function.-cartesian :: (Monoid m, Foldable t) => (a -> a -> m) -> t a -> t a -> m-cartesian f xs ys =-  foldMap (uncurry f) [(x, y) | x <- toList xs, y <- toList ys]  analyseStm ::   LocalScope GPUMem m =>
src/Futhark/Analysis/LastUse.hs view
@@ -136,6 +136,16 @@         used_acc <> unAliases aliases       ) +    addAliasesFromBodyRes (lumap_acc, used_acc) (PatElem {}, Constant _) = (lumap_acc, used_acc)+    addAliasesFromBodyRes (lumap_acc, used_acc) (PatElem name _, Var body_res) =+      -- Any aliases of `name` should have the same last-use as `name`+      ( case M.lookup name lumap_acc of+          Just name' ->+            insertNames name' (oneName body_res) lumap_acc+          Nothing -> lumap_acc,+        used_acc <> oneName body_res+      )+     pat_name = patElemName $ head $ patElems pat      analyseExp (lumap, used) (BasicOp _) = do@@ -149,16 +159,21 @@         bimap mconcat mconcat . unzip           <$> mapM (analyseBody lumap used . caseBody) cases       (lumap_defbody, used_defbody) <- analyseBody lumap used defbody-      let used' = used_cases <> used_defbody+      let (lumap', used') =+            (lumap_defbody <> lumap_cases, used_cases <> used_defbody)+              & flip (foldl addAliasesFromBodyRes) (zip (patElems pat) (map resSubExp $ bodyResult defbody))           nms = (freeIn ses <> freeIn dec) `namesSubtract` used'       pure-        ( insertNames pat_name nms (lumap_cases <> lumap_defbody),+        ( insertNames pat_name nms lumap',           used' <> nms         )     analyseExp (lumap, used) (DoLoop merge form body) = do-      (lumap', used') <- analyseBody lumap used body-      let nms = (freeIn merge <> freeIn form) `namesSubtract` used'-      pure (insertNames pat_name nms lumap', used' <> nms)+      let (lumap', used') =+            zip (patElems pat) (map resSubExp $ bodyResult body)+              & foldl addAliasesFromBodyRes (lumap, used)+      (lumap'', used'') <- analyseBody lumap' used' body+      let nms = (freeIn merge <> freeIn form) `namesSubtract` used''+      pure (insertNames pat_name nms lumap'', used'' <> nms)     analyseExp (lumap, used) (Op op) = do       onOp <- asks envLastUseOp       onOp pat_name (lumap, used) op
src/Futhark/Analysis/PrimExp.hs view
@@ -228,6 +228,20 @@   | oneIshExp y = y   | zeroIshExp x = y   | zeroIshExp y = x+constFoldPrimExp (UnOpExp Abs {} x)+  | not $ negativeIshExp x = x+constFoldPrimExp (BinOpExp UMod {} x y)+  | sameIshExp x y,+    IntType it <- primExpType x =+      ValueExp $ IntValue $ intValue it (0 :: Integer)+constFoldPrimExp (BinOpExp SMod {} x y)+  | sameIshExp x y,+    IntType it <- primExpType x =+      ValueExp $ IntValue $ intValue it (0 :: Integer)+constFoldPrimExp (BinOpExp SRem {} x y)+  | sameIshExp x y,+    IntType it <- primExpType x =+      ValueExp $ IntValue $ intValue it (0 :: Integer) constFoldPrimExp e = e  -- | The class of numeric types that can be used for constructing@@ -336,8 +350,8 @@     | otherwise = numBad "*" (x, y)    abs (TPrimExp x)-    | IntType t <- primExpType x = TPrimExp $ UnOpExp (Abs t) x-    | FloatType t <- primExpType x = TPrimExp $ UnOpExp (FAbs t) x+    | IntType t <- primExpType x = TPrimExp $ constFoldPrimExp $ UnOpExp (Abs t) x+    | FloatType t <- primExpType x = TPrimExp $ constFoldPrimExp $ UnOpExp (FAbs t) x     | otherwise = numBad "abs" x    signum (TPrimExp x)@@ -419,7 +433,7 @@    TPrimExp x `mod` TPrimExp y     | Just z <- msum [asIntOp (`SMod` Unsafe) x y] =-        TPrimExp z+        TPrimExp $ constFoldPrimExp z     | otherwise = numBad "mod" (x, y)    TPrimExp x `quot` TPrimExp y@@ -588,6 +602,15 @@ oneIshExp :: PrimExp v -> Bool oneIshExp (ValueExp v) = oneIsh v oneIshExp _ = False++-- | Is the expression a constant negative of some sort?+negativeIshExp :: PrimExp v -> Bool+negativeIshExp (ValueExp v) = negativeIsh v+negativeIshExp _ = False++sameIshExp :: PrimExp v -> PrimExp v -> Bool+sameIshExp (ValueExp v1) (ValueExp v2) = v1 == v2+sameIshExp _ _ = False  -- | If the given 'PrimExp' is a constant of the wrong integer type, -- coerce it to the given integer type.  This is a workaround for an
src/Futhark/Analysis/UsageTable.hs view
@@ -23,6 +23,7 @@     consumedU,     presentU,     usageInStm,+    usageInPat,   ) where @@ -119,7 +120,7 @@ -- | Construct a usage table where the given names have been used as -- an array or memory size. sizeUsages :: Names -> UsageTable-sizeUsages = UsageTable . IM.map (const sizeU) . namesIntMap+sizeUsages = UsageTable . IM.map (const (sizeU <> presentU)) . namesIntMap  -- | A description of how a single variable has been used. newtype Usages = Usages Int -- Bitmap representation for speed.@@ -155,20 +156,17 @@ usageInStm :: (ASTRep rep, Aliased rep) => Stm rep -> UsageTable usageInStm (Let pat rep e) =   mconcat-    [ usageInPat,-      usageInExpDec,+    [ usageInPat pat `without` patNames pat,+      usages $ freeIn rep,       usageInExp e,       usages (freeIn e)     ]-  where-    usageInPat =-      usages-        ( mconcat (map freeIn $ patElems pat)-            `namesSubtract` namesFromList (patNames pat)-        )-        <> sizeUsages (foldMap (freeIn . patElemType) (patElems pat))-    usageInExpDec =-      usages $ freeIn rep++-- | Usage table reflecting use in pattern.  In particular, free+-- variables in the decorations are considered used as sizes, even if+-- they are also bound in this pattern.+usageInPat :: FreeIn t => Pat t -> UsageTable+usageInPat = sizeUsages . foldMap freeIn . patElems  usageInExp :: Aliased rep => Exp rep -> UsageTable usageInExp (Apply _ args _ _) =
src/Futhark/CLI/Dev.hs view
@@ -462,6 +462,11 @@       "Print the resulting IR with aliases.",     Option       []+      ["fusion-graph"]+      (NoArg $ Right $ \opts -> opts {futharkAction = SOACSAction printFusionGraph})+      "Print fusion graph.",+    Option+      []       ["print-last-use-gpu"]       ( NoArg $           Right $ \opts ->
src/Futhark/CodeGen/Backends/GenericC/CLI.hs view
@@ -282,6 +282,7 @@                  $ty:et' *arr = calloc($exp:num_elems, $id:info.size);                  assert(arr != NULL);                  assert($id:values_array(ctx, $exp:e, arr) == 0);+                 assert(futhark_context_sync(ctx) == 0);                  write_array(stdout, binary_output, &$id:info, arr,                              $id:shape_array(ctx, $exp:e), $int:rank);                  free(arr);@@ -304,10 +305,6 @@       printstms =         printResult manifest $ zip (map outputType outputs) output_vals -      ctx_ty = [C.cty|struct futhark_context|]-      sync_ctx = "futhark_context_sync" :: T.Text-      error_ctx = "futhark_context_get_error" :: T.Text-       cli_entry_point_function_name = "futrts_cli_entry_" ++ T.unpack entry_point_name        pause_profiling = "futhark_context_pause_profiling" :: T.Text@@ -320,8 +317,8 @@                 int r;                 // Run the program once.                 $stms:pack_input-                if ($id:sync_ctx(ctx) != 0) {-                  futhark_panic(1, "%s", $id:error_ctx(ctx));+                if (futhark_context_sync(ctx) != 0) {+                  futhark_panic(1, "%s", futhark_context_get_error(ctx));                 };                 // Only profile last run.                 if (profile_run) {@@ -332,10 +329,10 @@                              $args:(map addrOf output_vals),                              $args:input_args);                 if (r != 0) {-                  futhark_panic(1, "%s", $id:error_ctx(ctx));+                  futhark_panic(1, "%s", futhark_context_get_error(ctx));                 }-                if ($id:sync_ctx(ctx) != 0) {-                  futhark_panic(1, "%s", $id:error_ctx(ctx));+                if (futhark_context_sync(ctx) != 0) {+                  futhark_panic(1, "%s", futhark_context_get_error(ctx));                 };                 if (profile_run) {                   $id:pause_profiling(ctx);@@ -349,7 +346,7 @@                 $stms:free_input               |]    in ( [C.cedecl|-   static int $id:cli_entry_point_function_name($ty:ctx_ty *ctx) {+   static int $id:cli_entry_point_function_name(struct futhark_context *ctx) {      typename int64_t t_start, t_end;      int time_runs = 0, profile_run = 0;      int retval = 0;
src/Futhark/CodeGen/ImpGen.hs view
@@ -109,6 +109,7 @@     sWrite,     sUpdate,     sLoopNest,+    sCopy,     sLoopSpace,     (<--),     (<~~),@@ -1497,7 +1498,7 @@    pure fname --- | Use an 'Imp.Copy' if possible, otherwise 'copyElementWise'.+-- | Use 'sCopy' if possible, otherwise 'copyElementWise'. defaultCopy :: CopyCompiler rep r op defaultCopy pt dest src   | Just (destoffset, srcoffset, num_arrays, size_x, size_y) <-@@ -1524,17 +1525,7 @@       destspace <- entryMemSpace <$> lookupMemory destmem       if isScalarSpace srcspace || isScalarSpace destspace         then copyElementWise pt dest src-        else-          emit-            $ Imp.Copy-              pt-              destmem-              (bytes destoffset)-              destspace-              srcmem-              (bytes srcoffset)-              srcspace-            $ num_elems `withElemType` pt+        else sCopy destmem destoffset destspace srcmem srcoffset srcspace num_elems pt   | otherwise =       copyElementWise pt dest src   where@@ -1926,6 +1917,33 @@   ([Imp.TExp Int64] -> ImpM rep r op ()) ->   ImpM rep r op () sLoopNest = sLoopSpace . map pe64 . shapeDims++sCopy ::+  VName ->+  Imp.TExp Int64 ->+  Space ->+  VName ->+  Imp.TExp Int64 ->+  Space ->+  Count Elements (Imp.TExp Int64) ->+  PrimType ->+  ImpM rep r op ()+sCopy destmem destoffset destspace srcmem srcoffset srcspace num_elems pt =+  if destmem == srcmem+    then sUnless (destoffset .==. srcoffset) the_copy+    else the_copy+  where+    the_copy =+      emit+        $ Imp.Copy+          pt+          destmem+          (bytes destoffset)+          destspace+          srcmem+          (bytes srcoffset)+          srcspace+        $ num_elems `withElemType` pt  -- | Untyped assignment. (<~~) :: VName -> Imp.Exp -> ImpM rep r op ()
src/Futhark/CodeGen/ImpGen/GPU.hs view
@@ -16,7 +16,6 @@ import Data.List (foldl') import Data.Map qualified as M import Data.Maybe-import Futhark.CodeGen.ImpCode.GPU (bytes) import Futhark.CodeGen.ImpCode.GPU qualified as Imp import Futhark.CodeGen.ImpGen hiding (compileProg) import Futhark.CodeGen.ImpGen qualified@@ -166,12 +165,12 @@   CallKernelGen () segOpCompiler pat (SegMap lvl space _ kbody) =   compileSegMap pat lvl space kbody-segOpCompiler pat (SegRed lvl@SegThread {} space reds _ kbody) =+segOpCompiler pat (SegRed lvl@(SegThread _ _) space reds _ kbody) =   compileSegRed pat lvl space reds kbody-segOpCompiler pat (SegScan lvl@SegThread {} space scans _ kbody) =+segOpCompiler pat (SegScan lvl@(SegThread _ _) space scans _ kbody) =   compileSegScan pat lvl space scans kbody-segOpCompiler pat (SegHist (SegThread num_groups group_size _) space ops _ kbody) =-  compileSegHist pat num_groups group_size space ops kbody+segOpCompiler pat (SegHist lvl@(SegThread _ _) space ops _ kbody) =+  compileSegHist pat lvl space ops kbody segOpCompiler pat segop =   compilerBugS $ "segOpCompiler: unexpected " ++ prettyString (segLevel segop) ++ " for rhs of pattern " ++ prettyString pat @@ -298,17 +297,16 @@       let num_elems = Imp.elements $ product $ map pe64 srcshape       srcspace <- entryMemSpace <$> lookupMemory srcmem       destspace <- entryMemSpace <$> lookupMemory destmem-      emit-        $ Imp.Copy-          bt-          destmem-          (bytes $ sExt64 destoffset)-          destspace-          srcmem-          (bytes $ sExt64 srcoffset)-          srcspace-        $ num_elems `Imp.withElemType` bt-  | otherwise = sCopy bt destloc srcloc+      sCopy+        destmem+        (sExt64 destoffset)+        destspace+        srcmem+        (sExt64 srcoffset)+        srcspace+        num_elems+        bt+  | otherwise = sCopyKernel bt destloc srcloc  mapTransposeForType :: PrimType -> CallKernelGen Name mapTransposeForType bt = do
src/Futhark/CodeGen/ImpGen/GPU/Base.hs view
@@ -19,6 +19,8 @@     sKernelThread,     KernelAttrs (..),     defKernelAttrs,+    sCopyKernel,+    lvlKernelAttrs,     allocLocal,     kernelAlloc,     compileThreadResult,@@ -1076,6 +1078,33 @@       kAttrGroupSize = group_size     } +getSize :: String -> SizeClass -> CallKernelGen (TV Int64)+getSize desc size_class = do+  v <- dPrim desc int64+  fname <- askFunction+  let v_key = keyWithEntryPoint fname $ nameFromString $ prettyString $ tvVar v+  sOp $ Imp.GetSize (tvVar v) v_key size_class+  pure v++-- | Compute kernel attributes from 'SegLevel'; including synthesising+-- group-size and thread count if no grid is provided.+lvlKernelAttrs :: SegLevel -> CallKernelGen KernelAttrs+lvlKernelAttrs lvl =+  case lvl of+    SegThread _ Nothing -> mkGrid+    SegThread _ (Just (KernelGrid num_groups group_size)) ->+      pure $ defKernelAttrs num_groups group_size+    SegGroup _ Nothing -> mkGrid+    SegGroup _ (Just (KernelGrid num_groups group_size)) ->+      pure $ defKernelAttrs num_groups group_size+    SegThreadInGroup {} ->+      error "lvlKernelAttrs: SegThreadInGroup"+  where+    mkGrid = do+      group_size <- getSize "group_size" Imp.SizeGroup+      num_groups <- getSize "num_groups" Imp.SizeNumGroups+      pure $ defKernelAttrs (Count $ tvSize num_groups) (Count $ tvSize group_size)+ sKernel ::   Operations GPUMem KernelEnv Imp.KernelOp ->   (KernelConstants -> Imp.TExp Int32) ->@@ -1318,8 +1347,8 @@           [Imp.MemArg arr_mem, Imp.ExpArg $ untyped n, Imp.ExpArg x, Imp.ExpArg s]     else sIotaKernel arr n x s et -sCopy :: CopyCompiler GPUMem HostEnv Imp.HostOp-sCopy pt destloc@(MemLoc destmem _ _) srcloc@(MemLoc srcmem srcdims _) = do+sCopyKernel :: CopyCompiler GPUMem HostEnv Imp.HostOp+sCopyKernel pt destloc@(MemLoc destmem _ _) srcloc@(MemLoc srcmem srcdims _) = do   -- Note that the shape of the destination and the source are   -- necessarily the same.   let shape = map pe64 srcdims
src/Futhark/CodeGen/ImpGen/GPU/Group.hs view
@@ -195,14 +195,8 @@   bimap (map fst) (map fst) $     partition ((`elem` seq_is) . snd) (zip (unSegSpace space) [0 ..]) -sanityCheckLevel :: SegLevel -> InKernelGen ()-sanityCheckLevel SegThread {} = pure ()-sanityCheckLevel SegGroup {} =-  error "compileGroupOp: unexpected group-level SegOp."--compileFlatId :: SegLevel -> SegSpace -> InKernelGen ()-compileFlatId lvl space = do-  sanityCheckLevel lvl+compileFlatId :: SegSpace -> InKernelGen ()+compileFlatId space = do   ltid <- kernelLocalThreadId . kernelConstants <$> askEnv   dPrimV_ (segFlat space) ltid @@ -342,7 +336,7 @@ compileGroupOp pat (Alloc size space) =   kernelAlloc pat size space compileGroupOp pat (Inner (SegOp (SegMap lvl space _ body))) = do-  compileFlatId lvl space+  compileFlatId space    groupCoverSegSpace (segVirt lvl) space $     compileStms mempty (kernelBodyStms body) $@@ -350,7 +344,7 @@         kernelBodyResult body   sOp $ Imp.ErrorSync Imp.FenceLocal compileGroupOp pat (Inner (SegOp (SegScan lvl space scans _ body))) = do-  compileFlatId lvl space+  compileFlatId space    let (ltids, dims) = unzip $ unSegSpace space       dims' = map pe64 dims@@ -397,7 +391,7 @@         (segBinOpLambda scan)         arrs_flat compileGroupOp pat (Inner (SegOp (SegRed lvl space ops _ body))) = do-  compileFlatId lvl space+  compileFlatId space    let dims' = map pe64 dims       mkTempArr t =@@ -512,7 +506,7 @@        sOp $ Imp.Barrier Imp.FenceLocal compileGroupOp pat (Inner (SegOp (SegHist lvl space ops _ kbody))) = do-  compileFlatId lvl space+  compileFlatId space   let (ltids, _dims) = unzip $ unSegSpace space    -- We don't need the red_pes, because it is guaranteed by our type@@ -522,7 +516,8 @@       (_red_pes, map_pes) =         splitAt num_red_res $ patElems pat -  ops' <- prepareIntraGroupSegHist (segGroupSize lvl) ops+  group_size <- kernelGroupSizeCount . kernelConstants <$> askEnv+  ops' <- prepareIntraGroupSegHist group_size ops    -- Ensure that all locks have been initialised.   sOp $ Imp.Barrier Imp.FenceLocal
src/Futhark/CodeGen/ImpGen/GPU/SegHist.hs view
@@ -1046,13 +1046,13 @@ -- | Generate code for a segmented histogram called from the host. compileSegHist ::   Pat LetDecMem ->-  Count NumGroups SubExp ->-  Count GroupSize SubExp ->+  SegLevel ->   SegSpace ->   [HistOp GPUMem] ->   KernelBody GPUMem ->   CallKernelGen ()-compileSegHist (Pat pes) num_groups group_size space ops kbody = do+compileSegHist (Pat pes) lvl space ops kbody = do+  KernelAttrs _ _ num_groups group_size <- lvlKernelAttrs lvl   -- Most of this function is not the histogram part itself, but   -- rather figuring out whether to use a local or global memory   -- strategy, as well as collapsing the subhistograms produced (which@@ -1152,7 +1152,7 @@          flat_gtid <- newVName "flat_gtid" -        let lvl = SegThread num_groups group_size SegVirt+        let grid = KernelGrid num_groups group_size             segred_space =               SegSpace flat_gtid $                 segment_dims@@ -1161,7 +1161,7 @@                   ++ [(subhistogram_id, Var $ tvVar num_histos)]          let segred_op = SegBinOp Commutative (histOp op) (histNeutral op) mempty-        compileSegRed' (Pat red_pes) lvl segred_space [segred_op] $ \red_cont ->+        compileSegRed' (Pat red_pes) grid segred_space [segred_op] $ \red_cont ->           red_cont . flip map subhistos $ \subhisto ->             ( Var subhisto,               map Imp.le64 $
src/Futhark/CodeGen/ImpGen/GPU/SegMap.hs view
@@ -23,10 +23,11 @@   KernelBody GPUMem ->   CallKernelGen () compileSegMap pat lvl space kbody = do+  attrs <- lvlKernelAttrs lvl+   let (is, dims) = unzip $ unSegSpace space       dims' = map pe64 dims-      group_size' = pe64 <$> segGroupSize lvl-      attrs = defKernelAttrs (segNumGroups lvl) (segGroupSize lvl)+      group_size' = pe64 <$> kAttrGroupSize attrs    emit $ Imp.DebugPrint "\n# SegMap" Nothing   case lvl of@@ -58,4 +59,6 @@             compileStms mempty (kernelBodyStms kbody) $               zipWithM_ (compileGroupResult space) (patElems pat) $                 kernelBodyResult kbody+    SegThreadInGroup {} ->+      error "compileSegMap: SegThreadInGroup"   emit $ Imp.DebugPrint "" Nothing
src/Futhark/CodeGen/ImpGen/GPU/SegRed.hs view
@@ -82,8 +82,10 @@   [SegBinOp GPUMem] ->   KernelBody GPUMem ->   CallKernelGen ()-compileSegRed pat lvl space reds body =-  compileSegRed' pat lvl space reds $ \red_cont ->+compileSegRed pat lvl space reds body = do+  KernelAttrs _ _ num_groups group_size <- lvlKernelAttrs lvl+  let grid = KernelGrid num_groups group_size+  compileSegRed' pat grid space reds $ \red_cont ->     compileStms mempty (kernelBodyStms body) $ do       let (red_res, map_res) = splitAt (segBinOpResults reds) $ kernelBodyResult body @@ -96,12 +98,12 @@ -- | Like 'compileSegRed', but where the body is a monadic action. compileSegRed' ::   Pat LetDecMem ->-  SegLevel ->+  KernelGrid ->   SegSpace ->   [SegBinOp GPUMem] ->   DoSegBody ->   CallKernelGen ()-compileSegRed' pat lvl space reds body+compileSegRed' pat grid space reds body   | genericLength reds > maxNumOps =       compilerLimitationS $         "compileSegRed': at most " ++ show maxNumOps ++ " reduction operators are supported."@@ -116,8 +118,8 @@         (smallSegmentsReduction pat num_groups group_size space reds body)         (largeSegmentsReduction pat num_groups group_size space reds body)   where-    num_groups = segNumGroups lvl-    group_size = segGroupSize lvl+    num_groups = gridNumGroups grid+    group_size = gridGroupSize grid  -- | Prepare intermediate arrays for the reduction.  Prim-typed -- arguments go in local memory (so we need to do the allocation of
src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs view
@@ -215,6 +215,7 @@   KernelBody GPUMem ->   CallKernelGen () compileSegScan pat lvl space scanOp kbody = do+  attrs <- lvlKernelAttrs lvl   let Pat all_pes = pat       scanOpNe = segBinOpNeutral scanOp       tys = map (\(Prim pt) -> pt) $ lambdaReturnType $ segBinOpLambda scanOp@@ -233,7 +234,7 @@       mem_constraint = max k_mem sumT `div` maxT       reg_constraint = (k_reg - 1 - sumT') `div` (2 * sumT') -      group_size = segGroupSize lvl+      group_size = kAttrGroupSize attrs       group_size' = pe64 $ unCount group_size    num_groups <-@@ -274,7 +275,7 @@     constants <- kernelConstants <$> askEnv      (sharedId, transposedArrays, prefixArrays, warpscan, exchanges) <--      createLocalArrays (segGroupSize lvl) (intConst Int64 m) tys+      createLocalArrays (kAttrGroupSize attrs) (intConst Int64 m) tys      dynamicId <- dPrim "dynamic_id" int32     sWhen (kernelLocalThreadId constants .==. 0) $ do
src/Futhark/CodeGen/ImpGen/GPU/SegScan/TwoPass.hs view
@@ -491,6 +491,8 @@   KernelBody GPUMem ->   CallKernelGen () compileSegScan pat lvl space scans kbody = do+  attrs <- lvlKernelAttrs lvl+   -- Since stage 2 involves a group size equal to the number of groups   -- used for stage 1, we have to cap this number to the maximum group   -- size.@@ -501,14 +503,13 @@     fmap (Imp.Count . tvSize) $       dPrimV "stage1_num_groups" $         sMin64 (tvExp stage1_max_num_groups) $-          pe64 $-            Imp.unCount $-              segNumGroups lvl+          pe64 . Imp.unCount . kAttrNumGroups $+            attrs    (stage1_num_threads, elems_per_group, crossesSegment) <--    scanStage1 pat stage1_num_groups (segGroupSize lvl) space scans kbody+    scanStage1 pat stage1_num_groups (kAttrGroupSize attrs) space scans kbody    emit $ Imp.DebugPrint "elems_per_group" $ Just $ untyped elems_per_group    scanStage2 pat stage1_num_threads elems_per_group stage1_num_groups crossesSegment space scans-  scanStage3 pat (segNumGroups lvl) (segGroupSize lvl) elems_per_group crossesSegment space scans+  scanStage3 pat (kAttrNumGroups attrs) (kAttrGroupSize attrs) elems_per_group crossesSegment space scans
src/Futhark/Construct.hs view
@@ -86,6 +86,8 @@     eAny,     eDimInBounds,     eOutOfBounds,+    eIndex,+    eLast,      -- * Other building blocks     asIntZ,@@ -413,6 +415,22 @@           BasicOp $             BinOp LogOr less_than_zero greater_than_size   foldBinOp LogOr (constant False) =<< zipWithM checkDim ws is'++-- | The array element at this index.+eIndex :: MonadBuilder m => VName -> m (Exp (Rep m)) -> m (Exp (Rep m))+eIndex arr i = do+  i' <- letSubExp "i" =<< i+  arr_t <- lookupType arr+  pure $ BasicOp $ Index arr $ fullSlice arr_t [DimFix i']++-- | The last element of the given array.+eLast :: MonadBuilder m => VName -> m (Exp (Rep m))+eLast arr = do+  n <- arraySize 0 <$> lookupType arr+  nm1 <-+    letSubExp "nm1" . BasicOp $+      BinOp (Sub Int64 OverflowUndef) n (intConst Int64 1)+  eIndex arr (eSubExp nm1)  -- | Construct an unspecified value of the given type. eBlank :: MonadBuilder m => Type -> m (Exp (Rep m))
src/Futhark/IR/GPU/Op.hs view
@@ -12,6 +12,10 @@      -- * SegOp refinements     SegLevel (..),+    segVirt,+    SegVirt (..),+    SegSeqDims (..),+    KernelGrid (..),      -- * Reexports     module Futhark.IR.GPU.Sizes,@@ -44,68 +48,118 @@   ) import Futhark.Util.Pretty qualified as PP +-- | 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+-- virtualisation is an unnecessary (but generally very small)+-- overhead.  This only really matters for fairly trivial but very+-- wide @map@ kernels where each thread performs constant-time work on+-- scalars.+data SegVirt+  = SegVirt+  | SegNoVirt+  | -- | 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 SegSeqDims+  deriving (Eq, Ord, Show)++-- | The actual, physical grid dimensions used for the GPU kernel+-- running this 'SegOp'.+data KernelGrid = KernelGrid+  { gridNumGroups :: Count NumGroups SubExp,+    gridGroupSize :: Count GroupSize SubExp+  }+  deriving (Eq, Ord, Show)+ -- | At which level the *body* of a t'SegOp' executes. data SegLevel-  = SegThread-      { segNumGroups :: Count NumGroups SubExp,-        segGroupSize :: Count GroupSize SubExp,-        segVirt :: SegVirt-      }-  | SegGroup-      { segNumGroups :: Count NumGroups SubExp,-        segGroupSize :: Count GroupSize SubExp,-        segVirt :: SegVirt-      }+  = SegThread SegVirt (Maybe KernelGrid)+  | SegGroup SegVirt (Maybe KernelGrid)+  | SegThreadInGroup SegVirt   deriving (Eq, Ord, Show) +-- | The 'SegVirt' of the 'SegLevel'.+segVirt :: SegLevel -> SegVirt+segVirt (SegThread v _) = v+segVirt (SegGroup v _) = v+segVirt (SegThreadInGroup v) = v++instance PP.Pretty SegVirt where+  pretty SegNoVirt = mempty+  pretty (SegNoVirtFull dims) = "full" <+> pretty (segSeqDims dims)+  pretty SegVirt = "virtualise"++instance PP.Pretty KernelGrid where+  pretty (KernelGrid num_groups group_size) =+    "groups=" <> pretty num_groups <> PP.semi+      <+> "groupsize=" <> pretty group_size+ instance PP.Pretty SegLevel where-  pretty lvl =-    PP.parens-      ( lvl' <> PP.semi-          <+> "#groups=" <> pretty (segNumGroups lvl) <> PP.semi-          <+> "groupsize=" <> pretty (segGroupSize lvl) <> virt-      )-    where-      lvl' = case lvl of-        SegThread {} -> "thread"-        SegGroup {} -> "group"-      virt = case segVirt lvl of-        SegNoVirt -> mempty-        SegNoVirtFull dims -> PP.semi <+> "full" <+> pretty (segSeqDims dims)-        SegVirt -> PP.semi <+> "virtualise"+  pretty (SegThread virt grid) =+    PP.parens ("thread" <> PP.semi <+> pretty virt <> PP.semi <+> pretty grid)+  pretty (SegGroup virt grid) =+    PP.parens ("group" <> PP.semi <+> pretty virt <> PP.semi <+> pretty grid)+  pretty (SegThreadInGroup virt) =+    PP.parens ("ingroup" <> PP.semi <+> pretty virt) -instance Engine.Simplifiable SegLevel where-  simplify (SegThread num_groups group_size virt) =-    SegThread-      <$> traverse Engine.simplify num_groups-      <*> traverse Engine.simplify group_size-      <*> pure virt-  simplify (SegGroup num_groups group_size virt) =-    SegGroup+instance Engine.Simplifiable KernelGrid where+  simplify (KernelGrid num_groups group_size) =+    KernelGrid       <$> traverse Engine.simplify num_groups       <*> traverse Engine.simplify group_size-      <*> pure virt -instance Substitute SegLevel where-  substituteNames substs (SegThread num_groups group_size virt) =-    SegThread-      (substituteNames substs num_groups)-      (substituteNames substs group_size)-      virt-  substituteNames substs (SegGroup num_groups group_size virt) =-    SegGroup+instance Engine.Simplifiable SegLevel where+  simplify (SegThread virt grid) =+    SegThread virt <$> Engine.simplify grid+  simplify (SegGroup virt grid) =+    SegGroup virt <$> Engine.simplify grid+  simplify (SegThreadInGroup virt) =+    pure $ SegThreadInGroup virt++instance Substitute KernelGrid where+  substituteNames substs (KernelGrid num_groups group_size) =+    KernelGrid       (substituteNames substs num_groups)       (substituteNames substs group_size)-      virt +instance Substitute SegLevel where+  substituteNames substs (SegThread virt grid) =+    SegThread virt (substituteNames substs grid)+  substituteNames substs (SegGroup virt grid) =+    SegGroup virt (substituteNames substs grid)+  substituteNames _ (SegThreadInGroup virt) =+    SegThreadInGroup virt+ instance Rename SegLevel where   rename = substituteRename +instance FreeIn KernelGrid where+  freeIn' (KernelGrid num_groups group_size) =+    freeIn' (num_groups, group_size)+ instance FreeIn SegLevel where-  freeIn' (SegThread num_groups group_size _) =-    freeIn' num_groups <> freeIn' group_size-  freeIn' (SegGroup num_groups group_size _) =-    freeIn' num_groups <> freeIn' group_size+  freeIn' (SegThread _virt grid) = freeIn' grid+  freeIn' (SegGroup _virt grid) = freeIn' grid+  freeIn' (SegThreadInGroup _virt) = mempty  -- | A simple size-level query or computation. data SizeOp@@ -305,22 +359,34 @@   opMetrics (SizeOp op) = opMetrics op   opMetrics (GPUBody _ body) = inside "GPUBody" $ bodyMetrics body +checkGrid :: TC.Checkable rep => KernelGrid -> TC.TypeM rep ()+checkGrid grid = do+  TC.require [Prim int64] $ unCount $ gridNumGroups grid+  TC.require [Prim int64] $ unCount $ gridGroupSize grid+ checkSegLevel ::   TC.Checkable rep =>   Maybe SegLevel ->   SegLevel ->   TC.TypeM rep ()-checkSegLevel Nothing lvl = do-  TC.require [Prim int64] $ unCount $ segNumGroups lvl-  TC.require [Prim int64] $ unCount $ segGroupSize lvl+checkSegLevel (Just SegGroup {}) (SegThreadInGroup _virt) =+  pure ()+checkSegLevel _ (SegThreadInGroup _virt) =+  TC.bad $ TC.TypeError "ingroup SegOp not in group SegOp." checkSegLevel (Just SegThread {}) _ =   TC.bad $ TC.TypeError "SegOps cannot occur when already at thread level."-checkSegLevel (Just x) y-  | x == y = TC.bad $ TC.TypeError $ "Already at at level " <> prettyText x-  | segNumGroups x /= segNumGroups y || segGroupSize x /= segGroupSize y =-      TC.bad $ TC.TypeError "Physical layout for SegLevel does not match parent SegLevel."-  | otherwise =-      pure ()+checkSegLevel (Just SegThreadInGroup {}) _ =+  TC.bad $ TC.TypeError "SegOps cannot occur when already at ingroup level."+checkSegLevel _ (SegThread _virt Nothing) =+  pure ()+checkSegLevel (Just _) SegThread {} =+  TC.bad $ TC.TypeError "thread-level SegOp cannot be nested"+checkSegLevel Nothing (SegThread _virt grid) =+  mapM_ checkGrid grid+checkSegLevel (Just _) SegGroup {} =+  TC.bad $ TC.TypeError "group-level SegOp cannot be nested"+checkSegLevel Nothing (SegGroup _virt grid) =+  mapM_ checkGrid grid  typeCheckHostOp ::   TC.Checkable rep =>
src/Futhark/IR/MC/Op.hs view
@@ -28,8 +28,7 @@ import Futhark.Transform.Rename import Futhark.Transform.Substitute import Futhark.Util.Pretty-  ( Pretty,-    nestedBlock,+  ( nestedBlock,     pretty,     (<+>),     (</>),
src/Futhark/IR/Mem.hs view
@@ -131,7 +131,7 @@ import Futhark.Transform.Rename import Futhark.Transform.Substitute import Futhark.Util-import Futhark.Util.Pretty (docText, indent, ppTuple', pretty, (<+>), (</>))+import Futhark.Util.Pretty (docText, indent, ppTupleLines', pretty, (<+>), (</>)) import Futhark.Util.Pretty qualified as PP import Prelude hiding (id, (.)) @@ -748,9 +748,9 @@       bad s =         TC.bad . TC.TypeError . docText $           "Return type"-            </> indent 2 (ppTuple' $ map pretty rettype)+            </> indent 2 (ppTupleLines' $ map pretty rettype)             </> "cannot match returns of results"-            </> indent 2 (ppTuple' $ map pretty ts)+            </> indent 2 (ppTupleLines' $ map pretty ts)             </> pretty s    either bad pure =<< runExceptT (zipWithM_ checkReturn rettype ts)@@ -772,9 +772,9 @@    unless ok . TC.bad . TC.TypeError . docText $     "Expression type:"-      </> indent 2 (ppTuple' $ map pretty rt)+      </> indent 2 (ppTupleLines' $ map pretty rt)       </> "cannot match pattern type:"-      </> indent 2 (ppTuple' $ map pretty val_ts)+      </> indent 2 (ppTupleLines' $ map pretty val_ts)   where     matches _ _ (MemPrim x) (MemPrim y) = x == y     matches _ _ (MemMem x_space) (MemMem y_space) =
src/Futhark/IR/Parse.hs view
@@ -49,7 +49,7 @@   lexeme . fmap nameFromString $     (:) <$> satisfy leading <*> many (satisfy constituent)   where-    leading c = isAlpha c || c `elem` ("_+-*/%=!<>|&^." :: String)+    leading c = isAlpha c || c `elem` ("_+-*/%=!<>|&^.#" :: String)  pVName :: Parser VName pVName = lexeme $ do@@ -910,23 +910,36 @@  pSegLevel :: Parser GPU.SegLevel pSegLevel =-  parens $-    choice-      [ keyword "thread" $> GPU.SegThread,-        keyword "group" $> GPU.SegGroup-      ]-      <*> (pSemi *> lexeme "#groups=" $> GPU.Count <*> pSubExp)-      <*> (pSemi *> lexeme "groupsize=" $> GPU.Count <*> pSubExp)-      <*> choice-        [ pSemi-            *> choice-              [ keyword "full"-                  $> SegOp.SegNoVirtFull-                  <*> (SegOp.SegSeqDims <$> brackets (pInt `sepBy` pComma)),-                keyword "virtualise" $> SegOp.SegVirt-              ],-          pure SegOp.SegNoVirt+  parens . choice $+    [ "thread"+        $> GPU.SegThread+        <* pSemi+        <*> pSegVirt+        <* pSemi+        <*> optional pKernelGrid,+      "group"+        $> GPU.SegGroup+        <* pSemi+        <*> pSegVirt+        <* pSemi+        <*> optional pKernelGrid,+      "ingroup" $> GPU.SegThreadInGroup <* pSemi <*> pSegVirt+    ]+  where+    pSegVirt =+      choice+        [ choice+            [ keyword "full"+                $> GPU.SegNoVirtFull+                <*> (GPU.SegSeqDims <$> brackets (pInt `sepBy` pComma)),+              keyword "virtualise" $> GPU.SegVirt+            ],+          pure GPU.SegNoVirt         ]+    pKernelGrid =+      GPU.KernelGrid+        <$> (lexeme "groups=" $> GPU.Count <*> pSubExp <* pSemi)+        <*> (lexeme "groupsize=" $> GPU.Count <*> pSubExp)  pHostOp :: PR rep -> Parser op -> Parser (GPU.HostOp rep op) pHostOp pr pOther =
src/Futhark/IR/Pretty.hs view
@@ -278,7 +278,7 @@       <+> "else"       <+> maybeNest f       </> colon-      <+> ppTuple' (map pretty ret)+      <+> ppTupleLines' (map pretty ret)     where       info' = case ifsort of         MatchNormal -> mempty@@ -291,7 +291,7 @@       <+> "->"       <+> maybeNest defb       </> colon-      <+> ppTuple' (map pretty ret)+      <+> ppTupleLines' (map pretty ret)     where       info' = case ifsort of         MatchNormal -> mempty@@ -359,7 +359,7 @@   pretty (Lambda params body rettype) =     "\\"       <+> ppTuple' (map pretty params)-      </> indent 2 (colon <+> ppTupleLines' rettype <+> "->")+      </> indent 2 (colon <+> ppTupleLines' (map pretty rettype) <+> "->")       </> indent 2 (pretty body)  instance Pretty Signedness where@@ -385,8 +385,8 @@     annot (attrAnnots attrs) $       fun         </> indent 2 (pretty (nameToString name))-        <+> apply (map pretty fparams)-        </> indent 2 (colon <+> align (ppTuple' $ map pretty rettype))+        <+> parens (commastack $ map pretty fparams)+        </> indent 2 (colon <+> align (ppTupleLines' $ map pretty rettype))         <+> equals         <+> nestedBlock "{" "}" (pretty body)     where@@ -396,8 +396,8 @@           "entry"             <> (parens . align)               ( "\"" <> pretty p_name <> "\"" <> comma-                  </> ppTupleLines' p_entry <> comma-                  </> ppTupleLines' ret_entry+                  </> ppTupleLines' (map pretty p_entry) <> comma+                  </> ppTupleLines' (map pretty ret_entry)               )  instance Pretty OpaqueType where@@ -420,7 +420,3 @@ instance Pretty d => Pretty (DimIndex d) where   pretty (DimFix i) = pretty i   pretty (DimSlice i n s) = pretty i <+> ":+" <+> pretty n <+> "*" <+> pretty s---- | Like 'prettyTupleLines', but produces a 'Doc'.-ppTupleLines' :: Pretty a => [a] -> Doc b-ppTupleLines' = braces . stack . punctuate comma . map (align . pretty)
src/Futhark/IR/Prop.hs view
@@ -54,7 +54,6 @@ import Futhark.Transform.Rename (Rename, Renameable) import Futhark.Transform.Substitute (Substitutable, Substitute) import Futhark.Util (maybeNth)-import Futhark.Util.Pretty  -- | @isBuiltInFunction k@ is 'True' if @k@ is an element of 'builtInFunctions'. isBuiltInFunction :: Name -> Bool
src/Futhark/IR/Prop/Names.hs view
@@ -47,6 +47,7 @@ import Data.IntMap.Strict qualified as IM import Data.IntSet qualified as IS import Data.Map.Strict qualified as M+import Data.Set qualified as S import Futhark.IR.Prop.Patterns import Futhark.IR.Prop.Scope import Futhark.IR.Syntax@@ -213,6 +214,9 @@   freeIn' (a, b, c, d) = freeIn' a <> freeIn' b <> freeIn' c <> freeIn' d  instance FreeIn a => FreeIn [a] where+  freeIn' = foldMap freeIn'++instance FreeIn a => FreeIn (S.Set a) where   freeIn' = foldMap freeIn'  instance
src/Futhark/IR/SOACS/SOAC.hs view
@@ -69,7 +69,7 @@ import Futhark.Transform.Rename import Futhark.Transform.Substitute import Futhark.Util (chunks, maybeNth)-import Futhark.Util.Pretty (Doc, Pretty, align, comma, commasep, docText, parens, ppTuple', pretty, (<+>), (</>))+import Futhark.Util.Pretty (Doc, align, comma, commasep, docText, parens, ppTuple', pretty, (<+>), (</>)) import Futhark.Util.Pretty qualified as PP import Prelude hiding (id, (.)) 
src/Futhark/IR/SOACS/Simplify.hs view
@@ -83,12 +83,12 @@   Simplify.SimplifiableRep rep =>   Simplify.SimplifyOp rep (SOAC (Wise rep)) simplifySOAC (VJP lam arr vec) = do-  (lam', hoisted) <- Engine.simplifyLambda lam+  (lam', hoisted) <- Engine.simplifyLambda mempty lam   arr' <- mapM Engine.simplify arr   vec' <- mapM Engine.simplify vec   pure (VJP lam' arr' vec', hoisted) simplifySOAC (JVP lam arr vec) = do-  (lam', hoisted) <- Engine.simplifyLambda lam+  (lam', hoisted) <- Engine.simplifyLambda mempty lam   arr' <- mapM Engine.simplify arr   vec' <- mapM Engine.simplify vec   pure (JVP lam' arr' vec', hoisted)@@ -96,11 +96,11 @@   outerdim' <- Engine.simplify outerdim   nes' <- mapM Engine.simplify nes   arr' <- mapM Engine.simplify arr-  (lam', lam_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda lam+  (lam', lam_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda mempty lam   pure (Stream outerdim' arr' nes' lam', lam_hoisted) simplifySOAC (Scatter w ivs lam as) = do   w' <- Engine.simplify w-  (lam', hoisted) <- Engine.enterLoop $ Engine.simplifyLambda lam+  (lam', hoisted) <- Engine.enterLoop $ Engine.simplifyLambda mempty lam   ivs' <- mapM Engine.simplify ivs   as' <- mapM Engine.simplify as   pure (Scatter w' ivs' lam' as', hoisted)@@ -112,25 +112,25 @@       rf' <- Engine.simplify rf       dests' <- Engine.simplify dests       nes' <- mapM Engine.simplify nes-      (op', hoisted) <- Engine.enterLoop $ Engine.simplifyLambda op+      (op', hoisted) <- Engine.enterLoop $ Engine.simplifyLambda mempty op       pure (HistOp dests_w' rf' dests' nes' op', hoisted)   imgs' <- mapM Engine.simplify imgs-  (bfun', bfun_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda bfun+  (bfun', bfun_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda mempty bfun   pure (Hist w' imgs' ops' bfun', mconcat hoisted <> bfun_hoisted) simplifySOAC (Screma w arrs (ScremaForm scans reds map_lam)) = do   (scans', scans_hoisted) <- fmap unzip $     forM scans $ \(Scan lam nes) -> do-      (lam', hoisted) <- Engine.simplifyLambda lam+      (lam', hoisted) <- Engine.simplifyLambda mempty lam       nes' <- Engine.simplify nes       pure (Scan lam' nes', hoisted)    (reds', reds_hoisted) <- fmap unzip $     forM reds $ \(Reduce comm lam nes) -> do-      (lam', hoisted) <- Engine.simplifyLambda lam+      (lam', hoisted) <- Engine.simplifyLambda mempty lam       nes' <- Engine.simplify nes       pure (Reduce comm lam' nes', hoisted) -  (map_lam', map_lam_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda map_lam+  (map_lam', map_lam_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda mempty map_lam    (,)     <$> ( Screma
src/Futhark/IR/SegOp.hs view
@@ -6,8 +6,6 @@ -- over @iota@s (so there will be explicit indexing inside them). module Futhark.IR.SegOp   ( SegOp (..),-    SegVirt (..),-    SegSeqDims (..),     segLevel,     segBody,     segSpace,@@ -88,7 +86,6 @@ import Futhark.Util (chunks, maybeNth) import Futhark.Util.Pretty   ( Doc,-    Pretty,     apply,     hsep,     parens,@@ -436,40 +433,6 @@       onDim (dim, blk_tile, reg_tile) =         pretty dim <+> "/" <+> parens (pretty blk_tile <+> "*" <+> pretty 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--- virtualisation is an unnecessary (but generally very small)--- overhead.  This only really matters for fairly trivial but very--- wide @map@ kernels where each thread performs constant-time work on--- scalars.-data SegVirt-  = SegVirt-  | SegNoVirt-  | -- | 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 SegSeqDims-  deriving (Eq, Ord, Show)- -- | Index space of a 'SegOp'. data SegSpace = SegSpace   { -- | Flat physical index corresponding to the@@ -1134,9 +1097,10 @@  simplifyLambda ::   Engine.SimplifiableRep rep =>+  Names ->   Lambda (Wise rep) ->   Engine.SimpleM rep (Lambda (Wise rep), Stms (Wise rep))-simplifyLambda = Engine.blockMigrated . Engine.simplifyLambda+simplifyLambda bound = Engine.blockMigrated . Engine.simplifyLambda bound  segSpaceSymbolTable :: ASTRep rep => SegSpace -> ST.SymbolTable rep segSpaceSymbolTable (SegSpace flat gtids_and_dims) =@@ -1146,12 +1110,13 @@  simplifySegBinOp ::   Engine.SimplifiableRep rep =>+  VName ->   SegBinOp (Wise rep) ->   Engine.SimpleM rep (SegBinOp (Wise rep), Stms (Wise rep))-simplifySegBinOp (SegBinOp comm lam nes shape) = do+simplifySegBinOp phys_id (SegBinOp comm lam nes shape) = do   (lam', hoisted) <-     Engine.localVtable (\vtable -> vtable {ST.simplifyMemory = True}) $-      simplifyLambda lam+      simplifyLambda (oneName phys_id) lam   shape' <- Engine.simplify shape   nes' <- mapM Engine.simplify nes   pure (SegBinOp comm lam' nes' shape', hoisted)@@ -1175,7 +1140,7 @@   (lvl', space', ts') <- Engine.simplify (lvl, space, ts)   (reds', reds_hoisted) <-     Engine.localVtable (<> scope_vtable) $-      unzip <$> mapM simplifySegBinOp reds+      unzip <$> mapM (simplifySegBinOp (segFlat space)) reds   (kbody', body_hoisted) <- simplifyKernelBody space kbody    pure@@ -1189,7 +1154,7 @@   (lvl', space', ts') <- Engine.simplify (lvl, space, ts)   (scans', scans_hoisted) <-     Engine.localVtable (<> scope_vtable) $-      unzip <$> mapM simplifySegBinOp scans+      unzip <$> mapM (simplifySegBinOp (segFlat space)) scans   (kbody', body_hoisted) <- simplifyKernelBody space kbody    pure@@ -1213,7 +1178,7 @@         (lam', op_hoisted) <-           Engine.localVtable (<> scope_vtable) $             Engine.localVtable (\vtable -> vtable {ST.simplifyMemory = True}) $-              simplifyLambda lam+              simplifyLambda (oneName (segFlat space)) lam         pure           ( HistOp w' rf' arrs' nes' dims' lam',             op_hoisted
src/Futhark/IR/Syntax.hs view
@@ -100,6 +100,7 @@   ( module Language.Futhark.Core,     prettyString,     prettyText,+    Pretty,     module Futhark.IR.Rep,     module Futhark.IR.Syntax.Core, @@ -171,7 +172,7 @@ import Data.Traversable (fmapDefault, foldMapDefault) import Futhark.IR.Rep import Futhark.IR.Syntax.Core-import Futhark.Util.Pretty (prettyString, prettyText)+import Futhark.Util.Pretty (Pretty, prettyString, prettyText) import Language.Futhark.Core import Prelude hiding (id, (.)) @@ -440,7 +441,14 @@  -- | For-loop or while-loop? data LoopForm rep-  = ForLoop VName IntType SubExp [(LParam rep, VName)]+  = ForLoop+      VName+      -- ^ The loop iterator var+      IntType+      -- ^ The type of the loop iterator var+      SubExp+      -- ^ The number of iterations.+      [(LParam rep, VName)]   | WhileLoop VName  deriving instance RepTypes rep => Eq (LoopForm rep)
src/Futhark/IR/TypeCheck.hs view
@@ -57,7 +57,7 @@ import Futhark.Construct (instantiateShapes) import Futhark.IR.Aliases hiding (lookupAliases) import Futhark.Util-import Futhark.Util.Pretty (Pretty, align, docText, indent, ppTuple', pretty, (<+>), (</>))+import Futhark.Util.Pretty (align, docText, indent, ppTuple', pretty, (<+>), (</>))  -- | Information about an error during type checking.  The 'Show' -- instance for this type produces a human-readable description.@@ -384,9 +384,9 @@ checkConsumption (ConsumptionError e) = bad $ TypeError e checkConsumption (Consumption os) = pure os --- | Type check two mutually control flow branches.  Think @if@.  This--- interacts with consumption checking, as it is OK for an array to be--- consumed in both branches.+-- | Type check two mutually exclusive control flow branches.  Think+-- @if@.  This interacts with consumption checking, as it is OK for an+-- array to be consumed in both branches. alternative :: TypeM rep a -> TypeM rep b -> TypeM rep (a, b) alternative m1 m2 = do   (x, os1) <- collectOccurences m1@@ -394,6 +394,10 @@   tell $ Consumption $ os1 `altOccurences` os2   pure (x, y) +alternatives :: [TypeM rep ()] -> TypeM rep ()+alternatives [] = pure ()+alternatives (x : xs) = void $ x `alternative` alternatives xs+ -- | Permit consumption of only the specified names.  If one of these -- names is consumed, the consumption will be rewritten to be a -- consumption of the corresponding alias set.  Consumption of@@ -989,8 +993,9 @@ checkExp (BasicOp op) = checkBasicOp op checkExp (Match ses cases def_case info) = do   ses_ts <- mapM checkSubExp ses-  mapM_ (checkCase ses_ts) cases-  checkCaseBody def_case+  alternatives $+    context "in body of last case" (checkCaseBody def_case)+      : map (checkCase ses_ts) cases   where     checkVal t (Just v) = Prim (primValueType v) == t     checkVal _ Nothing = True@@ -1002,7 +1007,9 @@           </> "cannot match pattern"           </> indent 2 (ppTuple' $ map pretty vs)       context ("in body of case " <> prettyTuple vs) $ checkCaseBody body-    checkCaseBody = matchBranchType (matchReturns info)+    checkCaseBody body = do+      void $ checkBody body+      matchBranchType (matchReturns info) body checkExp (Apply fname args rettype_annot _) = do   (rettype_derived, paramtypes) <- lookupFun fname $ map fst args   argflows <- mapM (checkArg . fst) args
src/Futhark/Internalise/Defunctionalise.hs view
@@ -40,6 +40,7 @@     -- holes.)     DynamicFun (Exp, StaticVal) StaticVal   | IntrinsicSV+  | HoleSV SrcLoc   deriving (Show)  -- | The type is Just if this is a polymorphic binding that must be@@ -111,6 +112,8 @@         replaceStaticValSizes globals orig_substs sv2     IntrinsicSV ->       IntrinsicSV+    HoleSV loc ->+      HoleSV loc   where     tv substs =       identityMapper@@ -219,6 +222,7 @@     restrict' u (DynamicFun (e, sv1) sv2) =       DynamicFun (e, restrict' u sv1) $ restrict' u sv2     restrict' _ IntrinsicSV = IntrinsicSV+    restrict' _ (HoleSV loc) = HoleSV loc     restrict'' u (Binding t sv) = Binding t $ restrict' u sv  -- | Defunctionalization monad.  The Reader environment tracks both@@ -326,6 +330,8 @@   sizesToRename sv1 <> sizesToRename sv2 sizesToRename IntrinsicSV =   mempty+sizesToRename HoleSV {} =+  mempty sizesToRename Dynamic {} =   mempty sizesToRename (RecordSV fs) =@@ -498,11 +504,13 @@     IntrinsicSV -> do       (pats, body, tp) <- etaExpand (typeOf e) e       defuncExp $ Lambda pats body Nothing (Info (mempty, tp)) mempty+    HoleSV hole_loc ->+      pure (Hole (Info t) hole_loc, HoleSV hole_loc)     _ ->       let tp = typeFromSV sv        in pure (Var qn (Info tp) loc, sv) defuncExp (Hole (Info t) loc) =-  pure (Hole (Info t) loc, IntrinsicSV)+  pure (Hole (Info t) loc, HoleSV loc) defuncExp (Ascript e0 tydecl loc)   | orderZero (typeOf e0) = do       (e0', sv) <- defuncExp e0@@ -933,8 +941,18 @@       pure (apply_e, sv)     -- Propagate the 'IntrinsicsSV' until we reach the outermost application,     -- where we construct a dynamic static value with the appropriate type.-    IntrinsicSV-      | depth == 0 ->+    IntrinsicSV -> intrinsicOrHole argtypes e' sv1+    HoleSV _ -> intrinsicOrHole argtypes e' sv1+    _ ->+      error $+        "Application of an expression\n"+          ++ prettyString e1+          ++ "\nthat is neither a static lambda "+          ++ "nor a dynamic function, but has static value:\n"+          ++ show sv1+  where+    intrinsicOrHole argtypes e' sv+      | depth == 0 =           -- If the intrinsic is fully applied, then we are done.           -- Otherwise we need to eta-expand it and recursively           -- defunctionalise. XXX: might it be better to simply@@ -945,14 +963,7 @@             else do               (pats, body, tp) <- etaExpand (typeOf e') e'               defuncExp $ Lambda pats body Nothing (Info (mempty, tp)) mempty-      | otherwise -> pure (e', IntrinsicSV)-    _ ->-      error $-        "Application of an expression\n"-          ++ prettyString e1-          ++ "\nthat is neither a static lambda "-          ++ "nor a dynamic function, but has static value:\n"-          ++ show sv1+      | otherwise = pure (e', sv) defuncApply depth e@(Var qn (Info t) loc) = do   let (argtypes, _) = unfoldFunType t   sv <- lookupVar (toStruct t) (qualLeaf qn)@@ -1129,6 +1140,8 @@    in Scalar $ Sum $ M.insert name svs' $ M.fromList fields typeFromSV IntrinsicSV =   error "Tried to get the type from the static value of an intrinsic."+typeFromSV HoleSV {} =+  error "Tried to get the type from the static value of a hole."  -- | Construct the type for a fully-applied dynamic function from its -- static value and the original types of its arguments.
src/Futhark/Internalise/Defunctorise.hs view
@@ -198,21 +198,18 @@         . localScope (const f_closure) -- Start afresh.         . generating         $ do-          outer_substs <- scopeSubsts <$> askScope           abs <- asks envAbs-          let forward (k, v) = (lookupSubst k outer_substs, v)-              p_substs' = M.fromList $ map forward $ M.toList p_substs-              keep k _ = k `M.member` p_substs' || k `S.member` abs+          let keep k _ = k `M.member` p_substs || k `S.member` abs               abs_substs =                 M.filterWithKey keep $-                  M.map (`lookupSubst` scopeSubsts (modScope arg_mod)) p_substs'+                  M.map (`lookupSubst` scopeSubsts (modScope arg_mod)) p_substs                     <> scopeSubsts f_closure                     <> scopeSubsts (modScope arg_mod)           extendScope             ( Scope                 abs_substs                 ( M.singleton (modParamName f_p) $-                    substituteInMod p_substs' arg_mod+                    substituteInMod p_substs arg_mod                 )             )             $ do
src/Futhark/Internalise/Exps.hs view
@@ -349,11 +349,31 @@        -- Some functions are magical (overloaded) and we handle that here.       case () of-        -- Overloaded functions never take array arguments (except-        -- equality, but those cannot be existential), so we can safely-        -- ignore the existential dimensions.         ()-          | Just internalise <- isOverloadedFunction qfname (map fst args) loc ->+          -- Short-circuiting operators are magical.+          | baseTag (qualLeaf qfname) <= maxIntrinsicTag,+            baseString (qualLeaf qfname) == "&&",+            [(x, _), (y, _)] <- args ->+              internaliseExp desc $+                E.AppExp+                  (E.If x y (E.Literal (E.BoolValue False) mempty) mempty)+                  (Info $ AppRes (E.Scalar $ E.Prim E.Bool) [])+          | baseTag (qualLeaf qfname) <= maxIntrinsicTag,+            baseString (qualLeaf qfname) == "||",+            [(x, _), (y, _)] <- args ->+              internaliseExp desc $+                E.AppExp+                  (E.If x (E.Literal (E.BoolValue True) mempty) y mempty)+                  (Info $ AppRes (E.Scalar $ E.Prim E.Bool) [])+          -- Overloaded and intrinsic functions never take array+          -- arguments (except equality, but those cannot be+          -- existential), so we can safely ignore the existential+          -- dimensions.+          | Just internalise <- isOverloadedFunction qfname desc loc -> do+              let prepareArg (arg, _) =+                    (E.toStruct (E.typeOf arg),) <$> internaliseExp "arg" arg+              internalise =<< mapM prepareArg args+          | Just internalise <- isIntrinsicFunction qfname (map fst args) loc ->               internalise desc           | baseTag (qualLeaf qfname) <= maxIntrinsicTag,             Just (rettype, _) <- M.lookup fname I.builtInFunctions -> do@@ -1274,6 +1294,10 @@   E.PrimType ->   E.PrimType ->   InternaliseM [I.SubExp]+internaliseBinOp _ desc E.LogAnd x y E.Bool _ =+  simpleBinOp desc I.LogAnd x y+internaliseBinOp _ desc E.LogOr x y E.Bool _ =+  simpleBinOp desc I.LogOr x y internaliseBinOp _ desc E.Plus x y (E.Signed t) _ =   simpleBinOp desc (I.Add t I.OverflowWrap) x y internaliseBinOp _ desc E.Plus x y (E.Unsigned t) _ =@@ -1459,82 +1483,30 @@       rettype       =<< bodyBind body --- | Some operators and functions are overloaded or otherwise special--- - we detect and treat them here.+-- | Overloaded operators are treated here. isOverloadedFunction ::   E.QualName VName ->-  [E.Exp] ->+  String ->   SrcLoc ->-  Maybe (String -> InternaliseM [SubExp])-isOverloadedFunction qname args loc = do+  Maybe ([(E.StructType, [SubExp])] -> InternaliseM [SubExp])+isOverloadedFunction qname desc loc = do   guard $ baseTag (qualLeaf qname) <= maxIntrinsicTag-  let handlers =-        [ handleSign,-          handleIntrinsicOps,-          handleOps,-          handleSOACs,-          handleAccs,-          handleAD,-          handleRest-        ]-  msum [h args $ baseString $ qualLeaf qname | h <- handlers]+  handle $ baseString $ qualLeaf qname   where-    handleSign [x] "sign_i8" = Just $ toSigned I.Int8 x-    handleSign [x] "sign_i16" = Just $ toSigned I.Int16 x-    handleSign [x] "sign_i32" = Just $ toSigned I.Int32 x-    handleSign [x] "sign_i64" = Just $ toSigned I.Int64 x-    handleSign [x] "unsign_i8" = Just $ toUnsigned I.Int8 x-    handleSign [x] "unsign_i16" = Just $ toUnsigned I.Int16 x-    handleSign [x] "unsign_i32" = Just $ toUnsigned I.Int32 x-    handleSign [x] "unsign_i64" = Just $ toUnsigned I.Int64 x-    handleSign _ _ = Nothing--    handleIntrinsicOps [x] s-      | Just unop <- find ((== s) . prettyString) allUnOps = Just $ \desc -> do-          x' <- internaliseExp1 "x" x-          fmap pure $ letSubExp desc $ I.BasicOp $ I.UnOp unop x'-    handleIntrinsicOps [TupLit [x, y] _] s-      | Just bop <- find ((== s) . prettyString) allBinOps = Just $ \desc -> do-          x' <- internaliseExp1 "x" x-          y' <- internaliseExp1 "y" y-          fmap pure $ letSubExp desc $ I.BasicOp $ I.BinOp bop x' y'-      | Just cmp <- find ((== s) . prettyString) allCmpOps = Just $ \desc -> do-          x' <- internaliseExp1 "x" x-          y' <- internaliseExp1 "y" y-          fmap pure $ letSubExp desc $ I.BasicOp $ I.CmpOp cmp x' y'-    handleIntrinsicOps [x] s-      | Just conv <- find ((== s) . prettyString) allConvOps = Just $ \desc -> do-          x' <- internaliseExp1 "x" x-          fmap pure $ letSubExp desc $ I.BasicOp $ I.ConvOp conv x'-    handleIntrinsicOps _ _ = Nothing--    -- Short-circuiting operators are magical.-    handleOps [x, y] "&&" = Just $ \desc ->-      internaliseExp desc $-        E.AppExp-          (E.If x y (E.Literal (E.BoolValue False) mempty) mempty)-          (Info $ AppRes (E.Scalar $ E.Prim E.Bool) [])-    handleOps [x, y] "||" = Just $ \desc ->-      internaliseExp desc $-        E.AppExp-          (E.If x (E.Literal (E.BoolValue True) mempty) y mempty)-          (Info $ AppRes (E.Scalar $ E.Prim E.Bool) [])     -- Handle equality and inequality specially, to treat the case of     -- arrays.-    handleOps [xe, ye] op-      | Just cmp_f <- isEqlOp op = Just $ \desc -> do-          xe' <- internaliseExp "x" xe-          ye' <- internaliseExp "y" ye-          rs <- zipWithM (doComparison desc) xe' ye'-          cmp_f desc =<< letSubExp "eq" =<< eAll rs+    handle op+      | Just cmp_f <- isEqlOp op = Just $ \[(_, xe'), (_, ye')] -> do+          rs <- zipWithM doComparison xe' ye'+          cmp_f =<< letSubExp "eq" =<< eAll rs       where-        isEqlOp "!=" = Just $ \desc eq ->+        isEqlOp "!=" = Just $ \eq ->           letTupExp' desc $ I.BasicOp $ I.UnOp I.Not eq-        isEqlOp "==" = Just $ \_ eq ->+        isEqlOp "==" = Just $ \eq ->           pure [eq]         isEqlOp _ = Nothing -        doComparison desc x y = do+        doComparison x y = do           x_t <- I.subExpType x           y_t <- I.subExpType y           case x_t of@@ -1572,15 +1544,62 @@                letSubExp "arrays_equal"                 =<< eIf (eSubExp shapes_match) compare_elems_body (resultBodyM [constant False])-    handleOps [x, y] name+    handle name       | Just bop <- find ((name ==) . prettyString) [minBound .. maxBound :: E.BinOp] =-          Just $ \desc -> do-            x' <- internaliseExp1 "x" x-            y' <- internaliseExp1 "y" y-            case (E.typeOf x, E.typeOf y) of+          Just $ \[(x_t, [x']), (y_t, [y'])] ->+            case (x_t, y_t) of               (E.Scalar (E.Prim t1), E.Scalar (E.Prim t2)) ->                 internaliseBinOp loc desc bop x' y' t1 t2               _ -> error "Futhark.Internalise.internaliseExp: non-primitive type in BinOp."+    handle _ = Nothing++-- | Handle intrinsic functions.  These are only allowed to be called+-- in the prelude, and their internalisation may involve inspecting+-- the AST.+isIntrinsicFunction ::+  E.QualName VName ->+  [E.Exp] ->+  SrcLoc ->+  Maybe (String -> InternaliseM [SubExp])+isIntrinsicFunction qname args loc = do+  guard $ baseTag (qualLeaf qname) <= maxIntrinsicTag+  let handlers =+        [ handleSign,+          handleOps,+          handleSOACs,+          handleAccs,+          handleAD,+          handleRest+        ]+  msum [h args $ baseString $ qualLeaf qname | h <- handlers]+  where+    handleSign [x] "sign_i8" = Just $ toSigned I.Int8 x+    handleSign [x] "sign_i16" = Just $ toSigned I.Int16 x+    handleSign [x] "sign_i32" = Just $ toSigned I.Int32 x+    handleSign [x] "sign_i64" = Just $ toSigned I.Int64 x+    handleSign [x] "unsign_i8" = Just $ toUnsigned I.Int8 x+    handleSign [x] "unsign_i16" = Just $ toUnsigned I.Int16 x+    handleSign [x] "unsign_i32" = Just $ toUnsigned I.Int32 x+    handleSign [x] "unsign_i64" = Just $ toUnsigned I.Int64 x+    handleSign _ _ = Nothing++    handleOps [x] s+      | Just unop <- find ((== s) . prettyString) allUnOps = Just $ \desc -> do+          x' <- internaliseExp1 "x" x+          fmap pure $ letSubExp desc $ I.BasicOp $ I.UnOp unop x'+    handleOps [TupLit [x, y] _] s+      | Just bop <- find ((== s) . prettyString) allBinOps = Just $ \desc -> do+          x' <- internaliseExp1 "x" x+          y' <- internaliseExp1 "y" y+          fmap pure $ letSubExp desc $ I.BasicOp $ I.BinOp bop x' y'+      | Just cmp <- find ((== s) . prettyString) allCmpOps = Just $ \desc -> do+          x' <- internaliseExp1 "x" x+          y' <- internaliseExp1 "y" y+          fmap pure $ letSubExp desc $ I.BasicOp $ I.CmpOp cmp x' y'+    handleOps [x] s+      | Just conv <- find ((== s) . prettyString) allConvOps = Just $ \desc -> do+          x' <- internaliseExp1 "x" x+          fmap pure $ letSubExp desc $ I.BasicOp $ I.ConvOp conv x'     handleOps _ _ = Nothing      handleSOACs [TupLit [lam, arr] _] "map" = Just $ \desc -> do
src/Futhark/Optimise/BlkRegTiling.hs view
@@ -211,7 +211,7 @@             is_inner_coal = isInnerCoal env inp_X load_X             str_A = baseString inp_X         x_loc <--          segScatter2D (str_A ++ "_glb2loc") loc_sz_X x_loc_init' segthd_lvl [r_par, tseq_div_tpar] (t_par, t_par) $+          segScatter2D (str_A ++ "_glb2loc") loc_sz_X x_loc_init' [r_par, tseq_div_tpar] (t_par, t_par) $             scatterFun is_inner_coal          pure (x_loc, copyLoc2Reg is_inner_coal str_A x_loc)@@ -406,7 +406,8 @@             (height_A, width_B, rem_outer_dims)             code2' -        let level' = SegGroup (Count grid_size) (Count group_size) SegNoVirt+        let grid = KernelGrid (Count grid_size) (Count group_size)+            level' = SegGroup SegNoVirt (Just grid)             space' = SegSpace gid_flat (rem_outer_dims ++ [(gid_t, gridDim_t), (gid_y, gridDim_y), (gid_x, gridDim_x)])             kbody' = KernelBody () stms_seggroup ret_seggroup         pure $ Let pat aux $ Op $ SegOp $ SegMap level' space' ts kbody'@@ -576,7 +577,8 @@             (height_A, width_B, rem_outer_dims)             code2' -        let level' = SegGroup (Count grid_size) (Count group_size) SegNoVirt+        let grid = KernelGrid (Count grid_size) (Count group_size)+            level' = SegGroup SegNoVirt (Just grid)             space' = SegSpace gid_flat (rem_outer_dims ++ [(gid_y, gridDim_y), (gid_x, gridDim_x)])             kbody' = KernelBody () stms_seggroup ret_seggroup         pure $ Let pat aux $ Op $ SegOp $ SegMap level' space' ts kbody'@@ -770,7 +772,7 @@ mkNewSegthdLvl tx ty grid_pexp = do   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 (SegSeqDims []))+  let segthd_lvl = SegThreadInGroup (SegNoVirtFull (SegSeqDims []))   pure (grid_size, group_size, segthd_lvl)  mkGidsXYF :: Builder GPU (VName, VName, VName)@@ -1084,7 +1086,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 (SegSeqDims []))+        let segthd_lvl = SegThreadInGroup (SegNoVirtFull (SegSeqDims []))          count_shmem <- letSubExp "count_shmem" =<< ceilDiv rz group_size @@ -1285,7 +1287,8 @@            pure $ map (RegTileReturns mempty regtile_ret_dims) epilogue_res'         -- END (ret_seggroup, stms_seggroup) <- runBuilder $ do-        let level' = SegGroup (Count grid_size) (Count group_size) SegNoVirt+        let grid = KernelGrid (Count grid_size) (Count group_size)+            level' = SegGroup SegNoVirt (Just grid)             space' = SegSpace gid_flat (rem_outer_dims ++ [(gid_z, gridDim_z), (gid_y, gridDim_y), (gid_x, gridDim_x)])             kbody' = KernelBody () stms_seggroup ret_seggroup 
src/Futhark/Optimise/Fusion/GraphRep.hs view
@@ -39,10 +39,12 @@      -- * Construction     mkDepGraph,+    mkDepGraphForFun,     pprg,   ) where +import Control.Monad.Reader import Data.Bifunctor (bimap) import Data.Foldable (foldlM) import Data.Graph.Inductive.Dot qualified as G@@ -330,6 +332,12 @@         makeAliasTable (bodyStms body),         initialGraphConstruction       ]++-- | Make a dependency graph corresponding to a function.+mkDepGraphForFun :: FunDef SOACS -> DepGraph+mkDepGraphForFun f = runReader (mkDepGraph (funDefBody f)) scope+  where+    scope = scopeOfFParams (funDefParams f) <> scopeOf (bodyStms (funDefBody f))  -- | Merges two contexts. mergedContext :: Ord b => a -> G.Context a b -> G.Context a b -> G.Context a b
src/Futhark/Optimise/GenRedOpt.hs view
@@ -89,12 +89,9 @@         Just stms_after -> pure $ Just $ stms_before <> stms_after         Nothing -> pure $ Just $ stms_before <> oneStm ker_snd -se1 :: SubExp-se1 = intConst Int64 1- genRed2Tile2d :: Env -> Stm GPU -> GenRedM (Maybe (Stms GPU, Stm GPU)) genRed2Tile2d env kerstm@(Let pat_ker aux (Op (SegOp (SegMap seg_thd seg_space kres_tps old_kbody))))-  | (SegThread _ seg_group_size _novirt) <- seg_thd,+  | SegThread _novirt _ <- seg_thd,     -- novirt == SegNoVirtFull || novirt == SegNoVirt,     KernelBody () kstms kres <- old_kbody,     Just (css, r_ses) <- allGoodReturns kres,@@ -161,11 +158,7 @@       gid_flat_1 <- newVName "gid_flat"       let space1 = SegSpace gid_flat_1 gid_dims_new -      (grid_size, host_stms1) <- runBuilder $ do-        let grid_pexp = foldl (\x d -> x * pe64 d) (pe64 se1) $ map snd gid_dims_new-        dim_prod <- letSubExp "dim_prod" =<< toExp grid_pexp-        letSubExp "grid_size" =<< ceilDiv dim_prod (unCount seg_group_size)-      let level1 = SegThread (Count grid_size) seg_group_size (SegNoVirtFull (SegSeqDims [])) -- novirt ?+      let level1 = SegThread (SegNoVirtFull (SegSeqDims [])) Nothing -- novirt ?           kbody1 = KernelBody () ker1_stms [Returns ResultMaySimplify (Certs []) k1_res]        -- is it OK here to use the "aux" from the parrent kernel?@@ -177,7 +170,7 @@       ker2_exp <- renameExp $ Op (SegOp (SegMap seg_thd seg_space kres_tps ker2_body))       let ker2 = Let pat_ker aux ker2_exp       pure $-        Just (code1_tr_host <> host_stms1 <> oneStm ker1, ker2)+        Just (code1_tr_host <> oneStm ker1, ker2)   where     isIndVarToParDim _ (Constant _) _ = False     isIndVarToParDim variance (Var acc_ind) par_dim =@@ -198,7 +191,6 @@               (reverse acc_inds)        in invar_dims ++ inner_dims     ---    ceilDiv x y = pure $ BasicOp $ BinOp (SDivUp Int64 Unsafe) x y     getAccLambda acc_tp =       case acc_tp of         (Acc tp_id _shp el_tps _) ->
src/Futhark/Optimise/ReduceDeviceSyncs/MigrationTable.hs view
@@ -1108,10 +1108,7 @@     collectHostOp (OtherOp op) = collectFree op     collectHostOp GPUBody {} = pure () -    collectSegLevel (SegThread (Count num) (Count size) _) =-      collectSubExp num >> collectSubExp size-    collectSegLevel (SegGroup (Count num) (Count size) _) =-      collectSubExp num >> collectSubExp size+    collectSegLevel = mapM_ captureName . namesToList . freeIn      collectSegSpace space =       mapM_ collectSubExp (segSpaceDims space)
src/Futhark/Optimise/Simplify/Engine.hs view
@@ -452,7 +452,7 @@   UT.UsageTable ->   SimpleM rep (Stms (Wise rep), Stm (Wise rep)) recSimplifyStm (Let pat (StmAux cs attrs (_, dec)) e) usage = do-  ((e', e_hoisted), e_cs) <- collectCerts $ simplifyExp usage pat e+  ((e', e_hoisted), e_cs) <- collectCerts $ simplifyExp (usage <> UT.usageInPat pat) pat e   let aux' = StmAux (cs <> e_cs) attrs dec   pure (e_hoisted, mkWiseStm (removePatWisdom pat) aux' e') @@ -666,8 +666,8 @@   all (`nameIn` ST.availableAtClosestLoop vtable) . namesToList . freeIn  matchBlocker ::-  (ASTRep rep, CanBeWise (Op rep), FreeIn a) =>-  a ->+  (ASTRep rep, CanBeWise (Op rep)) =>+  [SubExp] ->   MatchDec rt ->   SimpleM rep (BlockPred (Wise rep)) matchBlocker cond (MatchDec _ ifsort) = do@@ -896,7 +896,7 @@       Nothing ->         pure (Nothing, mempty)       Just (op_lam, nes) -> do-        (op_lam', op_lam_stms) <- blockMigrated (simplifyLambda op_lam)+        (op_lam', op_lam_stms) <- blockMigrated (simplifyLambda mempty op_lam)         nes' <- simplify nes         pure (Just (op_lam', nes'), op_lam_stms)     (,op_stms) <$> ((,,op') <$> simplify shape <*> simplify arrs)@@ -1063,11 +1063,12 @@  simplifyLambda ::   SimplifiableRep rep =>+  Names ->   Lambda (Wise rep) ->   SimpleM rep (Lambda (Wise rep), Stms (Wise rep))-simplifyLambda lam = do+simplifyLambda extra_bound lam = do   par_blocker <- asksEngineEnv $ blockHoistPar . envHoistBlockers-  simplifyLambdaMaybeHoist par_blocker mempty lam+  simplifyLambdaMaybeHoist (par_blocker `orIf` hasFree extra_bound) mempty lam  simplifyLambdaNoHoisting ::   SimplifiableRep rep =>
src/Futhark/Optimise/Simplify/Rules/Loop.hs view
@@ -238,34 +238,6 @@     notIndex _ = True simplifyLoopVariables _ _ _ _ = Skip --- If a for-loop with no loop variables has a counter of type Int64,--- and the bound is just a constant or sign-extended integer of--- smaller type, then change the loop to iterate over the smaller type--- instead.  We then move the sign extension inside the loop instead.--- This addresses loops of the form @for i in x..<y@ in the source--- language.-narrowLoopType :: (BuilderOps rep) => TopDownRuleDoLoop rep-narrowLoopType vtable pat aux (merge, ForLoop i Int64 n [], body)-  | Just (n', it', cs) <- smallerType =-      Simplify $ do-        i' <- newVName $ baseString i-        let form' = ForLoop i' it' n' []-        body' <- insertStmsM . inScopeOf form' $ do-          letBindNames [i] $ BasicOp $ ConvOp (SExt it' Int64) (Var i')-          pure body-        auxing aux $ certifying cs $ letBind pat $ DoLoop merge form' body'-  where-    smallerType-      | Var n' <- n,-        Just (ConvOp (SExt it' _) n'', cs) <- ST.lookupBasicOp n' vtable =-          Just (n'', it', cs)-      | Constant (IntValue (Int64Value n')) <- n,-        toInteger n' <= toInteger (maxBound :: Int32) =-          Just (intConst Int32 (toInteger n'), Int32, mempty)-      | otherwise =-          Nothing-narrowLoopType _ _ _ _ = Skip- unroll ::   BuilderOps rep =>   Integer ->@@ -313,8 +285,7 @@   [ RuleDoLoop hoistLoopInvariantMergeVariables,     RuleDoLoop simplifyClosedFormLoop,     RuleDoLoop simplifyKnownIterationLoop,-    RuleDoLoop simplifyLoopVariables,-    RuleDoLoop narrowLoopType+    RuleDoLoop simplifyLoopVariables   ]  bottomUpRules :: BuilderOps rep => [BottomUpRule rep]
src/Futhark/Optimise/TileLoops.hs view
@@ -126,13 +126,12 @@         not $ null $ tiledInputs inputs,         gtid_y : gtid_x : top_gtids_rev <- reverse gtids,         kdim_y : kdim_x : top_kdims_rev <- reverse kdims,-        (prestms', poststms') <-+        Just (prestms', poststms') <-           preludeToPostlude variance prestms stm_to_tile (stmsFromList poststms),         used <- freeIn stm_to_tile <> freeIn poststms' <> freeIn stms_res =           Just . injectPrelude initial_space variance prestms' used             <$> tileGeneric               (tiling2d $ reverse $ zip top_gtids_rev top_kdims_rev)-              initial_lvl               res_ts               (stmPat stm_to_tile)               (gtid_x, gtid_y)@@ -148,13 +147,12 @@         inputs <- map (is1DTileable gtid variance) arrs,         not $ null $ tiledInputs inputs,         gtid `notNameIn` branch_variant,-        (prestms', poststms') <-+        Just (prestms', poststms') <-           preludeToPostlude variance prestms stm_to_tile (stmsFromList poststms),         used <- freeIn stm_to_tile <> freeIn poststms' <> freeIn stms_res =           Just . injectPrelude initial_space variance prestms' used             <$> tileGeneric               (tiling1d $ reverse top_space_rev)-              initial_lvl               res_ts               (stmPat stm_to_tile)               gtid@@ -167,7 +165,7 @@       -- Tiling inside for-loop.       | DoLoop merge (ForLoop i it bound []) loopbody <- stmExp stm_to_tile,         not $ any ((`nameIn` freeIn merge) . paramName . fst) merge,-        (prestms', poststms') <-+        Just (prestms', poststms') <-           preludeToPostlude variance prestms stm_to_tile (stmsFromList poststms) = do           let branch_variant' =                 branch_variant@@ -214,15 +212,22 @@             descend (prestms <> oneStm stm_to_tile) poststms  -- | Move statements from prelude to postlude if they are not used in--- the tiled statement anyway.+-- the tiled statement anyway.  Also, fail if the provided Stm uses+-- anything from the resulting prelude whose size is not free in the+-- prelude. preludeToPostlude ::   VarianceTable ->   Stms GPU ->   Stm GPU ->   Stms GPU ->-  (Stms GPU, Stms GPU)-preludeToPostlude variance prelude stm_to_tile postlude =-  (prelude_used, prelude_not_used <> postlude)+  Maybe (Stms GPU, Stms GPU)+preludeToPostlude variance prelude stm_to_tile postlude = do+  let prelude_sizes =+        freeIn $ foldMap (patTypes . stmPat) prelude_used+      prelude_bound =+        namesFromList $ foldMap (patNames . stmPat) prelude_used+  guard $ not $ prelude_sizes `namesIntersect` prelude_bound+  Just (prelude_used, prelude_not_used <> postlude)   where     used_in_tiled = freeIn stm_to_tile @@ -404,7 +409,7 @@         mergeinit' <-           fmap (map Var) $             certifying (stmAuxCerts aux) $-              tilingSegMap tiling "tiled_loopinit" (scalarLevel tiling) ResultPrivate $+              tilingSegMap tiling "tiled_loopinit" ResultPrivate $                 \in_bounds slice ->                   fmap varsRes $                     protectOutOfBounds "loopinit" in_bounds merge_ts $ do@@ -428,8 +433,7 @@          loopbody' <-           localScope (scopeOfFParams mergeparams') . runBodyBuilder $-            resultBody . map Var-              <$> tiledBody private' privstms'+            resultBody . map Var <$> tiledBody private' privstms'         accs' <-           letTupExp "tiled_inside_loop" $             DoLoop merge' (ForLoop i it bound []) loopbody'@@ -447,13 +451,12 @@ doPrelude :: Tiling -> PrivStms -> Stms GPU -> [VName] -> Builder GPU [VName] doPrelude tiling privstms prestms prestms_live =   -- Create a SegMap that takes care of the prelude for every thread.-  tilingSegMap tiling "prelude" (scalarLevel tiling) ResultPrivate $-    \in_bounds slice -> do-      ts <- mapM lookupType prestms_live-      fmap varsRes . protectOutOfBounds "pre" in_bounds ts $ do-        addPrivStms slice privstms-        addStms prestms-        pure $ varsRes prestms_live+  tilingSegMap tiling "prelude" ResultPrivate $ \in_bounds slice -> do+    ts <- mapM lookupType prestms_live+    fmap varsRes . protectOutOfBounds "pre" in_bounds ts $ do+      addPrivStms slice privstms+      addStms prestms+      pure $ varsRes prestms_live  liveSet :: FreeIn a => Stms GPU -> a -> Names liveSet stms after =@@ -578,7 +581,6 @@ data Tiling = Tiling   { tilingSegMap ::       String ->-      SegLevel ->       ResultManifest ->       (PrimExp VName -> [DimIndex SubExp] -> Builder GPU Result) ->       Builder GPU [VName],@@ -604,13 +606,7 @@   }  type DoTiling gtids kdims =-  SegLevel -> gtids -> kdims -> SubExp -> Builder GPU Tiling--scalarLevel :: Tiling -> SegLevel-scalarLevel tiling =-  SegThread (segNumGroups lvl) (segGroupSize lvl) SegNoVirt-  where-    lvl = tilingLevel tiling+  gtids -> kdims -> SubExp -> Builder GPU Tiling  protectOutOfBounds ::   String ->@@ -643,7 +639,7 @@   [Type] ->   Builder GPU [VName] postludeGeneric tiling privstms pat accs' poststms poststms_res res_ts =-  tilingSegMap tiling "thread_res" (scalarLevel tiling) ResultPrivate $ \in_bounds slice -> do+  tilingSegMap tiling "thread_res" ResultPrivate $ \in_bounds slice -> do     -- Read our per-thread result from the tiled loop.     forM_ (zip (patNames pat) accs') $ \(us, everyone) -> do       everyone_t <- lookupType everyone@@ -664,7 +660,6 @@  tileGeneric ::   DoTiling gtids kdims ->-  SegLevel ->   [Type] ->   Pat Type ->   gtids ->@@ -675,8 +670,8 @@   Stms GPU ->   Result ->   TileM (Stms GPU, Tiling, TiledBody)-tileGeneric doTiling initial_lvl res_ts pat gtids kdims w form inputs poststms poststms_res = do-  (tiling, tiling_stms) <- runBuilder $ doTiling initial_lvl gtids kdims w+tileGeneric doTiling res_ts pat gtids kdims w form inputs poststms poststms_res = do+  (tiling, tiling_stms) <- runBuilder $ doTiling gtids kdims w    pure (tiling_stms, tiling, tiledBody tiling)   where@@ -690,7 +685,7 @@        -- We don't use a Replicate here, because we want to enforce a       -- scalar memory space.-      mergeinits <- tilingSegMap tiling "mergeinit" (scalarLevel tiling) ResultPrivate $ \in_bounds slice ->+      mergeinits <- tilingSegMap tiling "mergeinit" ResultPrivate $ \in_bounds slice ->         -- Constant neutral elements (a common case) do not need protection from OOB.         if freeIn red_nes == mempty           then pure $ subExpsRes red_nes@@ -736,10 +731,9 @@  mkReadPreludeValues :: [VName] -> [VName] -> ReadPrelude mkReadPreludeValues prestms_live_arrs prestms_live slice =-  fmap mconcat $-    forM (zip prestms_live_arrs prestms_live) $ \(arr, v) -> do-      arr_t <- lookupType arr-      letBindNames [v] $ BasicOp $ Index arr $ fullSlice arr_t slice+  fmap mconcat . forM (zip prestms_live_arrs prestms_live) $ \(arr, v) -> do+    arr_t <- lookupType arr+    letBindNames [v] $ BasicOp $ Index arr $ fullSlice arr_t slice  tileReturns :: [(VName, SubExp)] -> [(SubExp, SubExp)] -> VName -> Builder GPU KernelResult tileReturns dims_on_top dims arr = do@@ -776,16 +770,15 @@   SubExp ->   VName ->   VName ->-  Count NumGroups SubExp ->-  Count GroupSize SubExp ->+  KernelGrid ->   TileKind ->   PrivStms ->   SubExp ->   [InputArray] ->   Builder GPU [InputTile]-readTile1D tile_size gid gtid num_groups group_size kind privstms tile_id inputs =+readTile1D tile_size gid gtid (KernelGrid _num_groups group_size) kind privstms tile_id inputs =   fmap (inputsToTiles inputs)-    . segMap1D "full_tile" lvl ResultNoSimplify+    . segMap1D "full_tile" lvl ResultNoSimplify tile_size     $ \ltid -> do       j <-         letSubExp "j"@@ -813,18 +806,17 @@           TileFull ->             mapM readTileElem arrs   where-    lvl = SegThread num_groups group_size SegNoVirt+    lvl = SegThreadInGroup SegNoVirt  processTile1D ::   VName ->   VName ->   SubExp ->   SubExp ->-  Count NumGroups SubExp ->-  Count GroupSize SubExp ->+  KernelGrid ->   ProcessTileArgs ->   Builder GPU [VName]-processTile1D gid gtid kdim tile_size num_groups group_size tile_args = do+processTile1D gid gtid kdim tile_size (KernelGrid _num_groups group_size) tile_args = do   let red_comm = processComm tile_args       privstms = processPrivStms tile_args       map_lam = processMapLam tile_args@@ -833,7 +825,7 @@       tile_id = processTileId tile_args       accs = processAcc tile_args -  segMap1D "acc" lvl ResultPrivate $ \ltid -> do+  segMap1D "acc" lvl ResultPrivate (unCount group_size) $ \ltid -> do     reconstructGtids1D group_size gtid gid ltid     addPrivStms [DimFix $ Var ltid] privstms @@ -857,18 +849,17 @@           (eBody [pure $ Op $ OtherOp $ Screma tile_size tiles' form'])           (resultBodyM thread_accs)   where-    lvl = SegThread num_groups group_size SegNoVirt+    lvl = SegThreadInGroup SegNoVirt  processResidualTile1D ::   VName ->   VName ->   SubExp ->   SubExp ->-  Count NumGroups SubExp ->-  Count GroupSize SubExp ->+  KernelGrid ->   ResidualTileArgs ->   Builder GPU [VName]-processResidualTile1D gid gtid kdim tile_size num_groups group_size args = do+processResidualTile1D gid gtid kdim tile_size grid args = do   -- The number of residual elements that are not covered by   -- the whole tiles.   residual_input <-@@ -899,8 +890,7 @@           tile_size           gid           gtid-          num_groups-          group_size+          grid           TilePartial           privstms           num_whole_tiles@@ -921,61 +911,52 @@       let tile_args =             ProcessTileArgs privstms red_comm red_lam map_lam tiles accs num_whole_tiles       resultBody . map Var-        <$> processTile1D gid gtid kdim residual_input num_groups group_size tile_args+        <$> processTile1D gid gtid kdim residual_input grid tile_args  tiling1d :: [(VName, SubExp)] -> DoTiling VName SubExp-tiling1d dims_on_top initial_lvl gtid kdim w = do+tiling1d dims_on_top gtid kdim w = do   gid <- newVName "gid"   gid_flat <- newVName "gid_flat" -  (lvl, space) <--    if null dims_on_top-      then-        pure-          ( SegGroup (segNumGroups initial_lvl) (segGroupSize initial_lvl) $ segVirt initial_lvl,-            SegSpace gid_flat [(gid, unCount $ segNumGroups initial_lvl)]-          )-      else do-        group_size <--          letSubExp "computed_group_size" $-            BasicOp $-              BinOp (SMin Int64) (unCount (segGroupSize initial_lvl)) kdim+  tile_size_key <- nameFromString . prettyString <$> newVName "tile_size"+  tile_size <- letSubExp "tile_size" $ Op $ SizeOp $ GetSize tile_size_key SizeGroup+  let group_size = tile_size -        -- How many groups we need to exhaust the innermost dimension.-        ldim <--          letSubExp "ldim" $-            BasicOp $-              BinOp (SDivUp Int64 Unsafe) kdim group_size+  (grid, space) <- do+    -- How many groups we need to exhaust the innermost dimension.+    ldim <-+      letSubExp "ldim" . BasicOp $+        BinOp (SDivUp Int64 Unsafe) kdim group_size -        num_groups <--          letSubExp "computed_num_groups"-            =<< foldBinOp (Mul Int64 OverflowUndef) ldim (map snd dims_on_top)+    num_groups <-+      letSubExp "computed_num_groups"+        =<< foldBinOp (Mul Int64 OverflowUndef) ldim (map snd dims_on_top) -        pure-          ( SegGroup (Count num_groups) (Count group_size) SegNoVirt,-            SegSpace gid_flat $ dims_on_top ++ [(gid, ldim)]-          )-  let tile_size = unCount $ segGroupSize lvl+    pure+      ( KernelGrid (Count num_groups) (Count group_size),+        SegSpace gid_flat $ dims_on_top ++ [(gid, ldim)]+      )+  let tiling_lvl = SegThreadInGroup SegNoVirt    pure     Tiling-      { tilingSegMap = \desc lvl' manifest f -> segMap1D desc lvl' manifest $ \ltid -> do+      { tilingSegMap = \desc manifest f -> segMap1D desc tiling_lvl manifest tile_size $ \ltid -> do           letBindNames [gtid]             =<< toExp (le64 gid * pe64 tile_size + le64 ltid)           f (untyped $ le64 gtid .<. pe64 kdim) [DimFix $ Var ltid],         tilingReadTile =-          readTile1D tile_size gid gtid (segNumGroups lvl) (segGroupSize lvl),+          readTile1D tile_size gid gtid grid,         tilingProcessTile =-          processTile1D gid gtid kdim tile_size (segNumGroups lvl) (segGroupSize lvl),+          processTile1D gid gtid kdim tile_size grid,         tilingProcessResidualTile =-          processResidualTile1D gid gtid kdim tile_size (segNumGroups lvl) (segGroupSize lvl),+          processResidualTile1D gid gtid kdim tile_size grid,         tilingTileReturns = tileReturns dims_on_top [(kdim, tile_size)],         tilingTileShape = Shape [tile_size],         tilingNumWholeTiles =           letSubExp "num_whole_tiles" $             BasicOp $               BinOp (SQuot Int64 Unsafe) w tile_size,-        tilingLevel = lvl,+        tilingLevel = SegGroup SegNoVirt (Just grid),         tilingSpace = space       } @@ -1015,18 +996,16 @@   (VName, VName) ->   (VName, VName) ->   SubExp ->-  Count NumGroups SubExp ->-  Count GroupSize SubExp ->   TileKind ->   PrivStms ->   SubExp ->   [InputArray] ->   Builder GPU [InputTile]-readTile2D (kdim_x, kdim_y) (gtid_x, gtid_y) (gid_x, gid_y) tile_size num_groups group_size kind privstms tile_id inputs =+readTile2D (kdim_x, kdim_y) (gtid_x, gtid_y) (gid_x, gid_y) tile_size kind privstms tile_id inputs =   fmap (inputsToTiles inputs)     . segMap2D       "full_tile"-      (SegThread num_groups group_size (SegNoVirtFull (SegSeqDims [])))+      (SegThread (SegNoVirtFull (SegSeqDims [])) Nothing)       ResultNoSimplify       (tile_size, tile_size)     $ \(ltid_x, ltid_y) -> do@@ -1088,11 +1067,9 @@   (VName, VName) ->   (SubExp, SubExp) ->   SubExp ->-  Count NumGroups SubExp ->-  Count GroupSize SubExp ->   ProcessTileArgs ->   Builder GPU [VName]-processTile2D (gid_x, gid_y) (gtid_x, gtid_y) (kdim_x, kdim_y) tile_size num_groups group_size tile_args = do+processTile2D (gid_x, gid_y) (gtid_x, gtid_y) (kdim_x, kdim_y) tile_size tile_args = do   let privstms = processPrivStms tile_args       red_comm = processComm tile_args       red_lam = processRedLam tile_args@@ -1106,7 +1083,7 @@    segMap2D     "acc"-    (SegThread num_groups group_size (SegNoVirtFull (SegSeqDims [])))+    (SegThreadInGroup (SegNoVirtFull (SegSeqDims [])))     ResultPrivate     (tile_size, tile_size)     $ \(ltid_x, ltid_y) -> do@@ -1146,82 +1123,69 @@   (VName, VName) ->   (SubExp, SubExp) ->   SubExp ->-  Count NumGroups SubExp ->-  Count GroupSize SubExp ->   ResidualTileArgs ->   Builder GPU [VName]-processResidualTile2D-  gids-  gtids-  kdims-  tile_size-  num_groups-  group_size-  args = do-    -- The number of residual elements that are not covered by-    -- the whole tiles.-    residual_input <--      letSubExp "residual_input" $-        BasicOp $-          BinOp (SRem Int64 Unsafe) w tile_size+processResidualTile2D gids gtids kdims tile_size args = do+  -- The number of residual elements that are not covered by+  -- the whole tiles.+  residual_input <-+    letSubExp "residual_input" $+      BasicOp $+        BinOp (SRem Int64 Unsafe) w tile_size -    letTupExp "acc_after_residual"-      =<< eIf-        (toExp $ pe64 residual_input .==. 0)-        (resultBodyM $ map Var accs)-        (nonemptyTile residual_input)-    where-      privstms = residualPrivStms args-      red_comm = residualComm args-      red_lam = residualRedLam args-      map_lam = residualMapLam args-      accs = residualAcc args-      inputs = residualInput args-      num_whole_tiles = residualNumWholeTiles args-      w = residualInputSize args+  letTupExp "acc_after_residual"+    =<< eIf+      (toExp $ pe64 residual_input .==. 0)+      (resultBodyM $ map Var accs)+      (nonemptyTile residual_input)+  where+    privstms = residualPrivStms args+    red_comm = residualComm args+    red_lam = residualRedLam args+    map_lam = residualMapLam args+    accs = residualAcc args+    inputs = residualInput args+    num_whole_tiles = residualNumWholeTiles args+    w = residualInputSize args -      nonemptyTile residual_input = renameBody <=< runBodyBuilder $ do-        -- Collectively construct a tile.  Threads that are out-of-bounds-        -- provide a blank dummy value.-        full_tile <--          readTile2D-            kdims-            gtids-            gids-            tile_size-            num_groups-            group_size-            TilePartial-            privstms-            num_whole_tiles-            inputs+    nonemptyTile residual_input = renameBody <=< runBodyBuilder $ do+      -- Collectively construct a tile.  Threads that are out-of-bounds+      -- provide a blank dummy value.+      full_tile <-+        readTile2D+          kdims+          gtids+          gids+          tile_size+          TilePartial+          privstms+          num_whole_tiles+          inputs -        let slice =-              DimSlice (intConst Int64 0) residual_input (intConst Int64 1)-        tiles <- forM full_tile $ \case-          InputTiled perm tile' ->-            InputTiled perm-              <$> letExp "partial_tile" (BasicOp $ Index tile' (Slice [slice, slice]))-          InputUntiled arr ->-            pure $ InputUntiled arr+      let slice =+            DimSlice (intConst Int64 0) residual_input (intConst Int64 1)+      tiles <- forM full_tile $ \case+        InputTiled perm tile' ->+          InputTiled perm+            <$> letExp "partial_tile" (BasicOp $ Index tile' (Slice [slice, slice]))+        InputUntiled arr ->+          pure $ InputUntiled arr -        let tile_args =-              ProcessTileArgs privstms red_comm red_lam map_lam tiles accs num_whole_tiles+      let tile_args =+            ProcessTileArgs privstms red_comm red_lam map_lam tiles accs num_whole_tiles -        -- Now each thread performs a traversal of the tile and-        -- updates its accumulator.-        resultBody . map Var-          <$> processTile2D-            gids-            gtids-            kdims-            tile_size-            num_groups-            group_size-            tile_args+      -- Now each thread performs a traversal of the tile and+      -- updates its accumulator.+      resultBody . map Var+        <$> processTile2D+          gids+          gtids+          kdims+          tile_size+          tile_args  tiling2d :: [(VName, SubExp)] -> DoTiling (VName, VName) (SubExp, SubExp)-tiling2d dims_on_top _initial_lvl (gtid_x, gtid_y) (kdim_x, kdim_y) w = do+tiling2d dims_on_top (gtid_x, gtid_y) (kdim_x, kdim_y) w = do   gid_x <- newVName "gid_x"   gid_y <- newVName "gid_y" @@ -1246,24 +1210,26 @@         (num_groups_y : map snd dims_on_top)    gid_flat <- newVName "gid_flat"-  let lvl = SegGroup (Count num_groups) (Count group_size) (SegNoVirtFull (SegSeqDims []))+  let grid = KernelGrid (Count num_groups) (Count group_size)+      lvl = SegGroup (SegNoVirtFull (SegSeqDims [])) (Just grid)       space =         SegSpace gid_flat $           dims_on_top ++ [(gid_x, num_groups_x), (gid_y, num_groups_y)]+      tiling_lvl = SegThreadInGroup SegNoVirt    pure     Tiling-      { tilingSegMap = \desc lvl' manifest f ->-          segMap2D desc lvl' manifest (tile_size, tile_size) $ \(ltid_x, ltid_y) -> do+      { tilingSegMap = \desc manifest f ->+          segMap2D desc tiling_lvl manifest (tile_size, tile_size) $ \(ltid_x, ltid_y) -> do             reconstructGtids2D tile_size (gtid_x, gtid_y) (gid_x, gid_y) (ltid_x, ltid_y)             f               ( untyped $                   le64 gtid_x .<. pe64 kdim_x .&&. le64 gtid_y .<. pe64 kdim_y               )               [DimFix $ Var ltid_x, DimFix $ Var ltid_y],-        tilingReadTile = readTile2D (kdim_x, kdim_y) (gtid_x, gtid_y) (gid_x, gid_y) tile_size (segNumGroups lvl) (segGroupSize lvl),-        tilingProcessTile = processTile2D (gid_x, gid_y) (gtid_x, gtid_y) (kdim_x, kdim_y) tile_size (segNumGroups lvl) (segGroupSize lvl),-        tilingProcessResidualTile = processResidualTile2D (gid_x, gid_y) (gtid_x, gtid_y) (kdim_x, kdim_y) tile_size (segNumGroups lvl) (segGroupSize lvl),+        tilingReadTile = readTile2D (kdim_x, kdim_y) (gtid_x, gtid_y) (gid_x, gid_y) tile_size,+        tilingProcessTile = processTile2D (gid_x, gid_y) (gtid_x, gtid_y) (kdim_x, kdim_y) tile_size,+        tilingProcessResidualTile = processResidualTile2D (gid_x, gid_y) (gtid_x, gtid_y) (kdim_x, kdim_y) tile_size,         tilingTileReturns = tileReturns dims_on_top [(kdim_x, tile_size), (kdim_y, tile_size)],         tilingTileShape = Shape [tile_size, tile_size],         tilingNumWholeTiles =
src/Futhark/Optimise/TileLoops/Shared.hs view
@@ -85,12 +85,13 @@   String ->   SegLevel ->   ResultManifest ->+  SubExp -> -- dim_x   (VName -> Builder GPU Result) ->   Builder GPU [VName]-segMap1D desc lvl manifest f = do+segMap1D desc lvl manifest w f = do   ltid <- newVName "ltid"   ltid_flat <- newVName "ltid_flat"-  let space = SegSpace ltid_flat [(ltid, unCount $ segGroupSize lvl)]+  let space = SegSpace ltid_flat [(ltid, w)]    ((ts, res), stms) <- localScope (scopeOfSegSpace space) . runBuilder $ do     res <- f ltid@@ -164,12 +165,11 @@   String ->   SubExp ->   VName ->-  SegLevel -> -- lvl   [SubExp] -> -- dims of sequential loop on top   (SubExp, SubExp) -> -- (dim_y, dim_x)   ([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+segScatter2D desc arr_size updt_arr seq_dims (dim_x, dim_y) f = do   ltid_flat <- newVName "ltid_flat"   ltid_y <- newVName "ltid_y"   ltid_x <- newVName "ltid_x"@@ -178,10 +178,8 @@   let seq_space = zip seq_is seq_dims    let segspace = SegSpace ltid_flat $ seq_space ++ [(ltid_y, dim_y), (ltid_x, dim_x)]-      lvl' =-        SegThread-          (segNumGroups lvl)-          (segGroupSize lvl)+      lvl =+        SegThreadInGroup           (SegNoVirtFull (SegSeqDims [0 .. length seq_dims - 1]))    ((t_v, res_v, res_i), stms) <- runBuilder $ do@@ -194,7 +192,7 @@   let ret = WriteReturns mempty (Shape [arr_size]) updt_arr [(Slice [DimFix res_i], res_v)]   let body = KernelBody () stms [ret] -  letExp 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
src/Futhark/Pass/ExpandAllocations.hs view
@@ -110,33 +110,33 @@  transformExp :: Exp GPUMem -> ExpandM (Stms GPUMem, Exp GPUMem) transformExp (Op (Inner (SegOp (SegMap lvl space ts kbody)))) = do-  (alloc_stms, (_, kbody')) <- transformScanRed lvl space [] kbody+  (alloc_stms, (lvl', _, kbody')) <- transformScanRed lvl space [] kbody   pure     ( alloc_stms,-      Op $ Inner $ SegOp $ SegMap lvl space ts kbody'+      Op $ Inner $ SegOp $ SegMap lvl' space ts kbody'     ) transformExp (Op (Inner (SegOp (SegRed lvl space reds ts kbody)))) = do-  (alloc_stms, (lams, kbody')) <-+  (alloc_stms, (lvl', lams, kbody')) <-     transformScanRed lvl space (map segBinOpLambda reds) kbody   let reds' = zipWith (\red lam -> red {segBinOpLambda = lam}) reds lams   pure     ( alloc_stms,-      Op $ Inner $ SegOp $ SegRed lvl space reds' ts kbody'+      Op $ Inner $ SegOp $ SegRed lvl' space reds' ts kbody'     ) transformExp (Op (Inner (SegOp (SegScan lvl space scans ts kbody)))) = do-  (alloc_stms, (lams, kbody')) <-+  (alloc_stms, (lvl', lams, kbody')) <-     transformScanRed lvl space (map segBinOpLambda scans) kbody   let scans' = zipWith (\red lam -> red {segBinOpLambda = lam}) scans lams   pure     ( alloc_stms,-      Op $ Inner $ SegOp $ SegScan lvl space scans' ts kbody'+      Op $ Inner $ SegOp $ SegScan lvl' space scans' ts kbody'     ) transformExp (Op (Inner (SegOp (SegHist lvl space ops ts kbody)))) = do-  (alloc_stms, (lams', kbody')) <- transformScanRed lvl space lams kbody+  (alloc_stms, (lvl', lams', kbody')) <- transformScanRed lvl space lams kbody   let ops' = zipWith onOp ops lams'   pure     ( alloc_stms,-      Op $ Inner $ SegOp $ SegHist lvl space ops' ts kbody'+      Op $ Inner $ SegOp $ SegHist lvl' space ops' ts kbody'     )   where     lams = map histOp ops@@ -156,7 +156,7 @@       let -- XXX: fake a SegLevel, which we don't have here.  We will not           -- use it for anything, as we will not allow irregular           -- allocations inside the update function.-          lvl = SegThread (Count $ intConst Int64 0) (Count $ intConst Int64 0) SegNoVirt+          lvl = SegThread SegNoVirt Nothing           (op_lam', lam_allocs) =             extractLambdaAllocations (lvl, [0]) bound_outside mempty op_lam           variantAlloc (_, Var v, _) = v `notNameIn` bound_outside@@ -186,12 +186,33 @@ transformExp e =   pure (mempty, e) +ensureGridKnown :: SegLevel -> ExpandM (Stms GPUMem, SegLevel, KernelGrid)+ensureGridKnown lvl =+  case lvl of+    SegThread _ (Just grid) -> pure (mempty, lvl, grid)+    SegGroup _ (Just grid) -> pure (mempty, lvl, grid)+    SegThread virt Nothing -> mkGrid (SegThread virt)+    SegGroup virt Nothing -> mkGrid (SegGroup virt)+    SegThreadInGroup {} -> error "ensureGridKnown: SegThreadInGroup"+  where+    mkGrid f = do+      (grid, stms) <-+        runBuilder $+          KernelGrid+            <$> (Count <$> getSize "num_groups" SizeNumGroups)+            <*> (Count <$> getSize "group_size" SizeGroup)+      pure (stms, f $ Just grid, grid)++    getSize desc size_class = do+      size_key <- nameFromString . prettyString <$> newVName desc+      letSubExp desc $ Op $ Inner $ SizeOp $ GetSize size_key size_class+ transformScanRed ::   SegLevel ->   SegSpace ->   [Lambda GPUMem] ->   KernelBody GPUMem ->-  ExpandM (Stms GPUMem, ([Lambda GPUMem], KernelBody GPUMem))+  ExpandM (Stms GPUMem, (SegLevel, [Lambda GPUMem], KernelBody GPUMem)) transformScanRed lvl space ops kbody = do   bound_outside <- asks $ namesFromList . M.keys   let user = (lvl, [le64 $ segFlat space])@@ -221,10 +242,14 @@     _ ->       pure () -  allocsForBody variant_allocs invariant_allocs lvl space kbody' $ \alloc_stms kbody'' -> do-    ops'' <- forM ops' $ \op' ->-      localScope (scopeOf op') $ offsetMemoryInLambda op'-    pure (alloc_stms, (ops'', kbody''))+  if null variant_allocs && null invariant_allocs+    then pure (mempty, (lvl, ops, kbody))+    else do+      (lvl_stms, lvl', grid) <- ensureGridKnown lvl+      allocsForBody variant_allocs invariant_allocs grid space kbody' $ \alloc_stms kbody'' -> do+        ops'' <- forM ops' $ \op' ->+          localScope (scopeOf op') $ offsetMemoryInLambda op'+        pure (lvl_stms <> alloc_stms, (lvl', ops'', kbody''))   where     bound_in_kernel =       namesFromList (M.keys $ scopeOfSegSpace space)@@ -236,15 +261,15 @@ allocsForBody ::   Extraction ->   Extraction ->-  SegLevel ->+  KernelGrid ->   SegSpace ->   KernelBody GPUMem ->   (Stms GPUMem -> KernelBody GPUMem -> OffsetM b) ->   ExpandM b-allocsForBody variant_allocs invariant_allocs lvl space kbody' m = do+allocsForBody variant_allocs invariant_allocs grid space kbody' m = do   (alloc_offsets, alloc_stms) <-     memoryRequirements-      lvl+      grid       space       (kernelBodyStms kbody')       variant_allocs@@ -258,26 +283,26 @@       m alloc_stms kbody''  memoryRequirements ::-  SegLevel ->+  KernelGrid ->   SegSpace ->   Stms GPUMem ->   Extraction ->   Extraction ->   ExpandM (RebaseMap, Stms GPUMem)-memoryRequirements lvl space kstms variant_allocs invariant_allocs = do+memoryRequirements grid space kstms variant_allocs invariant_allocs = do   (num_threads, num_threads_stms) <-     runBuilder . letSubExp "num_threads" . BasicOp $       BinOp         (Mul Int64 OverflowUndef)-        (unCount $ segNumGroups lvl)-        (unCount $ segGroupSize lvl)+        (unCount $ gridNumGroups grid)+        (unCount $ gridGroupSize grid)    (invariant_alloc_stms, invariant_alloc_offsets) <-     inScopeOf num_threads_stms $       expandedInvariantAllocations         num_threads-        (segNumGroups lvl)-        (segGroupSize lvl)+        (gridNumGroups grid)+        (gridGroupSize grid)         invariant_allocs    (variant_alloc_stms, variant_alloc_offsets) <-@@ -437,7 +462,7 @@      untouched d = DimSlice 0 d 1 -    newBase user@(SegThread {}, _) (old_shape, _) =+    newBaseThread user (old_shape, _) =       let (users_shape, user_ids) = getNumUsers user           num_dims = length old_shape           perm = [num_dims .. num_dims + shapeRank users_shape - 1] ++ [0 .. num_dims - 1]@@ -448,7 +473,10 @@               Slice $                 map DimFix user_ids ++ map untouched old_shape        in offset_ixfun-    newBase user@(SegGroup {}, _) (old_shape, _) =++    newBase user@(SegThreadInGroup {}, _) = newBaseThread user+    newBase user@(SegThread {}, _) = newBaseThread user+    newBase user@(SegGroup {}, _) = \(old_shape, _) ->       let (users_shape, user_ids) = getNumUsers user           root_ixfun = IxFun.iota $ map pe64 (shapeDims users_shape) ++ old_shape           offset_ixfun =@@ -467,6 +495,8 @@   where     getNumUsers (SegThread {}, [gtid]) = (Shape [num_threads], [gtid])     getNumUsers (SegThread {}, [gid, ltid]) = (Shape [num_groups, group_size], [gid, ltid])+    getNumUsers (SegThreadInGroup {}, [gtid]) = (Shape [num_threads], [gtid])+    getNumUsers (SegThreadInGroup {}, [gid, ltid]) = (Shape [num_groups, group_size], [gid, ltid])     getNumUsers (SegGroup {}, [gid]) = (Shape [num_groups], [gid])     getNumUsers user = error $ "getNumUsers: unhandled " ++ show user 
src/Futhark/Pass/ExplicitAllocations/GPU.hs view
@@ -20,32 +20,48 @@   opIsConst (SizeOp GetSizeMax {}) = True   opIsConst _ = False -allocAtLevel :: SegLevel -> AllocM fromrep trep a -> AllocM fromrep trep a+allocAtLevel :: SegLevel -> AllocM GPU GPUMem a -> AllocM GPU GPUMem a allocAtLevel lvl = local $ \env ->   env     { allocSpace = space,-      aggressiveReuse = True+      aggressiveReuse = True,+      allocInOp = handleHostOp (Just lvl)     }   where     space = case lvl of-      SegThread {} -> DefaultSpace       SegGroup {} -> Space "local"+      SegThread {} -> DefaultSpace+      SegThreadInGroup {} -> DefaultSpace  handleSegOp ::+  Maybe SegLevel ->   SegOp SegLevel GPU ->   AllocM GPU GPUMem (SegOp SegLevel GPUMem)-handleSegOp op = do+handleSegOp outer_lvl op = do   num_threads <--    letSubExp "num_threads" $-      BasicOp $-        BinOp-          (Mul Int64 OverflowUndef)-          (unCount (segNumGroups lvl))-          (unCount (segGroupSize lvl))-  allocAtLevel lvl $ mapSegOpM (mapper num_threads) op+    letSubExp "num_threads"+      =<< case maybe_grid of+        Just grid ->+          pure . BasicOp $+            BinOp+              (Mul Int64 OverflowUndef)+              (unCount (gridNumGroups grid))+              (unCount (gridGroupSize grid))+        Nothing ->+          foldBinOp+            (Mul Int64 OverflowUndef)+            (intConst Int64 1)+            (segSpaceDims $ segSpace op)+  allocAtLevel (segLevel op) $ mapSegOpM (mapper num_threads) op   where+    maybe_grid =+      case (outer_lvl, segLevel op) of+        (Just (SegThread _ (Just grid)), _) -> Just grid+        (Just (SegGroup _ (Just grid)), _) -> Just grid+        (_, SegThread _ (Just grid)) -> Just grid+        (_, SegGroup _ (Just grid)) -> Just grid+        _ -> Nothing     scope = scopeOfSegSpace $ segSpace op-    lvl = segLevel op     mapper num_threads =       identitySegOpMapper         { mapOnSegOpBody =@@ -56,20 +72,22 @@         }     f = case segLevel op of       SegThread {} -> inThread+      SegThreadInGroup {} -> inThread       SegGroup {} -> inGroup     inThread env = env {envExpHints = inThreadExpHints}     inGroup env = env {envExpHints = inGroupExpHints}  handleHostOp ::+  Maybe SegLevel ->   HostOp GPU (SOAC GPU) ->   AllocM GPU GPUMem (MemOp (HostOp GPUMem ()))-handleHostOp (SizeOp op) =+handleHostOp _ (SizeOp op) =   pure $ Inner $ SizeOp op-handleHostOp (OtherOp op) =+handleHostOp _ (OtherOp op) =   error $ "Cannot allocate memory in SOAC: " ++ prettyString op-handleHostOp (SegOp op) =-  Inner . SegOp <$> handleSegOp op-handleHostOp (GPUBody ts (Body _ stms res)) =+handleHostOp outer_lvl (SegOp op) =+  Inner . SegOp <$> handleSegOp outer_lvl op+handleHostOp _ (GPUBody ts (Body _ stms res)) =   fmap (Inner . GPUBody ts) . buildBody_ . allocInStms stms $ pure res  kernelExpHints :: Exp GPUMem -> AllocM GPU GPUMem [ExpHint]@@ -79,9 +97,9 @@       dims' = rearrangeShape perm dims       ixfun = IxFun.permute (IxFun.iota $ map pe64 dims') perm_inv   pure [Hint ixfun DefaultSpace]-kernelExpHints (Op (Inner (SegOp (SegMap lvl@SegThread {} space ts body)))) =+kernelExpHints (Op (Inner (SegOp (SegMap lvl@(SegThread _ _) space ts body)))) =   zipWithM (mapResultHint lvl space) ts $ kernelBodyResult body-kernelExpHints (Op (Inner (SegOp (SegRed lvl@SegThread {} space reds ts body)))) =+kernelExpHints (Op (Inner (SegOp (SegRed lvl@(SegThread _ _) space reds ts body)))) =   (map (const NoHint) red_res <>) <$> zipWithM (mapResultHint lvl space) (drop num_reds ts) map_res   where     num_reds = segBinOpResults reds@@ -166,11 +184,11 @@  -- | The pass from 'GPU' to 'GPUMem'. explicitAllocations :: Pass GPU GPUMem-explicitAllocations = explicitAllocationsGeneric handleHostOp kernelExpHints+explicitAllocations = explicitAllocationsGeneric (handleHostOp Nothing) kernelExpHints  -- | Convert some 'GPU' stms to 'GPUMem'. explicitAllocationsInStms ::   (MonadFreshNames m, HasScope GPUMem m) =>   Stms GPU ->   m (Stms GPUMem)-explicitAllocationsInStms = explicitAllocationsInStmsGeneric handleHostOp kernelExpHints+explicitAllocationsInStms = explicitAllocationsInStmsGeneric (handleHostOp Nothing) kernelExpHints
src/Futhark/Pass/ExtractKernels/BlockedKernel.hs view
@@ -21,6 +21,7 @@ import Control.Monad.Writer import Futhark.Analysis.PrimExp import Futhark.IR+import Futhark.IR.GPU.Op (SegVirt (..)) import Futhark.IR.Prop.Aliases import Futhark.IR.SegOp import Futhark.MonadFreshNames
src/Futhark/Pass/ExtractKernels/DistributeNests.hs view
@@ -39,6 +39,7 @@ import Data.Map qualified as M import Data.Maybe import Futhark.IR+import Futhark.IR.GPU.Op (SegVirt (..)) import Futhark.IR.SOACS (SOACS) import Futhark.IR.SOACS qualified as SOACS import Futhark.IR.SOACS.SOAC hiding (HistOp, histDest)@@ -375,7 +376,7 @@         Nothing -> addStmToAcc stm acc         Just acc' -> distribute =<< onInnerMap (MapLoop pat (stmAux stm) w lam arrs) acc' maybeDistributeStm stm@(Let pat aux (DoLoop merge form@ForLoop {} body)) acc-  | all (`notNameIn` freeIn pat) (patNames pat),+  | all (`notNameIn` freeIn (patTypes pat)) (patNames pat),     bodyContainsParallelism body =       distributeSingleStm acc stm >>= \case         Just (kernels, res, nest, acc')
src/Futhark/Pass/ExtractKernels/Intragroup.hs view
@@ -60,12 +60,9 @@   let body = lambdaBody lam    group_size <- newVName "computed_group_size"-  let intra_lvl = SegThread (Count num_groups) (Count $ Var group_size) SegNoVirt-   (wss_min, wss_avail, log, kbody) <--    lift $-      localScope (scopeOfLParams $ lambdaParams lam) $-        intraGroupParalleliseBody intra_lvl body+    lift . localScope (scopeOfLParams $ lambdaParams lam) $+      intraGroupParalleliseBody body    outside_scope <- lift askScope   -- outside_scope may also contain the inputs, even though those are@@ -116,12 +113,10 @@    let nested_pat = loopNestingPat first_nest       rts = map (length ispace `stripArray`) $ patTypes nested_pat-      lvl = SegGroup (Count num_groups) (Count $ Var group_size) SegNoVirt+      grid = KernelGrid (Count num_groups) (Count $ Var group_size)+      lvl = SegGroup SegNoVirt (Just grid)       kstm =-        Let nested_pat aux $-          Op $-            SegOp $-              SegMap lvl kspace rts kbody'+        Let nested_pat aux $ Op $ SegOp $ SegMap lvl kspace rts kbody'    let intra_min_par = intra_avail_par   pure@@ -184,21 +179,21 @@         accAvailPar = S.singleton ws       } -intraGroupBody :: SegLevel -> Body SOACS -> IntraGroupM (Body GPU)-intraGroupBody lvl body = do-  stms <- collectStms_ $ intraGroupStms lvl $ bodyStms body+intraGroupBody :: Body SOACS -> IntraGroupM (Body GPU)+intraGroupBody body = do+  stms <- collectStms_ $ intraGroupStms $ bodyStms body   pure $ mkBody stms $ bodyResult body -intraGroupStm :: SegLevel -> Stm SOACS -> IntraGroupM ()-intraGroupStm lvl stm@(Let pat aux e) = do+intraGroupStm :: Stm SOACS -> IntraGroupM ()+intraGroupStm stm@(Let pat aux e) = do   scope <- askScope-  let lvl' = SegThread (segNumGroups lvl) (segGroupSize lvl) SegNoVirt+  let lvl = SegThread SegNoVirt Nothing    case e of     DoLoop merge form loopbody ->       localScope (scopeOf form') $         localScope (scopeOfFParams $ map fst merge) $ do-          loopbody' <- intraGroupBody lvl loopbody+          loopbody' <- intraGroupBody loopbody           certifying (stmAuxCerts aux) $             letBind pat $               DoLoop merge form' loopbody'@@ -207,13 +202,13 @@           ForLoop i it bound inps -> ForLoop i it bound inps           WhileLoop cond -> WhileLoop cond     Match cond cases defbody ifdec -> do-      cases' <- mapM (traverse $ intraGroupBody lvl) cases-      defbody' <- intraGroupBody lvl defbody+      cases' <- mapM (traverse intraGroupBody) cases+      defbody' <- intraGroupBody defbody       certifying (stmAuxCerts aux) . letBind pat $         Match cond cases' defbody' ifdec     Op soac       | "sequential_outer" `inAttrs` stmAuxAttrs aux ->-          intraGroupStms lvl . fmap (certify (stmAuxCerts aux))+          intraGroupStms . fmap (certify (stmAuxCerts aux))             =<< runBuilder_ (FOT.transformSOAC pat soac)     Op (Screma w arrs form)       | Just lam <- isMapSOAC form -> do@@ -229,7 +224,7 @@                     distOnInnerMap =                       distributeMap,                     distOnTopLevelStms =-                      liftInner . collectStms_ . intraGroupStms lvl,+                      liftInner . collectStms_ . intraGroupStms,                     distSegLevel = \minw _ _ -> do                       lift $ parallelMin minw                       pure lvl,@@ -252,7 +247,7 @@           let scanfun' = soacsLambdaToGPU scanfun               mapfun' = soacsLambdaToGPU mapfun           certifying (stmAuxCerts aux) $-            addStms =<< segScan lvl' pat mempty w [SegBinOp Noncommutative scanfun' nes mempty] mapfun' arrs [] []+            addStms =<< segScan lvl pat mempty w [SegBinOp Noncommutative scanfun' nes mempty] mapfun' arrs [] []           parallelMin [w]     Op (Screma w arrs form)       | Just (reds, map_lam) <- isRedomapSOAC form,@@ -260,7 +255,7 @@           let red_lam' = soacsLambdaToGPU red_lam               map_lam' = soacsLambdaToGPU map_lam           certifying (stmAuxCerts aux) $-            addStms =<< segRed lvl' pat mempty w [SegBinOp comm red_lam' nes mempty] map_lam' arrs [] []+            addStms =<< segRed lvl pat mempty w [SegBinOp comm red_lam' nes mempty] map_lam' arrs [] []           parallelMin [w]     Op (Hist w arrs ops bucket_fun) -> do       ops' <- forM ops $ \(HistOp num_bins rf dests nes op) -> do@@ -270,7 +265,7 @@        let bucket_fun' = soacsLambdaToGPU bucket_fun       certifying (stmAuxCerts aux) $-        addStms =<< segHist lvl' pat w [] [] ops' bucket_fun' arrs+        addStms =<< segHist lvl pat w [] [] ops' bucket_fun' arrs       parallelMin [w]     Op (Stream w arrs accs lam)       | chunk_size_param : _ <- lambdaParams lam -> do@@ -281,7 +276,7 @@               replace se = se               replaceSets (IntraAcc x y log) =                 IntraAcc (S.map (map replace) x) (S.map (map replace) y) log-          censor replaceSets $ intraGroupStms lvl stream_stms+          censor replaceSets $ intraGroupStms stream_stms     Op (Scatter w ivs lam dests) -> do       write_i <- newVName "write_i"       space <- mkSegSpace [(write_i, w)]@@ -308,23 +303,22 @@       certifying (stmAuxCerts aux) $ do         let ts = zipWith (stripArray . length) dests_ws $ patTypes pat             body = KernelBody () kstms krets-        letBind pat $ Op $ SegOp $ SegMap lvl' space ts body+        letBind pat $ Op $ SegOp $ SegMap lvl space ts body        parallelMin [w]     _ ->       addStm $ soacsStmToGPU stm -intraGroupStms :: SegLevel -> Stms SOACS -> IntraGroupM ()-intraGroupStms lvl = mapM_ (intraGroupStm lvl)+intraGroupStms :: Stms SOACS -> IntraGroupM ()+intraGroupStms = mapM_ intraGroupStm  intraGroupParalleliseBody ::   (MonadFreshNames m, HasScope GPU m) =>-  SegLevel ->   Body SOACS ->   m ([[SubExp]], [[SubExp]], Log, KernelBody GPU)-intraGroupParalleliseBody lvl body = do+intraGroupParalleliseBody body = do   (IntraAcc min_ws avail_ws log, kstms) <--    runIntraGroupM $ intraGroupStms lvl $ bodyStms body+    runIntraGroupM $ intraGroupStms $ bodyStms body   pure     ( S.toList min_ws,       S.toList avail_ws,
src/Futhark/Pass/ExtractKernels/StreamKernel.hs view
@@ -74,7 +74,9 @@             (SDivUp Int64 Unsafe)             (eSubExp w)             (eSubExp =<< asIntS Int64 group_size)-      pure $ SegThread (Count usable_groups) (Count group_size) SegNoVirt+      let grid = KernelGrid (Count usable_groups) (Count group_size)+      pure $ SegThread SegNoVirt (Just grid)     NoRecommendation v -> do       (num_groups, _) <- numberOfGroups desc w group_size-      pure $ SegThread (Count num_groups) (Count group_size) v+      let grid = KernelGrid (Count num_groups) (Count group_size)+      pure $ SegThread v (Just grid)
src/Futhark/Pass/ExtractKernels/ToGPU.hs view
@@ -34,10 +34,12 @@   String ->   m SegLevel segThread desc =-  SegThread-    <$> (Count <$> getSize (desc ++ "_num_groups") SizeNumGroups)-    <*> (Count <$> getSize (desc ++ "_group_size") SizeGroup)-    <*> pure SegVirt+  SegThread SegVirt <$> (Just <$> kernelGrid)+  where+    kernelGrid =+      KernelGrid+        <$> (Count <$> getSize (desc ++ "_num_groups") SizeNumGroups)+        <*> (Count <$> getSize (desc ++ "_group_size") SizeGroup)  injectSOACS ::   ( Monad m,
src/Futhark/Util.hs view
@@ -43,6 +43,7 @@     zEncodeString,     atMostChars,     invertMap,+    cartesian,     traverseFold,     fixPoint,   )@@ -57,7 +58,7 @@ import Data.ByteString.Base16 qualified as Base16 import Data.Char import Data.Either-import Data.Foldable (fold)+import Data.Foldable (fold, toList) import Data.Function ((&)) import Data.List (foldl', genericDrop, genericSplitAt, sortBy) import Data.List.NonEmpty qualified as NE@@ -411,6 +412,13 @@   M.toList m     & fmap (swap . first S.singleton)     & foldr (uncurry $ M.insertWith (<>)) mempty++-- | Compute the cartesian product of two foldable collections, using the given+-- combinator function.+cartesian :: (Monoid m, Foldable t) => (a -> a -> m) -> t a -> t a -> m+cartesian f xs ys =+  [(x, y) | x <- toList xs, y <- toList ys]+    & foldMap (uncurry f)  -- | Applicatively fold a traversable. traverseFold :: (Monoid m, Traversable t, Applicative f) => (a -> f m) -> t a -> f m
src/Futhark/Util/Pretty.hs view
@@ -35,6 +35,7 @@     stack,     parensIf,     ppTuple',+    ppTupleLines',      -- * Operators     (</>),@@ -113,15 +114,16 @@ ppTuple' :: [Doc a] -> Doc a ppTuple' ets = braces $ commasep $ map align ets +ppTupleLines' :: [Doc a] -> Doc a+ppTupleLines' ets = braces $ commastack $ map align ets+ -- | Prettyprint a list enclosed in curly braces. prettyTuple :: Pretty a => [a] -> Text prettyTuple = docText . ppTuple' . map pretty  -- | Like 'prettyTuple', but put a linebreak after every element. prettyTupleLines :: Pretty a => [a] -> Text-prettyTupleLines = docText . ppTupleLines'-  where-    ppTupleLines' = braces . hsep . punctuate comma . map (align . pretty)+prettyTupleLines = docText . ppTupleLines' . map pretty  -- | The document @'apply' ds@ separates @ds@ with commas and encloses them with -- parentheses.
src/Language/Futhark/Interpreter.hs view
@@ -1033,7 +1033,7 @@     onModule (Module (Env terms types _)) =       Module $ Env (replaceM onTerm terms) (replaceM onType types) mempty     onModule (ModuleFun f) =-      ModuleFun $ \m -> onModule <$> f (substituteInModule (M.mapMaybe maybeHead rev_substs) m)+      ModuleFun $ \m -> onModule <$> f (substituteInModule substs m)     onTerm (TermValue t v) = TermValue t v     onTerm (TermPoly t v) = TermPoly t v     onTerm (TermModule m) = TermModule $ onModule m
src/Language/Futhark/Pretty.hs view
@@ -253,8 +253,7 @@       _ -> hasArrayLit e prettyAppExp _ (LetFun fname (tparams, params, retdecl, rettype, e) body _) =   "let"-    <+> prettyName fname-    <+> hsep (map pretty tparams ++ map pretty params)+    <+> hsep (prettyName fname : map pretty tparams ++ map pretty params)       <> retdecl'     <+> equals     </> indent 2 (pretty e)@@ -468,8 +467,7 @@ instance (Eq vn, IsName vn, Annot f) => Pretty (TypeBindBase f vn) where   pretty (TypeBind name l params te rt _ _) =     "type" <> pretty l-      <+> prettyName name-      <+> hsep (map pretty params)+      <+> hsep (prettyName name : map pretty params)       <+> equals       <+> maybe (pretty te) pretty (unAnnot rt) @@ -502,9 +500,9 @@ instance (Eq vn, IsName vn, Annot f) => Pretty (SpecBase f vn) where   pretty (TypeAbbrSpec tpsig) = pretty tpsig   pretty (TypeSpec l name ps _ _) =-    "type" <> pretty l <+> prettyName name <+> hsep (map pretty ps)+    "type" <> pretty l <+> hsep (prettyName name : map pretty ps)   pretty (ValSpec name tparams vtype _ _ _) =-    "val" <+> prettyName name <+> hsep (map pretty tparams) <> colon <+> pretty vtype+    "val" <+> hsep (prettyName name : map pretty tparams) <> colon <+> pretty vtype   pretty (ModSpec name sig _ _) =     "module" <+> prettyName name <> colon <+> pretty sig   pretty (IncludeSpec e _) =@@ -531,11 +529,11 @@  instance (Eq vn, IsName vn, Annot f) => Pretty (ModBindBase f vn) where   pretty (ModBind name ps sig e _ _) =-    "module" <+> prettyName name <+> hsep (map pretty ps) <+> sig' <> " =" <+> pretty e+    "module" <+> hsep (prettyName name : map pretty ps) <> sig' <> " =" <+> pretty e     where       sig' = case sig of         Nothing -> mempty-        Just (s, _) -> colon <+> pretty s <> " "+        Just (s, _) -> " " <> colon <+> pretty s <> " "  ppBinOp :: IsName v => QualName v -> Doc a ppBinOp bop =
src/Language/Futhark/TypeChecker/Match.hs view
@@ -8,6 +8,7 @@   ) where +import Data.List qualified as L import Data.Map.Strict qualified as M import Data.Maybe import Futhark.Util (maybeHead, nubOrd)@@ -23,16 +24,16 @@   deriving (Eq, Ord, Show)  -- | A representation of the essentials of a pattern.-data Match-  = MatchWild StructType-  | MatchConstr Constr [Match] StructType+data Match t+  = MatchWild t+  | MatchConstr Constr [Match t] t   deriving (Eq, Ord, Show) -matchType :: Match -> StructType+matchType :: Match StructType -> StructType matchType (MatchWild t) = t matchType (MatchConstr _ _ t) = t -pprMatch :: Int -> Match -> Doc a+pprMatch :: Int -> Match t -> Doc a pprMatch _ MatchWild {} = "_" pprMatch _ (MatchConstr (ConstrLit l) _ _) = pretty l pprMatch p (MatchConstr (Constr c) ps _) =@@ -45,10 +46,10 @@   where     ppField name t = pretty (nameToString name) <> equals <> pprMatch (-1) t -instance Pretty Match where+instance Pretty (Match t) where   pretty = pprMatch (-1) -patternToMatch :: Pat -> Match+patternToMatch :: Pat -> Match StructType patternToMatch (Id _ (Info t) _) = MatchWild $ toStruct t patternToMatch (Wildcard (Info t) _) = MatchWild $ toStruct t patternToMatch (PatParens p _) = patternToMatch p@@ -67,29 +68,35 @@ patternToMatch (PatConstr c (Info t) args _) =   MatchConstr (Constr c) (map patternToMatch args) $ toStruct t -isConstr :: Match -> Maybe Name+isConstr :: Match t -> Maybe Name isConstr (MatchConstr (Constr c) _ _) = Just c isConstr _ = Nothing -complete :: [Match] -> Bool+isBool :: Match t -> Maybe Bool+isBool (MatchConstr (ConstrLit (PatLitPrim (BoolValue b))) _ _) = Just b+isBool _ = Nothing++complete :: [Match StructType] -> Bool complete xs   | Just x <- maybeHead xs,     Scalar (Sum all_cs) <- matchType x,     Just xs_cs <- mapM isConstr xs =       all (`elem` xs_cs) (M.keys all_cs)   | otherwise =-      (any (isBool True) xs && any (isBool False) xs)+      all (`elem` fromMaybe [] (mapM isBool xs)) [True, False]         || all isRecord xs         || all isTuple xs   where-    isBool b1 (MatchConstr (ConstrLit (PatLitPrim (BoolValue b2))) _ _) = b1 == b2-    isBool _ _ = False     isRecord (MatchConstr ConstrRecord {} _ _) = True     isRecord _ = False     isTuple (MatchConstr ConstrTuple _ _) = True     isTuple _ = False -specialise :: [StructType] -> Match -> [[Match]] -> [[Match]]+specialise ::+  [StructType] ->+  Match StructType ->+  [[Match StructType]] ->+  [[Match StructType]] specialise ats c1 = go   where     go ((c2 : row) : ps)@@ -109,14 +116,14 @@     match _ _ =       Nothing -defaultMat :: [[Match]] -> [[Match]]+defaultMat :: [[Match t]] -> [[Match t]] defaultMat = mapMaybe onRow   where     onRow (MatchConstr {} : _) = Nothing     onRow (MatchWild {} : ps) = Just ps     onRow [] = Nothing -- Should not happen. -findUnmatched :: [[Match]] -> Int -> [[Match]]+findUnmatched :: [[Match StructType]] -> Int -> [[Match ()]] findUnmatched pmat n   | ((p : _) : _) <- pmat,     Just heads <- mapM maybeHead pmat =@@ -133,40 +140,44 @@           pmat' = specialise ats c pmat       u <- findUnmatched pmat' (a_k + n - 1)       pure $ case c of-        MatchConstr c' _ t ->+        MatchConstr c' _ _ ->           let (r, p) = splitAt a_k u-           in MatchConstr c' r t : p-        MatchWild t ->-          MatchWild t : u+           in MatchConstr c' r () : p+        MatchWild _ ->+          MatchWild () : u      incompleteCase pt cs = do       u <- findUnmatched (defaultMat pmat) (n - 1)       if null cs-        then pure $ MatchWild pt : u+        then pure $ MatchWild () : u         else case pt of           Scalar (Sum all_cs) -> do             -- Figure out which constructors are missing.             let sigma = mapMaybe isConstr cs                 notCovered (k, _) = k `notElem` sigma             (cname, ts) <- filter notCovered $ M.toList all_cs-            pure $ MatchConstr (Constr cname) (map MatchWild ts) pt : u-          _ ->-            -- This is where we could have enumerated missing match-            -- values (e.g. for booleans), rather than just emitting a-            -- wildcard.-            pure $ MatchWild pt : u---- If we get here, then the number of columns must be zero.-findUnmatched [] _ = [[]]+            pure $ MatchConstr (Constr cname) (map (const (MatchWild ())) ts) () : u+          Scalar (Prim Bool) -> do+            -- Figure out which constants are missing.+            let sigma = mapMaybe isBool cs+            b <- filter (`notElem` sigma) [True, False]+            pure $ MatchConstr (ConstrLit (PatLitPrim (BoolValue b))) [] () : u+          _ -> do+            -- FIXME: this is wrong in the unlikely case where someone+            -- is pattern-matching every single possible number for+            -- some numeric type.  It should be handled more like Bool+            -- above.+            pure $ MatchWild () : u+findUnmatched [] n = [replicate n $ MatchWild ()] findUnmatched _ _ = []  {-# NOINLINE unmatched #-}  -- | Find the unmatched cases.-unmatched :: [Pat] -> [Match]+unmatched :: [Pat] -> [Match ()] unmatched orig_ps =   -- The algorithm may find duplicate example, which we filter away   -- here.   nubOrd $     mapMaybe maybeHead $-      findUnmatched (map ((: []) . patternToMatch) orig_ps) 1+      findUnmatched (map (L.singleton . patternToMatch) orig_ps) 1
src/Language/Futhark/TypeChecker/Modules.hs view
@@ -375,8 +375,7 @@         <+> hsep (map pretty ps) ppTypeAbbr _ name (l, ps, t) =   "type" <> pretty l-    <+> pretty name-    <+> hsep (map pretty ps)+    <+> hsep (pretty name : map pretty ps)     <+> equals     <+> nest 2 (align (pretty t)) @@ -455,11 +454,19 @@       (ModFun (FunSig mod_abs mod_pmod mod_mod))       (ModFun (FunSig sig_abs sig_pmod sig_mod))       loc = do+        -- We need to use different substitutions when matching+        -- parameter and body signatures - this is because the+        -- concrete parameter must be *at least as* general as the+        -- ascripted parameter, while the concrete body must be *at+        -- most as* general as the ascripted body.         abs_substs <- resolveAbsTypes mod_abs mod_pmod sig_abs loc+        p_abs_substs <- resolveAbsTypes sig_abs sig_pmod mod_abs loc         let abs_subst_to_type =               old_abs_subst_to_type <> M.map (substFromAbbr . snd) abs_substs+            p_abs_subst_to_type =+              old_abs_subst_to_type <> M.map (substFromAbbr . snd) p_abs_substs             abs_name_substs = M.map (qualLeaf . fst) abs_substs-        pmod_substs <- matchMods abs_subst_to_type quals mod_pmod sig_pmod loc+        pmod_substs <- matchMods p_abs_subst_to_type quals sig_pmod mod_pmod loc         mod_substs <- matchMTys' abs_subst_to_type quals mod_mod sig_mod loc         pure (pmod_substs <> mod_substs <> abs_name_substs) 
src/Language/Futhark/TypeChecker/Terms.hs view
@@ -895,10 +895,9 @@            in zeroOrderType (mkUsage argloc "potential consumption in expression") msg tp1         _ -> pure () -      occurs <- (dflow `seqOccurrences`) <$> consumeArg argloc argtype' (diet tp1')--      checkIfConsumable loc $ S.map AliasBound $ allConsumed occurs-      occur occurs+      arg_consumed <- consumedByArg argloc argtype' (diet tp1')+      checkIfConsumable loc $ mconcat arg_consumed+      occur $ dflow `seqOccurrences` map (`consumption` argloc) arg_consumed        -- Unification ignores uniqueness in higher-order arguments, so       -- we check for that here.@@ -1011,12 +1010,12 @@ maskAliases t FuncDiet {} = t maskAliases _ _ = error "Invalid arguments passed to maskAliases." -consumeArg :: SrcLoc -> PatType -> Diet -> TermTypeM [Occurrence]-consumeArg loc (Scalar (Record ets)) (RecordDiet ds) =-  concat . M.elems <$> traverse (uncurry $ consumeArg loc) (M.intersectionWith (,) ets ds)-consumeArg loc (Scalar (Sum ets)) (SumDiet ds) =-  concat <$> traverse (uncurry $ consumeArg loc) (concat $ M.elems $ M.intersectionWith zip ets ds)-consumeArg loc (Scalar (Arrow _ _ t1 _)) (FuncDiet d _)+consumedByArg :: SrcLoc -> PatType -> Diet -> TermTypeM [Aliasing]+consumedByArg loc (Scalar (Record ets)) (RecordDiet ds) =+  mconcat . M.elems <$> traverse (uncurry $ consumedByArg loc) (M.intersectionWith (,) ets ds)+consumedByArg loc (Scalar (Sum ets)) (SumDiet ds) =+  mconcat <$> traverse (uncurry $ consumedByArg loc) (concat $ M.elems $ M.intersectionWith zip ets ds)+consumedByArg loc (Scalar (Arrow _ _ t1 _)) (FuncDiet d _)   | not $ contravariantArg t1 d =       typeError loc mempty . withIndexLink "consuming-argument" $         "Non-consuming higher-order parameter passed consuming argument."@@ -1031,8 +1030,8 @@       contravariantArg tp dp && contravariantArg tr dr     contravariantArg _ _ =       True-consumeArg loc at Consume = pure [consumption (aliases at) loc]-consumeArg loc at _ = pure [observation (aliases at) loc]+consumedByArg _ at Consume = pure [aliases at]+consumedByArg _ _ _ = pure []  -- | Type-check a single expression in isolation.  This expression may -- turn out to be polymorphic, in which case the list of type
src/Language/Futhark/TypeChecker/Terms/Monad.hs view
@@ -69,7 +69,6 @@     -- * Errors     useAfterConsume,     unusedSize,-    notConsumable,     uniqueReturnAliased,     returnAliased,     badLetWithValue,@@ -970,14 +969,15 @@ checkIfConsumable :: SrcLoc -> Aliasing -> TermTypeM () checkIfConsumable loc als = do   vtable <- asks $ scopeVtable . termScope-  let consumable v = case M.lookup v vtable of+  let boundAlias (AliasBound v) = Just v+      boundAlias (AliasFree _) = Nothing+      consumable v = case M.lookup v vtable of         Just (BoundV Local _ t)           | Scalar Arrow {} <- t -> False           | otherwise -> True         Just (BoundV l _ _) -> l == Local-        _ -> True-  -- The sort ensures that AliasBound vars are shown before AliasFree.-  case map aliasVar $ sort $ filter (not . consumable . aliasVar) $ S.toList als of+        _ -> False -- Implies name from module.+  case sort $ filter (not . consumable) $ mapMaybe boundAlias $ S.toList als of     v : _ -> notConsumable loc =<< describeVar loc v     [] -> pure ()