packages feed

futhark 0.25.1 → 0.25.2

raw patch · 52 files changed

+1787/−1776 lines, 52 filesdep ~lspdep ~lsp-typesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: lsp, lsp-types

API changes (from Hackage documentation)

- Futhark.CodeGen.ImpGen.GPU.Base: sCopyKernel :: CopyCompiler GPUMem HostEnv HostOp
- Futhark.IR.Mem: instance (GHC.Classes.Eq d, GHC.Classes.Eq u, GHC.Classes.Eq ret) => GHC.Classes.Eq (Futhark.IR.Mem.MemInfo d u ret)
- Futhark.IR.Mem: instance (GHC.Classes.Ord d, GHC.Classes.Ord u, GHC.Classes.Ord ret) => GHC.Classes.Ord (Futhark.IR.Mem.MemInfo d u ret)
- Futhark.IR.Mem: instance (GHC.Show.Show d, GHC.Show.Show u, GHC.Show.Show ret) => GHC.Show.Show (Futhark.IR.Mem.MemInfo d u ret)
- Futhark.IR.Mem.IxFun: Dec :: Monotonicity
- Futhark.IR.Mem.IxFun: Inc :: Monotonicity
- Futhark.IR.Mem.IxFun: Unknown :: Monotonicity
- Futhark.IR.Mem.IxFun: [contiguous] :: IxFun num -> Bool
- Futhark.IR.Mem.IxFun: [ixfunLMADs] :: IxFun num -> NonEmpty (LMAD num)
- Futhark.IR.Mem.IxFun: [ldMon] :: LMADDim num -> Monotonicity
- Futhark.IR.Mem.IxFun: [lmadDims] :: LMAD num -> [LMADDim num]
- Futhark.IR.Mem.IxFun: [lmadOffset] :: LMAD num -> num
- Futhark.IR.Mem.IxFun: conservativeFlatten :: LMAD (TPrimExp Int64 VName) -> Maybe (LMAD (TPrimExp Int64 VName))
- Futhark.IR.Mem.IxFun: data Monotonicity
- Futhark.IR.Mem.IxFun: hasOneLmad :: IxFun num -> Bool
- Futhark.IR.Mem.IxFun: isLinear :: (Eq num, IntegralExp num) => IxFun num -> Bool
- Futhark.IR.Mem.IxFun: linearWithOffset :: (Eq num, IntegralExp num) => IxFun num -> num -> Maybe num
- Futhark.IR.Mem.IxFun: lmadShape :: LMAD num -> Shape num
- Futhark.IR.Mem.IxFun: rearrangeWithOffset :: (Eq num, IntegralExp num) => IxFun num -> num -> Maybe (num, [(Int, num)])
- Futhark.IR.Mem.LMAD: Dec :: Monotonicity
- Futhark.IR.Mem.LMAD: Inc :: Monotonicity
- Futhark.IR.Mem.LMAD: Unknown :: Monotonicity
- Futhark.IR.Mem.LMAD: [ldMon] :: LMADDim num -> Monotonicity
- Futhark.IR.Mem.LMAD: [lmadDims] :: LMAD num -> [LMADDim num]
- Futhark.IR.Mem.LMAD: [lmadOffset] :: LMAD num -> num
- Futhark.IR.Mem.LMAD: conservativeFlatten :: LMAD (TPrimExp Int64 VName) -> Maybe (LMAD (TPrimExp Int64 VName))
- Futhark.IR.Mem.LMAD: data Monotonicity
- Futhark.IR.Mem.LMAD: instance GHC.Classes.Eq Futhark.IR.Mem.LMAD.Monotonicity
- Futhark.IR.Mem.LMAD: instance GHC.Classes.Ord Futhark.IR.Mem.LMAD.Monotonicity
- Futhark.IR.Mem.LMAD: instance GHC.Show.Show Futhark.IR.Mem.LMAD.Monotonicity
- Futhark.IR.Mem.LMAD: instance Prettyprinter.Internal.Pretty Futhark.IR.Mem.LMAD.Monotonicity
- Futhark.IR.Mem.LMAD: invertMonotonicity :: Monotonicity -> Monotonicity
- Futhark.IR.Mem.LMAD: lmadPermutation :: LMAD num -> Permutation
- Futhark.IR.Mem.LMAD: lmadShape :: LMAD num -> Shape num
- Futhark.IR.Mem.LMAD: lmadShapeBase :: LMAD num -> Shape num
- Futhark.IR.Mem.LMAD: makeRotIota :: IntegralExp num => Monotonicity -> num -> [num] -> LMAD num
- Futhark.IR.Syntax.Core: instance (GHC.Classes.Eq u, GHC.Classes.Eq shape) => GHC.Classes.Eq (Futhark.IR.Syntax.Core.TypeBase shape u)
- Futhark.IR.Syntax.Core: instance (GHC.Classes.Ord u, GHC.Classes.Ord shape) => GHC.Classes.Ord (Futhark.IR.Syntax.Core.TypeBase shape u)
- Futhark.IR.Syntax.Core: instance (GHC.Show.Show u, GHC.Show.Show shape) => GHC.Show.Show (Futhark.IR.Syntax.Core.TypeBase shape u)
- Futhark.Passes: kernelsPipeline :: Pipeline SOACS GPU
- Futhark.Passes: multicorePipeline :: Pipeline SOACS MCMem
- Futhark.Passes: sequentialCpuPipeline :: Pipeline SOACS SeqMem
- Futhark.Passes: sequentialPipeline :: Pipeline SOACS Seq
- Language.Futhark.Parser: parseDecOrExpIncrM :: Monad m => m Text -> FilePath -> Text -> m (Either SyntaxError (Either UncheckedDec UncheckedExp))
- Language.Futhark.Parser.Lexer.Tokens: indexing :: (Loc, Text) -> Alex Name
- Language.Futhark.Parser.Lexer.Tokens: keyword :: Text -> Token
- Language.Futhark.Parser.Lexer.Tokens: readIntegral :: Integral a => Text -> a
- Language.Futhark.Parser.Lexer.Tokens: tokenM :: (Text -> Alex a) -> (Pos, Char, ByteString, Int64) -> Int64 -> Alex (Lexeme a)
- Language.Futhark.Parser.Lexer.Tokens: tokenPosM :: ((Loc, Text) -> Alex a) -> (Pos, Char, ByteString, Int64) -> Int64 -> Alex (Lexeme a)
- Language.Futhark.Parser.Lexer.Tokens: type Lexeme a = (Pos, Pos, a)
- Language.Futhark.Parser.Lexer.Wrapper: alexError :: Loc -> Text -> Alex a
- Language.Futhark.Parser.Lexer.Wrapper: alexGetInput :: Alex AlexInput
- Language.Futhark.Parser.Lexer.Wrapper: alexGetStartCode :: Alex Int
- Language.Futhark.Parser.Lexer.Wrapper: alexSetInput :: AlexInput -> Alex ()
- Language.Futhark.Parser.Lexer.Wrapper: data Alex a
- Language.Futhark.Parser.Lexer.Wrapper: instance GHC.Base.Applicative Language.Futhark.Parser.Lexer.Wrapper.Alex
- Language.Futhark.Parser.Lexer.Wrapper: instance GHC.Base.Functor Language.Futhark.Parser.Lexer.Wrapper.Alex
- Language.Futhark.Parser.Lexer.Wrapper: instance GHC.Base.Monad Language.Futhark.Parser.Lexer.Wrapper.Alex
- Language.Futhark.Parser.Lexer.Wrapper: runAlex :: Pos -> ByteString -> Alex a -> Either LexerError a
- Language.Futhark.Parser.Lexer.Wrapper: type Byte = Word8
- Language.Futhark.Parser.Monad: GetLine :: (Maybe Text -> ReadLineMonad a) -> ReadLineMonad a
- Language.Futhark.Parser.Monad: Value :: a -> ReadLineMonad a
- Language.Futhark.Parser.Monad: data ReadLineMonad a
- Language.Futhark.Parser.Monad: getLinesFromM :: Monad m => m Text -> ReadLineMonad a -> m a
- Language.Futhark.Parser.Monad: instance GHC.Base.Applicative Language.Futhark.Parser.Monad.ReadLineMonad
- Language.Futhark.Parser.Monad: instance GHC.Base.Functor Language.Futhark.Parser.Monad.ReadLineMonad
- Language.Futhark.Parser.Monad: instance GHC.Base.Monad Language.Futhark.Parser.Monad.ReadLineMonad
- Language.Futhark.Parser.Monad: parseInMonad :: ParserMonad a -> FilePath -> Text -> ReadLineMonad (Either SyntaxError (a, [Comment]))
- Language.Futhark.Syntax: instance (GHC.Classes.Eq u, GHC.Classes.Eq dim) => GHC.Classes.Eq (Language.Futhark.Syntax.ScalarTypeBase dim u)
- Language.Futhark.Syntax: instance (GHC.Classes.Eq u, GHC.Classes.Eq dim) => GHC.Classes.Eq (Language.Futhark.Syntax.TypeBase dim u)
- Language.Futhark.Syntax: instance (GHC.Classes.Ord u, GHC.Classes.Ord dim) => GHC.Classes.Ord (Language.Futhark.Syntax.ScalarTypeBase dim u)
- Language.Futhark.Syntax: instance (GHC.Classes.Ord u, GHC.Classes.Ord dim) => GHC.Classes.Ord (Language.Futhark.Syntax.TypeBase dim u)
- Language.Futhark.Syntax: instance (GHC.Show.Show u, GHC.Show.Show dim) => GHC.Show.Show (Language.Futhark.Syntax.ScalarTypeBase dim u)
- Language.Futhark.Syntax: instance (GHC.Show.Show u, GHC.Show.Show dim) => GHC.Show.Show (Language.Futhark.Syntax.TypeBase dim u)
+ Futhark.CodeGen.ImpGen.GPU.Copy: copyKernel :: PrimType -> (TExp Int64, GroupDim) -> (VName, LMAD (TExp Int64)) -> (VName, LMAD (TExp Int64)) -> Kernel
+ Futhark.IR.Mem: instance (GHC.Classes.Eq d, GHC.Classes.Eq ret, GHC.Classes.Eq u) => GHC.Classes.Eq (Futhark.IR.Mem.MemInfo d u ret)
+ Futhark.IR.Mem: instance (GHC.Classes.Ord d, GHC.Classes.Ord ret, GHC.Classes.Ord u) => GHC.Classes.Ord (Futhark.IR.Mem.MemInfo d u ret)
+ Futhark.IR.Mem: instance (GHC.Show.Show d, GHC.Show.Show ret, GHC.Show.Show u) => GHC.Show.Show (Futhark.IR.Mem.MemInfo d u ret)
+ Futhark.IR.Mem.IxFun: [dims] :: LMAD num -> [LMADDim num]
+ Futhark.IR.Mem.IxFun: [ixfunLMAD] :: IxFun num -> LMAD num
+ Futhark.IR.Mem.IxFun: [offset] :: LMAD num -> num
+ Futhark.IR.Mem.IxFun: permutation :: IxFun num -> Permutation
+ Futhark.IR.Mem.LMAD: [dims] :: LMAD num -> [LMADDim num]
+ Futhark.IR.Mem.LMAD: [offset] :: LMAD num -> num
+ Futhark.IR.Mem.LMAD: contiguous :: (Pretty num, Eq num) => LMAD (TPrimExp Int64 num) -> TPrimExp Bool num
+ Futhark.IR.Mem.LMAD: flatSlice :: IntegralExp num => LMAD num -> FlatSlice num -> Maybe (LMAD num)
+ Futhark.IR.Mem.LMAD: index :: (IntegralExp num, Eq num) => LMAD num -> Indices num -> num
+ Futhark.IR.Mem.LMAD: iota :: IntegralExp num => num -> [num] -> LMAD num
+ Futhark.IR.Mem.LMAD: memcpyable :: (Pretty num, Eq num) => LMAD (TPrimExp Int64 num) -> LMAD (TPrimExp Int64 num) -> TPrimExp Bool num
+ Futhark.IR.Mem.LMAD: mkExistential :: [Int] -> Int -> LMAD (Ext a)
+ Futhark.IR.Mem.LMAD: noPermutation :: LMAD t -> LMAD t
+ Futhark.IR.Mem.LMAD: permutation :: LMAD num -> Permutation
+ Futhark.IR.Mem.LMAD: permute :: LMAD num -> Permutation -> LMAD num
+ Futhark.IR.Mem.LMAD: reshape :: (Eq num, IntegralExp num) => LMAD num -> Shape num -> Maybe (LMAD num)
+ Futhark.IR.Mem.LMAD: setPermutation :: Permutation -> LMAD num -> LMAD num
+ Futhark.IR.Mem.LMAD: setShape :: Shape num -> LMAD num -> LMAD num
+ Futhark.IR.Mem.LMAD: shape :: LMAD num -> Shape num
+ Futhark.IR.Mem.LMAD: shapeBase :: LMAD num -> Shape num
+ Futhark.IR.Mem.LMAD: slice :: (Eq num, IntegralExp num) => LMAD num -> Slice num -> LMAD num
+ Futhark.IR.Mem.LMAD: type Indices num = [num]
+ Futhark.IR.Syntax.Core: instance (GHC.Classes.Eq shape, GHC.Classes.Eq u) => GHC.Classes.Eq (Futhark.IR.Syntax.Core.TypeBase shape u)
+ Futhark.IR.Syntax.Core: instance (GHC.Classes.Ord shape, GHC.Classes.Ord u) => GHC.Classes.Ord (Futhark.IR.Syntax.Core.TypeBase shape u)
+ Futhark.IR.Syntax.Core: instance (GHC.Show.Show shape, GHC.Show.Show u) => GHC.Show.Show (Futhark.IR.Syntax.Core.TypeBase shape u)
+ Futhark.Passes: gpumemPipeline :: Pipeline SOACS GPUMem
+ Futhark.Passes: mcmemPipeline :: Pipeline SOACS MCMem
+ Futhark.Passes: seqPipeline :: Pipeline SOACS Seq
+ Futhark.Passes: seqmemPipeline :: Pipeline SOACS SeqMem
+ Futhark.Util.Pretty: italicized :: AnsiStyle
+ Futhark.Util.Pretty: underlined :: AnsiStyle
+ Language.Futhark.Parser: parseDecOrExp :: FilePath -> Text -> Either SyntaxError (Either UncheckedDec UncheckedExp)
+ Language.Futhark.Parser.Lexer.Tokens: advance :: Pos -> ByteString -> Pos
+ Language.Futhark.Parser.Lexer.Tokens: binToken :: Integral a => (a -> Token) -> ByteString -> Token
+ Language.Futhark.Parser.Lexer.Tokens: decToken :: Integral a => (a -> Token) -> ByteString -> Token
+ Language.Futhark.Parser.Lexer.Tokens: hexToken :: Integral a => (a -> Token) -> ByteString -> Token
+ Language.Futhark.Parser.Lexer.Tokens: romToken :: Integral a => (a -> Token) -> ByteString -> Token
+ Language.Futhark.Parser.Lexer.Wrapper: initialLexerState :: Pos -> ByteString -> AlexInput
+ Language.Futhark.Syntax: instance (GHC.Classes.Eq dim, GHC.Classes.Eq u) => GHC.Classes.Eq (Language.Futhark.Syntax.ScalarTypeBase dim u)
+ Language.Futhark.Syntax: instance (GHC.Classes.Eq dim, GHC.Classes.Eq u) => GHC.Classes.Eq (Language.Futhark.Syntax.TypeBase dim u)
+ Language.Futhark.Syntax: instance (GHC.Classes.Ord dim, GHC.Classes.Ord u) => GHC.Classes.Ord (Language.Futhark.Syntax.ScalarTypeBase dim u)
+ Language.Futhark.Syntax: instance (GHC.Classes.Ord dim, GHC.Classes.Ord u) => GHC.Classes.Ord (Language.Futhark.Syntax.TypeBase dim u)
+ Language.Futhark.Syntax: instance (GHC.Show.Show dim, GHC.Show.Show u) => GHC.Show.Show (Language.Futhark.Syntax.ScalarTypeBase dim u)
+ Language.Futhark.Syntax: instance (GHC.Show.Show dim, GHC.Show.Show u) => GHC.Show.Show (Language.Futhark.Syntax.TypeBase dim u)
- Futhark.CodeGen.ImpGen: isMapTransposeCopy :: PrimType -> MemLoc -> MemLoc -> Maybe (TExp Int64, TExp Int64, TExp Int64, TExp Int64, TExp Int64)
+ Futhark.CodeGen.ImpGen: isMapTransposeCopy :: PrimType -> MemLoc -> MemLoc -> Maybe (TExp Bool, (TExp Int64, TExp Int64, TExp Int64, TExp Int64, TExp Int64))
- Futhark.CodeGen.ImpGen: sCopy :: VName -> TExp Int64 -> Space -> VName -> TExp Int64 -> Space -> Count Elements (TExp Int64) -> PrimType -> ImpM rep r op ()
+ Futhark.CodeGen.ImpGen: sCopy :: VName -> Count Bytes (TExp Int64) -> Space -> VName -> Count Bytes (TExp Int64) -> Space -> Count Elements (TExp Int64) -> PrimType -> ImpM rep r op ()
- 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.Base: sCopy :: VName -> Count Bytes (TExp Int64) -> Space -> VName -> Count Bytes (TExp Int64) -> Space -> Count Elements (TExp Int64) -> PrimType -> ImpM rep r op ()
- Futhark.IR.Mem: expReturns :: (LocalScope rep m, Mem rep inner) => Exp rep -> m [ExpReturns]
+ Futhark.IR.Mem: expReturns :: (LocalScope rep m, Mem rep inner) => Exp rep -> m (Maybe [ExpReturns])
- Futhark.IR.Mem.IxFun: IxFun :: NonEmpty (LMAD num) -> Shape num -> Bool -> IxFun num
+ Futhark.IR.Mem.IxFun: IxFun :: LMAD num -> Shape num -> IxFun num
- Futhark.IR.Mem.IxFun: LMADDim :: num -> num -> Int -> Monotonicity -> LMADDim num
+ Futhark.IR.Mem.IxFun: LMADDim :: num -> num -> Int -> LMADDim num
- Futhark.IR.Mem.IxFun: flatSlice :: (Eq num, IntegralExp num) => IxFun num -> FlatSlice num -> IxFun num
+ Futhark.IR.Mem.IxFun: flatSlice :: (Eq num, IntegralExp num) => IxFun num -> FlatSlice num -> Maybe (IxFun num)
- Futhark.IR.Mem.IxFun: mkExistential :: Int -> [(Int, Monotonicity)] -> Bool -> Int -> IxFun (Ext a)
+ Futhark.IR.Mem.IxFun: mkExistential :: Int -> [Int] -> Int -> IxFun (Ext a)
- Futhark.IR.Mem.IxFun: rebase :: (Eq num, IntegralExp num) => IxFun num -> IxFun num -> IxFun num
+ Futhark.IR.Mem.IxFun: rebase :: (Eq num, IntegralExp num) => IxFun num -> IxFun num -> Maybe (IxFun num)
- Futhark.IR.Mem.IxFun: reshape :: (Eq num, IntegralExp num) => IxFun num -> Shape num -> IxFun num
+ Futhark.IR.Mem.IxFun: reshape :: (Eq num, IntegralExp num) => IxFun num -> Shape num -> Maybe (IxFun num)
- Futhark.IR.Mem.LMAD: LMADDim :: num -> num -> Int -> Monotonicity -> LMADDim num
+ Futhark.IR.Mem.LMAD: LMADDim :: num -> num -> Int -> LMADDim num
- Futhark.IR.Syntax: class Pretty a
+ Futhark.IR.Syntax: class () => Pretty a
- Futhark.LSP.Handlers: handlers :: IORef State -> Handlers (LspM ())
+ Futhark.LSP.Handlers: handlers :: IORef State -> ClientCapabilities -> Handlers (LspM ())
- Futhark.Passes: gpuPipeline :: Pipeline SOACS GPUMem
+ Futhark.Passes: gpuPipeline :: Pipeline SOACS GPU
- Futhark.Pkg.Types: data Chunk
+ Futhark.Pkg.Types: data () => Chunk
- Futhark.Pkg.Types: data SemVer
+ Futhark.Pkg.Types: data () => SemVer
- Futhark.Pkg.Types: newtype Release
+ Futhark.Pkg.Types: newtype () => Release
- Futhark.Test: data Mismatch
+ Futhark.Test: data () => Mismatch
- Futhark.Test: data Value
+ Futhark.Test: data () => Value
- Futhark.Util.Pretty: data AnsiStyle
+ Futhark.Util.Pretty: data () => AnsiStyle
- Futhark.Util.Pretty: data Color
+ Futhark.Util.Pretty: data () => Color
- Futhark.Util.Table: data AnsiStyle
+ Futhark.Util.Table: data () => AnsiStyle
- Futhark.Util.Table: data Color
+ Futhark.Util.Table: data () => Color
- Language.Futhark.Core: class Located a
+ Language.Futhark.Core: class () => Located a
- Language.Futhark.Core: data Half
+ Language.Futhark.Core: data () => Half
- Language.Futhark.Core: data Int16
+ Language.Futhark.Core: data () => Int16
- Language.Futhark.Core: data Int32
+ Language.Futhark.Core: data () => Int32
- Language.Futhark.Core: data Int64
+ Language.Futhark.Core: data () => Int64
- Language.Futhark.Core: data Int8
+ Language.Futhark.Core: data () => Int8
- Language.Futhark.Core: data Loc
+ Language.Futhark.Core: data () => Loc
- Language.Futhark.Core: data SrcLoc
+ Language.Futhark.Core: data () => SrcLoc
- Language.Futhark.Core: data Word16
+ Language.Futhark.Core: data () => Word16
- Language.Futhark.Core: data Word32
+ Language.Futhark.Core: data () => Word32
- Language.Futhark.Core: data Word64
+ Language.Futhark.Core: data () => Word64
- Language.Futhark.Core: data Word8
+ Language.Futhark.Core: data () => Word8
- Language.Futhark.Parser.Lexer.Tokens: mkQualId :: Text -> Alex ([Name], Name)
+ Language.Futhark.Parser.Lexer.Tokens: mkQualId :: Text -> ([Name], Name)
- Language.Futhark.Parser.Lexer.Tokens: readHexRealLit :: RealFloat a => Text -> Alex a
+ Language.Futhark.Parser.Lexer.Tokens: readHexRealLit :: RealFloat a => Text -> a
- Language.Futhark.Parser.Lexer.Tokens: tokenC :: a -> (Pos, Char, ByteString, Int64) -> Int64 -> Alex (Lexeme a)
+ Language.Futhark.Parser.Lexer.Tokens: tokenC :: a -> ByteString -> a
- Language.Futhark.Parser.Lexer.Tokens: tokenS :: (Text -> a) -> (Pos, Char, ByteString, Int64) -> Int64 -> Alex (Lexeme a)
+ Language.Futhark.Parser.Lexer.Tokens: tokenS :: (Text -> a) -> ByteString -> a
- Language.Futhark.Parser.Lexer.Tokens: tryRead :: Read a => String -> Text -> Alex a
+ Language.Futhark.Parser.Lexer.Tokens: tryRead :: Read a => String -> Text -> a
- Language.Futhark.Parser.Lexer.Wrapper: alexGetPos :: Alex Pos
+ Language.Futhark.Parser.Lexer.Wrapper: alexGetPos :: AlexInput -> Pos
- Language.Futhark.Parser.Monad: data L a
+ Language.Futhark.Parser.Monad: data () => L a
- Language.Futhark.Parser.Monad: type ParserMonad = ExceptT SyntaxError (StateT ParserState ReadLineMonad)
+ Language.Futhark.Parser.Monad: type ParserMonad = ExceptT SyntaxError (State ParserState)
- Language.Futhark.Primitive: data Half
+ Language.Futhark.Primitive: data () => Half
- Language.Futhark.Primitive: data Int16
+ Language.Futhark.Primitive: data () => Int16
- Language.Futhark.Primitive: data Int32
+ Language.Futhark.Primitive: data () => Int32
- Language.Futhark.Primitive: data Int64
+ Language.Futhark.Primitive: data () => Int64
- Language.Futhark.Primitive: data Int8
+ Language.Futhark.Primitive: data () => Int8
- Language.Futhark.Primitive: data Word16
+ Language.Futhark.Primitive: data () => Word16
- Language.Futhark.Primitive: data Word32
+ Language.Futhark.Primitive: data () => Word32
- Language.Futhark.Primitive: data Word64
+ Language.Futhark.Primitive: data () => Word64
- Language.Futhark.Primitive: data Word8
+ Language.Futhark.Primitive: data () => Word8
- Language.Futhark.Query: data Pos
+ Language.Futhark.Query: data () => Pos

Files

docs/man/futhark-repl.rst view
@@ -17,7 +17,8 @@ Start an interactive Futhark session.  This will let you interactively enter expressions and declarations which are then immediately interpreted.  If the entered line can be either a declaration or an-expression, it is assumed to be a declaration.+expression, it is assumed to be a declaration.  The input msut fit on+a single line.  Futhark source files can be loaded using the ``:load`` command.  This will erase any interactively entered definitions.  Use the ``:help``
docs/usage.rst view
@@ -482,9 +482,9 @@ When using the OpenCL backend, extra API functions are provided for directly accessing or providing the OpenCL objects used by Futhark. Take care when using these functions.  In particular, a Futhark-context can now be provided with the command queue to use::+context can now be configured with the command queue to use:: -  struct futhark_context *futhark_context_new_with_command_queue(struct futhark_context_config *cfg, cl_command_queue queue);+  void futhark_context_config_set_command_queue(struct futhark_context_config *cfg, cl_command_queue queue);  As a ``cl_command_queue`` specifies an OpenCL device, this is also how manual platform and device selection is possible.  A function is also
futhark.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name:           futhark-version:        0.25.1+version:        0.25.2 synopsis:       An optimising compiler for a functional, array-oriented language.  description:    Futhark is a small programming language designed to be compiled to@@ -248,6 +248,7 @@       Futhark.CodeGen.ImpGen.CUDA       Futhark.CodeGen.ImpGen.GPU       Futhark.CodeGen.ImpGen.GPU.Base+      Futhark.CodeGen.ImpGen.GPU.Copy       Futhark.CodeGen.ImpGen.GPU.Group       Futhark.CodeGen.ImpGen.GPU.SegHist       Futhark.CodeGen.ImpGen.GPU.SegMap@@ -494,8 +495,8 @@     , haskeline     , language-c-quote >= 0.12     , lens-    , lsp >= 2.0.0.0-    , lsp-types >= 2.0.0.0+    , lsp >= 2.1.0.0+    , lsp-types >= 2.0.1.0     , mainland-pretty >=0.7.1     , cmark-gfm >=0.2.1     , megaparsec >=9.0.0
rts/c/atomics.h view
@@ -1,5 +1,30 @@ // Start of atomics.h +inline int32_t atomic_xchg_i32_global(volatile __global int32_t *p, int32_t x);+inline int32_t atomic_xchg_i32_local(volatile __local int32_t *p, int32_t x);+inline int32_t atomic_cmpxchg_i32_global(volatile __global int32_t *p,+                                         int32_t cmp, int32_t val);+inline int32_t atomic_cmpxchg_i32_local(volatile __local int32_t *p,+                                        int32_t cmp, int32_t val);+inline int32_t atomic_add_i32_global(volatile __global int32_t *p, int32_t x);+inline int32_t atomic_add_i32_local(volatile __local int32_t *p, int32_t x);+inline float atomic_fadd_f32_global(volatile __global float *p, float x);+inline float atomic_fadd_f32_local(volatile __local float *p, float x);+inline int32_t atomic_smax_i32_global(volatile __global int32_t *p, int32_t x);+inline int32_t atomic_smax_i32_local(volatile __local int32_t *p, int32_t x);+inline int32_t atomic_smin_i32_global(volatile __global int32_t *p, int32_t x);+inline int32_t atomic_smin_i32_local(volatile __local int32_t *p, int32_t x);+inline uint32_t atomic_umax_i32_global(volatile __global uint32_t *p, uint32_t x);+inline uint32_t atomic_umax_i32_local(volatile __local uint32_t *p, uint32_t x);+inline uint32_t atomic_umin_i32_global(volatile __global uint32_t *p, uint32_t x);+inline uint32_t atomic_umin_i32_local(volatile __local uint32_t *p, uint32_t x);+inline int32_t atomic_and_i32_global(volatile __global int32_t *p, int32_t x);+inline int32_t atomic_and_i32_local(volatile __local int32_t *p, int32_t x);+inline int32_t atomic_or_i32_global(volatile __global int32_t *p, int32_t x);+inline int32_t atomic_or_i32_local(volatile __local int32_t *p, int32_t x);+inline int32_t atomic_xor_i32_global(volatile __global int32_t *p, int32_t x);+inline int32_t atomic_xor_i32_local(volatile __local int32_t *p, int32_t x);+ inline int32_t atomic_xchg_i32_global(volatile __global int32_t *p, int32_t x) { #ifdef FUTHARK_CUDA   return atomicExch((int32_t*)p, x);@@ -196,6 +221,36 @@  // Start of 64 bit atomics +#if defined(FUTHARK_CUDA) || defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics)++inline int64_t atomic_xchg_i64_global(volatile __global int64_t *p, int64_t x);+inline int64_t atomic_xchg_i64_local(volatile __local int64_t *p, int64_t x);+inline int64_t atomic_cmpxchg_i64_global(volatile __global int64_t *p,+                                         int64_t cmp, int64_t val);+inline int64_t atomic_cmpxchg_i64_local(volatile __local int64_t *p,+                                        int64_t cmp, int64_t val);+inline int64_t atomic_add_i64_global(volatile __global int64_t *p, int64_t x);+inline int64_t atomic_add_i64_local(volatile __local int64_t *p, int64_t x);+inline int64_t atomic_smax_i64_global(volatile __global int64_t *p, int64_t x);+inline int64_t atomic_smax_i64_local(volatile __local int64_t *p, int64_t x);+inline int64_t atomic_smin_i64_global(volatile __global int64_t *p, int64_t x);+inline int64_t atomic_smin_i64_local(volatile __local int64_t *p, int64_t x);+inline uint64_t atomic_umax_i64_global(volatile __global uint64_t *p, uint64_t x);+inline uint64_t atomic_umax_i64_local(volatile __local uint64_t *p, uint64_t x);+inline uint64_t atomic_umin_i64_global(volatile __global uint64_t *p, uint64_t x);+uint64_t atomic_umin_i64_local(volatile __local uint64_t *p, uint64_t x);+inline int64_t atomic_and_i64_global(volatile __global int64_t *p, int64_t x);+inline int64_t atomic_and_i64_local(volatile __local int64_t *p, int64_t x);+inline int64_t atomic_or_i64_global(volatile __global int64_t *p, int64_t x);+inline int64_t atomic_or_i64_local(volatile __local int64_t *p, int64_t x);+inline int64_t atomic_xor_i64_global(volatile __global int64_t *p, int64_t x);+inline int64_t atomic_xor_i64_local(volatile __local int64_t *p, int64_t x);++#ifdef FUTHARK_F64_ENABLED+inline double atomic_fadd_f64_global(volatile __global double *p, double x);+inline double atomic_fadd_f64_local(volatile __local double *p, double x);+#endif+ inline int64_t atomic_xchg_i64_global(volatile __global int64_t *p, int64_t x) { #ifdef FUTHARK_CUDA   return atomicExch((uint64_t*)p, x);@@ -393,5 +448,7 @@   return atom_xor(p, x); #endif }++#endif // defined(FUTHARK_CUDA) || defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics)  // End of atomics.h
rts/c/backends/cuda.h view
@@ -251,10 +251,10 @@   lock_t error_lock;   FILE *log;   struct constants *constants;-  struct free_list cu_free_list;+  struct free_list free_list;   int64_t peak_mem_usage_default;   int64_t cur_mem_usage_default;-  // Uniform above+  // Uniform fields above.    CUdeviceptr global_failure;   CUdeviceptr global_failure_args;@@ -270,8 +270,9 @@   CUdevice dev;   CUcontext cu_ctx;   CUmodule module;+  CUstream stream; -  struct free_list free_list;+  struct free_list cu_free_list;    size_t max_block_size;   size_t max_grid_size;@@ -307,8 +308,8 @@   struct futhark_context_config *cfg = ctx->cfg;   char name[256];   int count, chosen = -1, best_cc = -1;-  int cc_major_best, cc_minor_best;-  int cc_major, cc_minor;+  int cc_major_best = 0, cc_minor_best = 0;+  int cc_major = 0, cc_minor = 0;   CUdevice dev;    CUDA_SUCCEED_FATAL(cuDeviceGetCount(&count));@@ -385,11 +386,11 @@ }  static const char *cuda_nvrtc_get_arch(CUdevice dev) {-  struct {+  static struct {     int major;     int minor;     const char *arch_str;-  } static const x[] = {+  } const x[] = {     { 3, 0, "compute_30" },     { 3, 2, "compute_32" },     { 3, 5, "compute_35" },@@ -730,38 +731,15 @@   return NULL; } -static char* cuda_setup(struct futhark_context *ctx, const char *src_fragments[],-                        const char *extra_opts[], const char* cache_fname) {-  CUDA_SUCCEED_FATAL(cuInit(0));--  if (cuda_device_setup(ctx) != 0) {-    futhark_panic(-1, "No suitable CUDA device found.\n");-  }-  CUDA_SUCCEED_FATAL(cuCtxCreate(&ctx->cu_ctx, 0, ctx->dev));--  free_list_init(&ctx->cu_free_list);--  ctx->max_shared_memory = device_query(ctx->dev, MAX_SHARED_MEMORY_PER_BLOCK);-  ctx->max_block_size = device_query(ctx->dev, MAX_THREADS_PER_BLOCK);-  ctx->max_grid_size = device_query(ctx->dev, MAX_GRID_DIM_X);-  ctx->max_tile_size = sqrt(ctx->max_block_size);-  ctx->max_threshold = 0;-  ctx->max_bespoke = 0;-  ctx->lockstep_width = device_query(ctx->dev, WARP_SIZE);--  cuda_size_setup(ctx);-  return cuda_module_setup(ctx, src_fragments, extra_opts, cache_fname);-}- // Count up the runtime all the profiling_records that occured during execution. // Also clears the buffer of profiling_records.-static cudaError_t cuda_tally_profiling_records(struct futhark_context *ctx) {-  cudaError_t err;+static CUresult cuda_tally_profiling_records(struct futhark_context *ctx) {+  CUresult err;   for (int i = 0; i < ctx->profiling_records_used; i++) {     struct profiling_record record = ctx->profiling_records[i];      float ms;-    if ((err = cudaEventElapsedTime(&ms, record.events[0], record.events[1])) != cudaSuccess) {+    if ((err = cuEventElapsedTime(&ms, record.events[0], record.events[1])) != CUDA_SUCCESS) {       return err;     } @@ -769,10 +747,10 @@     *record.runs += 1;     *record.runtime += ms*1000; -    if ((err = cudaEventDestroy(record.events[0])) != cudaSuccess) {+    if ((err = cuEventDestroy(record.events[0])) != CUDA_SUCCESS) {       return err;     }-    if ((err = cudaEventDestroy(record.events[1])) != cudaSuccess) {+    if ((err = cuEventDestroy(record.events[1])) != CUDA_SUCCESS) {       return err;     } @@ -781,7 +759,7 @@    ctx->profiling_records_used = 0; -  return cudaSuccess;+  return CUDA_SUCCESS; }  // Returns pointer to two events.@@ -918,10 +896,28 @@   ctx->peak_mem_usage_device = 0;   ctx->cur_mem_usage_device = 0; -  ctx->error = cuda_setup(ctx, cuda_program, ctx->cfg->nvrtc_opts, ctx->cfg->cache_fname);+  CUDA_SUCCEED_FATAL(cuInit(0));+  if (cuda_device_setup(ctx) != 0) {+    futhark_panic(-1, "No suitable CUDA device found.\n");+  }+  CUDA_SUCCEED_FATAL(cuCtxCreate(&ctx->cu_ctx, 0, ctx->dev)); +  free_list_init(&ctx->cu_free_list);++  ctx->max_shared_memory = device_query(ctx->dev, MAX_SHARED_MEMORY_PER_BLOCK);+  ctx->max_block_size = device_query(ctx->dev, MAX_THREADS_PER_BLOCK);+  ctx->max_grid_size = device_query(ctx->dev, MAX_GRID_DIM_X);+  ctx->max_tile_size = sqrt(ctx->max_block_size);+  ctx->max_threshold = 0;+  ctx->max_bespoke = 0;+  ctx->lockstep_width = device_query(ctx->dev, WARP_SIZE);+  CUDA_SUCCEED_FATAL(cuStreamCreate(&ctx->stream, CU_STREAM_DEFAULT));+  cuda_size_setup(ctx);+  ctx->error = cuda_module_setup(ctx, cuda_program,+                                 ctx->cfg->nvrtc_opts, ctx->cfg->cache_fname);+   if (ctx->error != NULL) {-    futhark_panic(1, "%s\n", ctx->error);+    futhark_panic(1, "During CUDA initialisation:\n%s\n", ctx->error);   }    int32_t no_error = -1;@@ -938,6 +934,7 @@   CUDA_SUCCEED_FATAL(cuda_free_all(ctx));   (void)cuda_tally_profiling_records(ctx);   free(ctx->profiling_records);+  CUDA_SUCCEED_FATAL(cuStreamDestroy(ctx->stream));   CUDA_SUCCEED_FATAL(cuModuleUnload(ctx->module));   CUDA_SUCCEED_FATAL(cuCtxDestroy(ctx->cu_ctx)); }
src/Futhark/CLI/C.hs view
@@ -3,7 +3,7 @@  import Futhark.Actions (compileCAction) import Futhark.Compiler.CLI-import Futhark.Passes (sequentialCpuPipeline)+import Futhark.Passes (seqmemPipeline)  -- | Run @futhark c@ main :: String -> [String] -> IO ()@@ -12,6 +12,6 @@   []   "Compile sequential C"   "Generate sequential C code from optimised Futhark program."-  sequentialCpuPipeline+  seqmemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compileCAction fcfg mode outpath) prog
src/Futhark/CLI/CUDA.hs view
@@ -3,7 +3,7 @@  import Futhark.Actions (compileCUDAAction) import Futhark.Compiler.CLI-import Futhark.Passes (gpuPipeline)+import Futhark.Passes (gpumemPipeline)  -- | Run @futhark cuda@. main :: String -> [String] -> IO ()@@ -12,6 +12,6 @@   []   "Compile CUDA"   "Generate CUDA/C code from optimised Futhark program."-  gpuPipeline+  gpumemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compileCUDAAction fcfg mode outpath) prog
src/Futhark/CLI/Dev.hs view
@@ -639,7 +639,7 @@       "GPU"       GPU       "Run the default optimised kernels pipeline"-      kernelsPipeline+      gpuPipeline       []       ["gpu"],     pipelineOption@@ -647,7 +647,7 @@       "GPUMem"       GPUMem       "Run the full GPU compilation pipeline"-      gpuPipeline+      gpumemPipeline       []       ["gpu-mem"],     pipelineOption@@ -655,7 +655,7 @@       "Seq"       Seq       "Run the sequential CPU compilation pipeline"-      sequentialPipeline+      seqPipeline       []       ["seq"],     pipelineOption@@ -663,7 +663,7 @@       "SeqMem"       SeqMem       "Run the sequential CPU+memory compilation pipeline"-      sequentialCpuPipeline+      seqmemPipeline       []       ["seq-mem"],     pipelineOption@@ -679,7 +679,7 @@       "MCMem"       MCMem       "Run the multicore+memory compilation pipeline"-      multicorePipeline+      mcmemPipeline       []       ["mc-mem"]   ]
src/Futhark/CLI/Misc.hs view
@@ -22,7 +22,7 @@ import Futhark.Util (hashText, interactWithFileSafely) import Futhark.Util.Options import Futhark.Util.Pretty (prettyTextOneLine)-import Language.Futhark.Parser.Lexer (scanTokens)+import Language.Futhark.Parser.Lexer (scanTokensText) import Language.Futhark.Prop (isBuiltin) import Language.Futhark.Semantic (includeToString) import System.Environment (getExecutablePath)@@ -115,7 +115,7 @@ mainTokens = mainWithOptions () [] "program" $ \args () ->   case args of     [file] -> Just $ do-      res <- interactWithFileSafely (scanTokens (startPos file) <$> BS.readFile file)+      res <- interactWithFileSafely (scanTokensText (startPos file) <$> T.readFile file)       case res of         Nothing -> do           hPutStrLn stderr $ file <> ": file not found."
src/Futhark/CLI/Multicore.hs view
@@ -3,7 +3,7 @@  import Futhark.Actions (compileMulticoreAction) import Futhark.Compiler.CLI-import Futhark.Passes (multicorePipeline)+import Futhark.Passes (mcmemPipeline)  -- | Run @futhark multicore@. main :: String -> [String] -> IO ()@@ -12,6 +12,6 @@   []   "Compile to multicore C"   "Generate multicore C code from optimised Futhark program."-  multicorePipeline+  mcmemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compileMulticoreAction fcfg mode outpath) prog
src/Futhark/CLI/MulticoreISPC.hs view
@@ -3,7 +3,7 @@  import Futhark.Actions (compileMulticoreToISPCAction) import Futhark.Compiler.CLI-import Futhark.Passes (multicorePipeline)+import Futhark.Passes (mcmemPipeline)  -- | Run @futhark multicore@. main :: String -> [String] -> IO ()@@ -12,6 +12,6 @@   []   "Compile to multicore ISPC"   "Generate multicore ISPC code from optimised Futhark program."-  multicorePipeline+  mcmemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compileMulticoreToISPCAction fcfg mode outpath) prog
src/Futhark/CLI/MulticoreWASM.hs view
@@ -3,7 +3,7 @@  import Futhark.Actions (compileMulticoreToWASMAction) import Futhark.Compiler.CLI-import Futhark.Passes (multicorePipeline)+import Futhark.Passes (mcmemPipeline)  -- | Run @futhark c@ main :: String -> [String] -> IO ()@@ -12,6 +12,6 @@   []   "Compile to multicore WASM"   "Generate multicore WASM with the multicore C backend code from optimised Futhark program."-  multicorePipeline+  mcmemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compileMulticoreToWASMAction fcfg mode outpath) prog
src/Futhark/CLI/OpenCL.hs view
@@ -3,7 +3,7 @@  import Futhark.Actions (compileOpenCLAction) import Futhark.Compiler.CLI-import Futhark.Passes (gpuPipeline)+import Futhark.Passes (gpumemPipeline)  -- | Run @futhark opencl@ main :: String -> [String] -> IO ()@@ -12,6 +12,6 @@   []   "Compile OpenCL"   "Generate OpenCL/C code from optimised Futhark program."-  gpuPipeline+  gpumemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compileOpenCLAction fcfg mode outpath) prog
src/Futhark/CLI/PyOpenCL.hs view
@@ -12,6 +12,6 @@   []   "Compile PyOpenCL"   "Generate Python + OpenCL code from optimised Futhark program."-  gpuPipeline+  gpumemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compilePyOpenCLAction fcfg mode outpath) prog
src/Futhark/CLI/Python.hs view
@@ -12,6 +12,6 @@   []   "Compile sequential Python"   "Generate sequential Python code from optimised Futhark program."-  sequentialCpuPipeline+  seqmemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compilePythonAction fcfg mode outpath) prog
src/Futhark/CLI/REPL.hs view
@@ -20,7 +20,7 @@ import Futhark.MonadFreshNames import Futhark.Util (fancyTerminal) import Futhark.Util.Options-import Futhark.Util.Pretty (AnsiStyle, Color (..), Doc, align, annotate, bgColorDull, bold, brackets, color, docText, docTextForHandle, hardline, oneLine, pretty, putDoc, putDocLn, unAnnotate, (<+>))+import Futhark.Util.Pretty (AnsiStyle, Color (..), Doc, align, annotate, bgColorDull, bold, brackets, color, docText, docTextForHandle, hardline, italicized, oneLine, pretty, putDoc, putDocLn, unAnnotate, (<+>)) import Futhark.Version import Language.Futhark import Language.Futhark.Interpreter qualified as I@@ -220,9 +220,7 @@               <> mconcat (intersperse ", " (map fst matches))     _ -> do       -- Read a declaration or expression.-      maybe_dec_or_e <- parseDecOrExpIncrM (inputLine "  ") prompt line--      case maybe_dec_or_e of+      case parseDecOrExp prompt line of         Left (SyntaxError _ err) -> liftIO $ T.putStrLn err         Right (Left d) -> onDec d         Right (Right e) -> onExp e@@ -396,10 +394,13 @@  typeCommand :: Command typeCommand = genTypeCommand parseExp T.checkExp $ \(ps, e) ->-  oneLine (pretty e)-    <> foldMap ((" " <>) . pretty) ps-    <> " : "-    <> oneLine (pretty (typeOf e))+  oneLine (pretty (typeOf e))+    <> if not (null ps)+      then+        annotate italicized $+          "\n\nPolymorphic in"+            <+> mconcat (intersperse " " $ map pretty ps) <> "."+      else mempty  mtypeCommand :: Command mtypeCommand = genTypeCommand parseModExp T.checkModExp $ pretty . fst
src/Futhark/CLI/WASM.hs view
@@ -3,7 +3,7 @@  import Futhark.Actions (compileCtoWASMAction) import Futhark.Compiler.CLI-import Futhark.Passes (sequentialCpuPipeline)+import Futhark.Passes (seqmemPipeline)  -- | Run @futhark c@ main :: String -> [String] -> IO ()@@ -12,6 +12,6 @@   []   "Compile to WASM"   "Generate WASM with the sequential C backend code from optimised Futhark program."-  sequentialCpuPipeline+  seqmemPipeline   $ \fcfg () mode outpath prog ->     actionProcedure (compileCtoWASMAction fcfg mode outpath) prog
src/Futhark/CodeGen/Backends/CCUDA.hs view
@@ -11,6 +11,7 @@ where  import Control.Monad+import Data.List (unzip4) import Data.Maybe (catMaybes) import Data.Text qualified as T import Futhark.CodeGen.Backends.CCUDA.Boilerplate@@ -152,7 +153,7 @@                 cuMemcpyHtoDAsync($exp:mem + $exp:idx * sizeof($ty:t),                                   &$id:val',                                   sizeof($ty:t),-                                  0));+                                  ctx->stream));               $items:aft              }|] writeCUDAScalar mem idx t "device" _ val = do@@ -226,9 +227,9 @@     memcpyFun _ (Space "device") (Space "device") =       ([C.cexp|cuMemcpy($exp:dst, $exp:src, $exp:nbytes)|], copyDevToDev)     memcpyFun GC.CopyNoBarrier DefaultSpace (Space "device") =-      ([C.cexp|cuMemcpyDtoHAsync($exp:dst, $exp:src, $exp:nbytes, 0)|], copyDevToHost)+      ([C.cexp|cuMemcpyDtoHAsync($exp:dst, $exp:src, $exp:nbytes, ctx->stream)|], copyDevToHost)     memcpyFun GC.CopyNoBarrier (Space "device") DefaultSpace =-      ([C.cexp|cuMemcpyHtoDAsync($exp:dst, $exp:src, $exp:nbytes, 0)|], copyHostToDev)+      ([C.cexp|cuMemcpyHtoDAsync($exp:dst, $exp:src, $exp:nbytes, ctx->stream)|], copyHostToDev)     memcpyFun _ _ _ =       error $         "Cannot copy to '"@@ -274,21 +275,81 @@   let e = kernelConstToExp $ SizeMaxConst size_class   GC.stm [C.cstm|$id:v = $exp:e;|] callKernel (LaunchKernel safety kernel_name args num_blocks block_size) = do-  args_arr <- newVName "kernel_args"-  time_start <- newVName "time_start"-  time_end <- newVName "time_end"-  (args', shared_vars) <- mapAndUnzipM mkArgs args+  (arg_params, arg_params_inits, call_args, shared_vars) <-+    unzip4 <$> zipWithM mkArgs [(0 :: Int) ..] args   let (shared_sizes, shared_offsets) = unzip $ catMaybes shared_vars       shared_offsets_sc = mkOffsets shared_sizes       shared_args = zip shared_offsets shared_offsets_sc-      shared_tot = last shared_offsets_sc+      shared_bytes = last shared_offsets_sc   forM_ shared_args $ \(arg, offset) ->     GC.decl [C.cdecl|unsigned int $id:arg = $exp:offset;|]    (grid_x, grid_y, grid_z) <- mkDims <$> mapM GC.compileExp num_blocks   (block_x, block_y, block_z) <- mkDims <$> mapM compileGroupDim block_size-  let perm_args-        | length num_blocks == 3 = [[C.cinit|&perm[0]|], [C.cinit|&perm[1]|], [C.cinit|&perm[2]|]]++  let need_perm = length num_blocks == 3+  kernel_fname <- genKernelFunction kernel_name safety need_perm arg_params arg_params_inits++  GC.stm+    [C.cstm|{+           err = $id:kernel_fname(ctx,+                                  $exp:grid_x,$exp:grid_y,$exp:grid_z,+                                  $exp:block_x, $exp:block_y, $exp:block_z,+                                  $exp:shared_bytes,+                                  $args:call_args);+           if (err != FUTHARK_SUCCESS) { goto cleanup; }+           }|]++  when (safety >= SafetyFull) $+    GC.stm [C.cstm|ctx->failure_is_an_option = 1;|]+  where+    mkDims [] = ([C.cexp|0|], [C.cexp|0|], [C.cexp|0|])+    mkDims [x] = (x, [C.cexp|1|], [C.cexp|1|])+    mkDims [x, y] = (x, y, [C.cexp|1|])+    mkDims (x : y : z : _) = (x, y, z)+    addExp x y = [C.cexp|$exp:x + $exp:y|]+    alignExp e = [C.cexp|$exp:e + ((8 - ($exp:e % 8)) % 8)|]+    mkOffsets = scanl (\a b -> a `addExp` alignExp b) [C.cexp|0|]+    mkArgs i (ValueKArg e t) = do+      e' <- GC.compileExp e+      pure+        ( [C.cparam|$ty:(primStorageType t) $id:("arg" <> show i)|],+          [C.cinit|&$id:("arg" <> show i)|],+          toStorage t e',+          Nothing+        )+    mkArgs i (MemKArg v) = do+      v' <- GC.rawMem v+      pure+        ( [C.cparam|typename CUdeviceptr $id:("arg" <> show i)|],+          [C.cinit|&$id:("arg" <> show i)|],+          v',+          Nothing+        )+    mkArgs i (SharedMemoryKArg (Count c)) = do+      num_bytes <- GC.compileExp c+      size <- newVName "shared_size"+      offset <- newVName "shared_offset"+      GC.decl [C.cdecl|unsigned int $id:size = $exp:num_bytes;|]+      pure+        ( [C.cparam|unsigned int $id:("arg" <> show i)|],+          [C.cinit|&$id:("arg" <> show i)|],+          [C.cexp|$id:offset|],+          Just (size, offset)+        )++genKernelFunction ::+  KernelName ->+  KernelSafety ->+  Bool ->+  [C.Param] ->+  [C.Initializer] ->+  GC.CompilerM op s Name+genKernelFunction kernel_name safety need_perm arg_params arg_params_inits = do+  let kernel_fname = "gpu_kernel_" <> kernel_name+      (bef, aft) = profilingEnclosure kernel_name+      perm_args+        | need_perm = [[C.cinit|&perm[0]|], [C.cinit|&perm[1]|], [C.cinit|&perm[2]|]]         | otherwise = []       failure_args =         take@@ -297,92 +358,56 @@             [C.cinit|&ctx->failure_is_an_option|],             [C.cinit|&ctx->global_failure_args|]           ]-      args'' = perm_args ++ failure_args ++ [[C.cinit|&$id:a|] | a <- args']-      sizes_nonzero =-        expsNotZero-          [ grid_x,-            grid_y,-            grid_z,-            block_x,-            block_y,-            block_z-          ]-      (bef, aft) = profilingEnclosure kernel_name -  GC.stm-    [C.cstm|-    if ($exp:sizes_nonzero) {+  GC.libDecl+    [C.cedecl|static int $id:kernel_fname(+                struct futhark_context* ctx, unsigned int grid_x, unsigned int grid_y, unsigned int grid_z,+                unsigned int block_x, unsigned int block_y, unsigned int block_z,+                unsigned int shared_bytes, $params:arg_params) {+    if (grid_x * grid_y * grid_z * block_x * block_y * block_z != 0) {       int perm[3] = { 0, 1, 2 }; -      if ($exp:grid_y >= (1<<16)) {+      if (grid_y >= (1<<16)) {         perm[1] = perm[0];         perm[0] = 1;       } -      if ($exp:grid_z >= (1<<16)) {+      if (grid_z >= (1<<16)) {         perm[2] = perm[0];         perm[0] = 2;       }        size_t grid[3];-      grid[perm[0]] = $exp:grid_x;-      grid[perm[1]] = $exp:grid_y;-      grid[perm[2]] = $exp:grid_z;+      grid[perm[0]] = grid_x;+      grid[perm[1]] = grid_y;+      grid[perm[2]] = grid_z; -      void *$id:args_arr[] = { $inits:args'' };-      typename int64_t $id:time_start = 0, $id:time_end = 0;+      void *all_args[] = { $inits:(perm_args ++ failure_args ++ arg_params_inits) };+      typename int64_t time_start = 0, time_end = 0;       if (ctx->debugging) {-        fprintf(ctx->log, "Launching %s with grid size [%ld, %ld, %ld] and block size [%ld, %ld, %ld]; shared memory: %d bytes.\n",+        fprintf(ctx->log, "Launching %s with grid size [%d, %d, %d] and block size [%d, %d, %d]; shared memory: %d bytes.\n",                 $string:(prettyString kernel_name),-                (long int)$exp:grid_x, (long int)$exp:grid_y, (long int)$exp:grid_z,-                (long int)$exp:block_x, (long int)$exp:block_y, (long int)$exp:block_z,-                (int)$exp:shared_tot);-        $id:time_start = get_wall_time();+                grid_x, grid_y, grid_z,+                block_x, block_y, block_z,+                shared_bytes);+        time_start = get_wall_time();       }       $items:bef       CUDA_SUCCEED_OR_RETURN(         cuLaunchKernel(ctx->program->$id:kernel_name,                        grid[0], grid[1], grid[2],-                       $exp:block_x, $exp:block_y, $exp:block_z,-                       $exp:shared_tot, NULL,-                       $id:args_arr, NULL));+                       block_x, block_y, block_z,+                       shared_bytes, ctx->stream,+                       all_args, NULL));       $items:aft       if (ctx->debugging) {         CUDA_SUCCEED_FATAL(cuCtxSynchronize());-        $id:time_end = get_wall_time();+        time_end = get_wall_time();         fprintf(ctx->log, "Kernel %s runtime: %ldus\n",-                $string:(prettyString kernel_name), $id:time_end - $id:time_start);+                $string:(prettyString kernel_name), time_end - time_start);       }-    }|]+    }+    return FUTHARK_SUCCESS;+  }|] -  when (safety >= SafetyFull) $-    GC.stm [C.cstm|ctx->failure_is_an_option = 1;|]-  where-    mkDims [] = ([C.cexp|0|], [C.cexp|0|], [C.cexp|0|])-    mkDims [x] = (x, [C.cexp|1|], [C.cexp|1|])-    mkDims [x, y] = (x, y, [C.cexp|1|])-    mkDims (x : y : z : _) = (x, y, z)-    addExp x y = [C.cexp|$exp:x + $exp:y|]-    alignExp e = [C.cexp|$exp:e + ((8 - ($exp:e % 8)) % 8)|]-    mkOffsets = scanl (\a b -> a `addExp` alignExp b) [C.cexp|0|]-    expNotZero e = [C.cexp|$exp:e != 0|]-    expAnd a b = [C.cexp|$exp:a && $exp:b|]-    expsNotZero = foldl expAnd [C.cexp|1|] . map expNotZero-    mkArgs (ValueKArg e t@(FloatType Float16)) = do-      arg <- newVName "kernel_arg"-      e' <- GC.compileExp e-      GC.item [C.citem|$ty:(primStorageType t) $id:arg = $exp:(toStorage t e');|]-      pure (arg, Nothing)-    mkArgs (ValueKArg e t) =-      (,Nothing) <$> GC.compileExpToName "kernel_arg" t e-    mkArgs (MemKArg v) = do-      v' <- GC.rawMem v-      arg <- newVName "kernel_arg"-      GC.decl [C.cdecl|typename CUdeviceptr $id:arg = $exp:v';|]-      pure (arg, Nothing)-    mkArgs (SharedMemoryKArg (Count c)) = do-      num_bytes <- GC.compileExp c-      size <- newVName "shared_size"-      offset <- newVName "shared_offset"-      GC.decl [C.cdecl|unsigned int $id:size = $exp:num_bytes;|]-      pure (offset, Just (size, offset))+  pure kernel_fname
src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs view
@@ -37,17 +37,17 @@ profilingEnclosure :: Name -> ([C.BlockItem], [C.BlockItem]) profilingEnclosure name =   ( [C.citems|-      typename cudaEvent_t *pevents = NULL;+      typename CUevent *pevents = NULL;       if (ctx->profiling && !ctx->profiling_paused) {         pevents = cuda_get_events(ctx,                                   &ctx->program->$id:(kernelRuns name),                                   &ctx->program->$id:(kernelRuntime name));-        CUDA_SUCCEED_FATAL(cudaEventRecord(pevents[0], 0));+        CUDA_SUCCEED_FATAL(cuEventRecord(pevents[0], ctx->stream));       }       |],     [C.citems|       if (pevents != NULL) {-        CUDA_SUCCEED_FATAL(cudaEventRecord(pevents[1], 0));+        CUDA_SUCCEED_FATAL(cuEventRecord(pevents[1], ctx->stream));       }       |]   )
src/Futhark/CodeGen/Backends/COpenCL.hs view
@@ -11,7 +11,6 @@ where  import Control.Monad hiding (mapM)-import Data.List (intercalate) import Data.Text qualified as T import Futhark.CodeGen.Backends.COpenCL.Boilerplate import Futhark.CodeGen.Backends.GenericC qualified as GC@@ -320,111 +319,107 @@                                               &ctx->failure_is_an_option));     |] -  zipWithM_ setKernelArg [numFailureParams safety ..] args+  (arg_params, arg_set, call_args) <-+    unzip3 <$> zipWithM onArg [(0 :: Int) ..] args+   num_workgroups' <- mapM GC.compileExp num_workgroups   workgroup_size' <- mapM compileGroupDim workgroup_size   local_bytes <- foldM localBytes [C.cexp|0|] args -  launchKernel name num_workgroups' workgroup_size' local_bytes+  kernel_fname <- genKernelFunction name safety arg_params arg_set +  let grid_x : grid_y : grid_z : _ = num_workgroups' ++ repeat [C.cexp|1|]+      group_x : group_y : group_z : _ = workgroup_size' ++ repeat [C.cexp|1|]++  GC.stm+    [C.cstm|{+           err = $id:kernel_fname(ctx,+                                  $exp:grid_x,$exp:grid_y,$exp:grid_z,+                                  $exp:group_x, $exp:group_y, $exp:group_z,+                                  $exp:local_bytes,+                                  $args:call_args);+           if (err != FUTHARK_SUCCESS) { goto cleanup; }+           }|]+   when (safety >= SafetyFull) $     GC.stm [C.cstm|ctx->failure_is_an_option = 1;|]   where-    setKernelArg i (ValueKArg e pt) = do-      v <- case pt of-        -- We always transfer f16 values to the kernel as 16 bits, but-        -- the actual host type may be typedef'd to a 32-bit float.-        -- This requires some care.-        FloatType Float16 -> do-          v <- newVName "kernel_arg"-          e' <- toStorage pt <$> GC.compileExp e-          GC.decl [C.cdecl|$ty:(primStorageType pt) $id:v = $e';|]-          pure v-        _ -> GC.compileExpToName "kernel_arg" pt e-      GC.stm-        [C.cstm|-            OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:name, $int:i, sizeof($id:v), &$id:v));-          |]-    setKernelArg i (MemKArg v) = do-      v' <- GC.rawMem v-      GC.stm-        [C.cstm|-            OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:name, $int:i, sizeof($exp:v'), &$exp:v'));-          |]-    setKernelArg i (SharedMemoryKArg num_bytes) = do-      num_bytes' <- GC.compileExp $ unCount num_bytes-      GC.stm-        [C.cstm|-            OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:name, $int:i, (size_t)$exp:num_bytes', NULL));-            |]-     localBytes cur (SharedMemoryKArg num_bytes) = do       num_bytes' <- GC.compileExp $ unCount num_bytes       pure [C.cexp|$exp:cur + $exp:num_bytes'|]     localBytes cur _ = pure cur -launchKernel ::-  C.ToExp a =>-  KernelName ->-  [a] ->-  [a] ->-  a ->-  GC.CompilerM op s ()-launchKernel kernel_name num_workgroups workgroup_dims local_bytes = do-  global_work_size <- newVName "global_work_size"-  time_start <- newVName "time_start"-  time_end <- newVName "time_end"-  time_diff <- newVName "time_diff"-  local_work_size <- newVName "local_work_size"--  let (debug_str, debug_args) = debugPrint global_work_size local_work_size+    onArg i (ValueKArg e t) = do+      let arg = "arg" <> show i+      e' <- GC.compileExp e+      pure+        ( [C.cparam|$ty:(primStorageType t) $id:arg|],+          ([C.cexp|sizeof($id:arg)|], [C.cexp|&$id:arg|]),+          toStorage t e'+        )+    onArg i (MemKArg v) = do+      let arg = "arg" <> show i+      v' <- GC.rawMem v+      pure+        ( [C.cparam|typename cl_mem $id:arg|],+          ([C.cexp|sizeof($id:arg)|], [C.cexp|&$id:arg|]),+          v'+        )+    onArg i (SharedMemoryKArg (Count c)) = do+      let arg = "arg" <> show i+      num_bytes <- GC.compileExp c+      pure+        ( [C.cparam|unsigned int $id:arg|],+          ([C.cexp|$id:arg|], [C.cexp|NULL|]),+          num_bytes+        ) -  GC.stm-    [C.cstm|-    if ($exp:total_elements != 0) {-      const size_t $id:global_work_size[$int:kernel_rank] = {$inits:kernel_dims'};-      const size_t $id:local_work_size[$int:kernel_rank] = {$inits:workgroup_dims'};-      typename int64_t $id:time_start = 0, $id:time_end = 0;+genKernelFunction ::+  KernelName ->+  KernelSafety ->+  [C.Param] ->+  [(C.Exp, C.Exp)] ->+  GC.CompilerM op s Name+genKernelFunction kernel_name safety arg_params arg_set = do+  let kernel_fname = "gpu_kernel_" <> kernel_name+  GC.libDecl+    [C.cedecl|static int $id:kernel_fname(+                struct futhark_context* ctx,+                unsigned int grid_x, unsigned int grid_y, unsigned int grid_z,+                unsigned int block_x, unsigned int block_y, unsigned int block_z,+                unsigned int local_bytes, $params:arg_params) {+    (void)local_bytes;+    if (grid_x * grid_y * grid_z * block_x * block_y * block_z != 0) {+      const size_t global_work_size[3] = {grid_x*block_x, grid_y*block_y, grid_z*block_z};+      const size_t local_work_size[3] = {block_x, block_y, block_z};+      typename int64_t time_start = 0, time_end = 0;+      $stms:set_args       if (ctx->debugging) {-        fprintf(ctx->log, $string:debug_str, $args:debug_args);-        $id:time_start = get_wall_time();+        fprintf(ctx->log, "Launching %s with grid size [%d, %d, %d] and group size [%d, %d, %d]; local memory: %d bytes.\n",+                $string:(prettyString kernel_name),+                grid_x, grid_y, grid_z,+                block_x, block_y, block_z,+                local_bytes);+        time_start = get_wall_time();       }       typename cl_event *pevent = $exp:(profilingEvent kernel_name);       OPENCL_SUCCEED_OR_RETURN(-        clEnqueueNDRangeKernel(ctx->queue, ctx->program->$id:kernel_name, $int:kernel_rank, NULL,-                               $id:global_work_size, $id:local_work_size,+        clEnqueueNDRangeKernel(ctx->queue, ctx->program->$id:kernel_name, 3, NULL,+                               global_work_size, local_work_size,                                0, NULL, pevent));       if (ctx->debugging) {         OPENCL_SUCCEED_FATAL(clFinish(ctx->queue));-        $id:time_end = get_wall_time();-        long int $id:time_diff = $id:time_end - $id:time_start;+        time_end = get_wall_time();+        long int time_diff = time_end - time_start;         fprintf(ctx->log, "kernel %s runtime: %ldus\n",-                $string:(prettyString kernel_name), $id:time_diff);+                $string:(prettyString kernel_name), time_diff);       }-    }|]-  where-    kernel_rank = length kernel_dims-    kernel_dims = zipWith multExp (map toSize num_workgroups) (map toSize workgroup_dims)-    kernel_dims' = map toInit kernel_dims-    workgroup_dims' = map (toInit . toSize) workgroup_dims-    total_elements = foldl multExp [C.cexp|1|] kernel_dims--    toInit e = [C.cinit|$exp:e|]-    multExp x y = [C.cexp|$exp:x * $exp:y|]-    toSize e = [C.cexp|(size_t)$exp:e|]+    }+    return FUTHARK_SUCCESS;+  }|] -    debugPrint :: VName -> VName -> (String, [C.Exp])-    debugPrint global_work_size local_work_size =-      ( "Launching %s with global work size "-          ++ dims-          ++ " and local work size "-          ++ dims-          ++ "; local memory: %d bytes.\n",-        [C.cexp|$string:(prettyString kernel_name)|]-          : map (kernelDim global_work_size) [0 .. kernel_rank - 1]-          ++ map (kernelDim local_work_size) [0 .. kernel_rank - 1]-          ++ [[C.cexp|(int)$exp:local_bytes|]]-      )-      where-        dims = "[" ++ intercalate ", " (replicate kernel_rank "%zu") ++ "]"-        kernelDim arr i = [C.cexp|$id:arr[$int:i]|]+  pure kernel_fname+  where+    set_args = zipWith setKernelArg [numFailureParams safety ..] arg_set+    setKernelArg i (size, e) =+      [C.cstm|OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:kernel_name, $int:i, $exp:size, $exp:e));|]
src/Futhark/CodeGen/Backends/SimpleRep.hs view
@@ -209,11 +209,11 @@ instance C.ToExp FloatValue where   toExp (Float16Value x) _     | isInfinite x =-        if x > 0 then [C.cexp|INFINITY|] else [C.cexp|-INFINITY|]+        if x > 0 then [C.cexp|(typename f16)INFINITY|] else [C.cexp|(typename f16)-INFINITY|]     | isNaN x =-        [C.cexp|NAN|]+        [C.cexp|(typename f16)NAN|]     | otherwise =-        [C.cexp|$float:(fromRational (toRational x))|]+        [C.cexp|(typename f16)$float:(fromRational (toRational x))|]   toExp (Float32Value x) _     | isInfinite x =         if x > 0 then [C.cexp|INFINITY|] else [C.cexp|-INFINITY|]
src/Futhark/CodeGen/ImpCode.hs view
@@ -602,8 +602,11 @@         If {} -> pretty fbranch         _ ->           "{" </> indent 2 (pretty fbranch) </> "}"+  pretty (Call [] fname args) =+    "call" <+> pretty fname <> parens (commasep $ map pretty args)   pretty (Call dests fname args) =-    commasep (map pretty dests)+    "call"+      <+> commasep (map pretty dests)       <+> "<-"       <+> pretty fname <> parens (commasep $ map pretty args)   pretty (Comment s code) =
src/Futhark/CodeGen/ImpGen.hs view
@@ -146,6 +146,7 @@ import Futhark.Construct hiding (ToExp (..)) import Futhark.IR.Mem import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.IR.SOACS (SOACS) import Futhark.Util import Futhark.Util.IntegralExp@@ -207,9 +208,9 @@ sliceMemLoc (MemLoc mem shape ixfun) slice =   MemLoc mem shape $ IxFun.slice ixfun slice -flatSliceMemLoc :: MemLoc -> FlatSlice (Imp.TExp Int64) -> MemLoc+flatSliceMemLoc :: MemLoc -> FlatSlice (Imp.TExp Int64) -> Maybe MemLoc flatSliceMemLoc (MemLoc mem shape ixfun) slice =-  MemLoc mem shape $ IxFun.flatSlice ixfun slice+  MemLoc mem shape <$> IxFun.flatSlice ixfun slice  data ArrayEntry = ArrayEntry   { entryArrayLoc :: MemLoc,@@ -931,7 +932,9 @@ defCompileBasicOp (Pat [pe]) (FlatUpdate _ slice v) = do   pe_loc <- entryArrayLoc <$> lookupArray (patElemName pe)   v_loc <- entryArrayLoc <$> lookupArray v-  copy (elemType (patElemType pe)) (flatSliceMemLoc pe_loc slice') v_loc+  case flatSliceMemLoc pe_loc slice' of+    Just pe_loc' -> copy (elemType (patElemType pe)) pe_loc' v_loc+    Nothing -> error "defCompileBasicOp FlatUpdate"   where     slice' = fmap pe64 slice defCompileBasicOp (Pat [pe]) (Replicate shape se)@@ -1401,8 +1404,8 @@ copy :: CopyCompiler rep r op copy   bt-  dst@(MemLoc dst_name _ dst_ixfn@(IxFun.IxFun dst_lmads@(dst_lmad :| _) _ _))-  src@(MemLoc src_name _ src_ixfn@(IxFun.IxFun src_lmads@(src_lmad :| _) _ _)) = do+  dst@(MemLoc dst_name _ dst_ixfn@(IxFun.IxFun dst_lmad _))+  src@(MemLoc src_name _ src_ixfn@(IxFun.IxFun src_lmad _)) = do     -- If we can statically determine that the two index-functions     -- are equivalent, don't do anything     unless (dst_name == src_name && dst_ixfn `IxFun.equivalent` src_ixfn)@@ -1410,7 +1413,7 @@       -- It's also possible that we can dynamically determine that the two       -- index-functions are equivalent.       sUnless-        ( fromBool (dst_name == src_name && length dst_lmads == 1 && length src_lmads == 1)+        ( fromBool (dst_name == src_name)             .&&. IxFun.dynamicEqualsLMAD dst_lmad src_lmad         )       $ do@@ -1418,44 +1421,54 @@         cc <- asks envCopyCompiler         cc bt dst src --- | Is this copy really a mapping with transpose?+-- | Is this copy really a mapping with transpose?  Produce an+-- expression that is true if so, as well as other expressions that+-- contain information about the transpose in that case (don't trust+-- these if the boolean is false). isMapTransposeCopy ::   PrimType ->   MemLoc ->   MemLoc ->   Maybe-    ( Imp.TExp Int64,-      Imp.TExp Int64,-      Imp.TExp Int64,-      Imp.TExp Int64,-      Imp.TExp Int64+    ( Imp.TExp Bool,+      ( Imp.TExp Int64,+        Imp.TExp Int64,+        Imp.TExp Int64,+        Imp.TExp Int64,+        Imp.TExp Int64+      )     )-isMapTransposeCopy bt (MemLoc _ _ destIxFun) (MemLoc _ _ srcIxFun)-  | Just (dest_offset, perm_and_destshape) <- IxFun.rearrangeWithOffset destIxFun bt_size,-    (perm, destshape) <- unzip perm_and_destshape,-    Just src_offset <- IxFun.linearWithOffset srcIxFun bt_size,+isMapTransposeCopy pt (MemLoc _ _ destIxFun) (MemLoc _ _ srcIxFun)+  | perm <- LMAD.permutation dest_lmad,+    LMAD.permutation src_lmad == [0 .. rank - 1],     Just (r1, r2, _) <- isMapTranspose perm =-      isOk destshape swap r1 r2 dest_offset src_offset-  | Just dest_offset <- IxFun.linearWithOffset destIxFun bt_size,-    Just (src_offset, perm_and_srcshape) <- IxFun.rearrangeWithOffset srcIxFun bt_size,-    (perm, srcshape) <- unzip perm_and_srcshape,+      isOk (IxFun.shape destIxFun) swap r1 r2+  | perm <- LMAD.permutation src_lmad,+    LMAD.permutation dest_lmad == [0 .. rank - 1],     Just (r1, r2, _) <- isMapTranspose perm =-      isOk srcshape id r1 r2 dest_offset src_offset+      isOk (IxFun.shape srcIxFun) id r1 r2   | otherwise =       Nothing   where-    bt_size = primByteSize bt+    rank = IxFun.rank destIxFun     swap (x, y) = (y, x)+    dest_lmad = IxFun.ixfunLMAD destIxFun+    src_lmad = IxFun.ixfunLMAD srcIxFun+    dest_offset = LMAD.offset dest_lmad+    src_offset = LMAD.offset src_lmad -    isOk shape f r1 r2 dest_offset src_offset = do+    isOk shape f r1 r2 =       let (num_arrays, size_x, size_y) = getSizes shape f r1 r2-      pure-        ( dest_offset,-          src_offset,-          num_arrays,-          size_x,-          size_y-        )+       in Just+            ( LMAD.contiguous dest_lmad+                .&&. LMAD.contiguous src_lmad,+              ( dest_offset * primByteSize pt,+                src_offset * primByteSize pt,+                num_arrays,+                size_x,+                size_y+              )+            )      getSizes shape f r1 r2 =       let (mapped, notmapped) = splitAt r1 shape@@ -1477,35 +1490,25 @@ -- | Use 'sCopy' if possible, otherwise 'copyElementWise'. defaultCopy :: CopyCompiler rep r op defaultCopy pt dest src-  | Just (destoffset, srcoffset, num_arrays, size_x, size_y) <-+  | Just (is_transpose, (destoffset, srcoffset, num_arrays, size_x, size_y)) <-       isMapTransposeCopy pt dest src = do       fname <- mapTransposeForType pt-      emit-        $ Imp.Call-          []-          fname-        $ transposeArgs-          pt-          destmem-          (bytes destoffset)-          srcmem-          (bytes srcoffset)-          num_arrays-          size_x-          size_y-  | Just destoffset <--      IxFun.linearWithOffset dest_ixfun pt_size,-    Just srcoffset <--      IxFun.linearWithOffset src_ixfun pt_size = do-      srcspace <- entryMemSpace <$> lookupMemory srcmem-      destspace <- entryMemSpace <$> lookupMemory destmem-      if isScalarSpace srcspace || isScalarSpace destspace-        then copyElementWise pt dest src-        else sCopy destmem destoffset destspace srcmem srcoffset srcspace num_elems pt-  | otherwise =-      copyElementWise pt dest src+      sIf+        is_transpose+        ( emit . Imp.Call [] fname $+            transposeArgs+              pt+              destmem+              (bytes destoffset)+              srcmem+              (bytes srcoffset)+              num_arrays+              size_x+              size_y+        )+        nontranspose+  | otherwise = nontranspose   where-    pt_size = primByteSize pt     num_elems = Imp.elements $ product $ IxFun.shape $ memLocIxFun src      MemLoc destmem _ dest_ixfun = dest@@ -1514,6 +1517,21 @@     isScalarSpace ScalarSpace {} = True     isScalarSpace _ = False +    nontranspose = do+      srcspace <- entryMemSpace <$> lookupMemory srcmem+      destspace <- entryMemSpace <$> lookupMemory destmem+      if isScalarSpace srcspace || isScalarSpace destspace+        then copyElementWise pt dest src+        else do+          let dest_lmad = LMAD.noPermutation $ IxFun.ixfunLMAD dest_ixfun+              src_lmad = LMAD.noPermutation $ IxFun.ixfunLMAD src_ixfun+              destoffset = elements (LMAD.offset dest_lmad) `withElemType` pt+              srcoffset = elements (LMAD.offset src_lmad) `withElemType` pt+          sIf+            (LMAD.memcpyable dest_lmad src_lmad)+            (sCopy destmem destoffset destspace srcmem srcoffset srcspace num_elems pt)+            (copyElementWise pt dest src)+ copyElementWise :: CopyCompiler rep r op copyElementWise bt dest src = do   let bounds = IxFun.shape $ memLocIxFun src@@ -1889,17 +1907,17 @@  sCopy ::   VName ->-  Imp.TExp Int64 ->+  Count Bytes (Imp.TExp Int64) ->   Space ->   VName ->-  Imp.TExp Int64 ->+  Count Bytes (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+    then sUnless (Imp.unCount destoffset .==. Imp.unCount srcoffset) the_copy     else the_copy   where     the_copy =@@ -1907,10 +1925,10 @@         $ Imp.Copy           pt           destmem-          (bytes destoffset)+          destoffset           destspace           srcmem-          (bytes srcoffset)+          srcoffset           srcspace         $ num_elems `withElemType` pt 
src/Futhark/CodeGen/ImpGen/GPU.hs view
@@ -12,6 +12,8 @@ where  import Control.Monad+import Control.Monad.State+import Data.Foldable (toList) import Data.List (foldl') import Data.Map qualified as M import Data.Maybe@@ -19,6 +21,7 @@ import Futhark.CodeGen.ImpGen hiding (compileProg) import Futhark.CodeGen.ImpGen qualified import Futhark.CodeGen.ImpGen.GPU.Base+import Futhark.CodeGen.ImpGen.GPU.Copy import Futhark.CodeGen.ImpGen.GPU.SegHist import Futhark.CodeGen.ImpGen.GPU.SegMap import Futhark.CodeGen.ImpGen.GPU.SegRed@@ -27,6 +30,7 @@ import Futhark.Error import Futhark.IR.GPUMem import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.MonadFreshNames import Futhark.Util.IntegralExp (IntegralExp, divUp, quot, rem) import Prelude hiding (quot, rem)@@ -231,10 +235,12 @@   s' <- toExp s    sIota (patElemName pe) (pe64 n) x' s' et-expCompiler (Pat [pe]) (BasicOp (Replicate _ se))+expCompiler (Pat [pe]) (BasicOp (Replicate shape se))   | Acc {} <- patElemType pe = pure ()   | otherwise =-      sReplicate (patElemName pe) se+      if shapeRank shape == 0+        then copyDWIM (patElemName pe) [] se []+        else sReplicate (patElemName pe) se -- Allocation in the "local" space is just a placeholder. expCompiler _ (Op (Alloc _ (Space "local"))) =   pure ()@@ -257,40 +263,92 @@ expCompiler dest e =   defCompileExp dest e -callKernelCopy :: CopyCompiler GPUMem HostEnv Imp.HostOp-callKernelCopy bt destloc@(MemLoc destmem _ destIxFun) srcloc@(MemLoc srcmem srcshape srcIxFun)-  | Just (destoffset, srcoffset, num_arrays, size_x, size_y) <--      isMapTransposeCopy bt destloc srcloc = do-      fname <- mapTransposeForType bt-      emit $-        Imp.Call-          []-          fname-          [ Imp.MemArg destmem,-            Imp.ExpArg $ untyped destoffset,-            Imp.MemArg srcmem,-            Imp.ExpArg $ untyped srcoffset,-            Imp.ExpArg $ untyped num_arrays,-            Imp.ExpArg $ untyped size_x,-            Imp.ExpArg $ untyped size_y-          ]-  | bt_size <- primByteSize bt,-    Just destoffset <- IxFun.linearWithOffset destIxFun bt_size,-    Just srcoffset <- IxFun.linearWithOffset srcIxFun bt_size = do-      let num_elems = Imp.elements $ product $ map pe64 srcshape-      srcspace <- entryMemSpace <$> lookupMemory srcmem-      destspace <- entryMemSpace <$> lookupMemory destmem-      sCopy-        destmem-        (sExt64 destoffset)-        destspace-        srcmem-        (sExt64 srcoffset)-        srcspace-        num_elems-        bt-  | otherwise = sCopyKernel bt destloc srcloc+gpuCopyForType :: Rank -> PrimType -> CallKernelGen Name+gpuCopyForType r bt = do+  let fname = nameFromString $ "builtin#" <> gpuCopyName r bt +  exists <- hasFunction fname+  unless exists $ emitFunction fname $ gpuCopyFunction r bt++  pure fname++gpuCopyName :: Rank -> PrimType -> String+gpuCopyName (Rank r) bt = "gpu_copy_" <> show r <> "d_" <> prettyString bt++gpuCopyFunction :: Rank -> PrimType -> Imp.Function Imp.HostOp+gpuCopyFunction (Rank r) pt = do+  let tdesc = mconcat (replicate r "[]") <> prettyString pt+  Imp.Function Nothing [] params $+    Imp.DebugPrint ("\n# Copy " <> tdesc) Nothing+      <> copy_code+      <> Imp.DebugPrint "" Nothing+  where+    space = Space "device"+    memparam v = Imp.MemParam v space+    intparam v = Imp.ScalarParam v $ IntType Int64++    mkIxFun desc = do+      let new x = newVName $ desc <> "_" <> x+          newDim i = LMAD.LMADDim <$> new "stride" <*> new "shape" <*> pure i+      LMAD.LMAD <$> new "offset" <*> mapM newDim [0 .. r - 1]++    (params, copy_code) = do+      flip evalState blankNameSource $ do+        dest_mem <- newVName "destmem"+        dest_lmad <- mkIxFun "dest"++        src_mem <- newVName "srcmem"+        src_lmad <- mkIxFun "src"++        group_size <- newVName "group_size"+        num_groups <- newVName "num_groups"++        let kernel =+              copyKernel+                pt+                (le64 num_groups, Left $ untyped $ le64 group_size)+                (dest_mem, le64 <$> dest_lmad)+                (src_mem, le64 <$> src_lmad)++            dest_offset =+              Imp.elements (le64 (LMAD.offset dest_lmad)) `Imp.withElemType` pt++            src_offset =+              Imp.elements (le64 (LMAD.offset src_lmad)) `Imp.withElemType` pt++            num_bytes =+              Imp.elements (product (le64 <$> LMAD.shape src_lmad)) `Imp.withElemType` pt++            do_copy =+              Imp.Copy+                pt+                dest_mem+                dest_offset+                (Space "device")+                src_mem+                src_offset+                (Space "device")+                num_bytes++        pure+          ( [memparam dest_mem]+              ++ map intparam (toList dest_lmad)+              ++ [memparam src_mem]+              ++ map intparam (toList src_lmad),+            Imp.DeclareScalar group_size Imp.Nonvolatile int64+              <> Imp.DeclareScalar num_groups Imp.Nonvolatile int64+              <> Imp.Op (Imp.GetSize group_size "copy_group_size" Imp.SizeGroup)+              <> Imp.Op (Imp.GetSize num_groups "copy_num_groups" Imp.SizeNumGroups)+              <> Imp.If+                (LMAD.memcpyable (le64 <$> dest_lmad) (le64 <$> src_lmad))+                ( Imp.DebugPrint "## Simple copy" Nothing+                    <> do_copy+                )+                ( Imp.DebugPrint "## Kernel copy" Nothing+                    <> Imp.Op (Imp.CallKernel kernel)+                )+          )+ mapTransposeForType :: PrimType -> CallKernelGen Name mapTransposeForType bt = do   let fname = nameFromString $ "builtin#" <> mapTransposeName bt@@ -480,3 +538,51 @@ -- unfortunate code bloat, and it would be preferable if we could -- simply optimise the 64-bit version to make this distinction -- unnecessary.  Fortunately these kernels are quite small.++callKernelCopy :: CopyCompiler GPUMem HostEnv Imp.HostOp+callKernelCopy pt destloc@(MemLoc destmem _ dest_ixfun) srcloc@(MemLoc srcmem _ src_ixfun)+  | Just (is_transpose, (destoffset, srcoffset, num_arrays, size_x, size_y)) <-+      isMapTransposeCopy pt destloc srcloc = do+      fname <- mapTransposeForType pt+      sIf+        is_transpose+        ( emit . Imp.Call [] fname $+            [ Imp.MemArg destmem,+              Imp.ExpArg $ untyped destoffset,+              Imp.MemArg srcmem,+              Imp.ExpArg $ untyped srcoffset,+              Imp.ExpArg $ untyped num_arrays,+              Imp.ExpArg $ untyped size_x,+              Imp.ExpArg $ untyped size_y+            ]+        )+        nontranspose+  | otherwise = nontranspose+  where+    nontranspose = do+      fname <- gpuCopyForType (Rank (IxFun.rank dest_ixfun)) pt+      dest_space <- entryMemSpace <$> lookupMemory destmem+      src_space <- entryMemSpace <$> lookupMemory srcmem+      let dest_lmad = LMAD.noPermutation $ IxFun.ixfunLMAD dest_ixfun+          src_lmad = LMAD.noPermutation $ IxFun.ixfunLMAD src_ixfun+          num_elems = Imp.elements $ product $ LMAD.shape dest_lmad+      if dest_space == Space "device" && src_space == Space "device"+        then+          emit . Imp.Call [] fname $+            [Imp.MemArg destmem]+              ++ map (Imp.ExpArg . untyped) (toList dest_lmad)+              ++ [Imp.MemArg srcmem]+              ++ map (Imp.ExpArg . untyped) (toList src_lmad)+        else -- FIXME: this assumes a linear representation!+        -- Currently we never generate code where this is not the+        -- case, but we might in the future.++          sCopy+            destmem+            (Imp.elements (LMAD.offset dest_lmad) `Imp.withElemType` pt)+            dest_space+            srcmem+            (Imp.elements (LMAD.offset src_lmad) `Imp.withElemType` pt)+            src_space+            num_elems+            pt
src/Futhark/CodeGen/ImpGen/GPU/Base.hs view
@@ -19,7 +19,6 @@     sKernelThread,     KernelAttrs (..),     defKernelAttrs,-    sCopyKernel,     lvlKernelAttrs,     allocLocal,     kernelAlloc,@@ -1258,7 +1257,7 @@   v_t <- subExpType v   case v_t of     Prim v_t'-      | IxFun.isLinear arr_ixfun -> pure $+      | IxFun.isDirect arr_ixfun -> pure $           Just $ do             fname <- replicateForType v_t'             emit $@@ -1360,7 +1359,7 @@   CallKernelGen () sIota arr n x s et = do   ArrayEntry (MemLoc arr_mem _ arr_ixfun) _ <- lookupArray arr-  if IxFun.isLinear arr_ixfun+  if IxFun.isDirect arr_ixfun     then do       fname <- iotaForType et       emit $@@ -1369,33 +1368,6 @@           fname           [Imp.MemArg arr_mem, Imp.ExpArg $ untyped n, Imp.ExpArg x, Imp.ExpArg s]     else sIotaKernel arr n x s et--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-      kernel_size = product shape--  (virtualise, constants) <- simpleKernelConstants kernel_size "copy"--  fname <- askFunction-  let name =-        keyWithEntryPoint fname $-          nameFromString $-            "copy_" ++ show (baseTag $ kernelGlobalThreadIdVar constants)--  sKernelFailureTolerant True threadOperations constants name $-    virtualise $ \gtid -> do-      is <- dIndexSpace' "copy_i" shape gtid--      (_, destspace, destidx) <- fullyIndexArray' destloc is-      (_, srcspace, srcidx) <- fullyIndexArray' srcloc is--      sWhen (gtid .<. kernel_size) $ do-        tmp <- tvVar <$> dPrim "tmp" pt-        emit $ Imp.Read tmp srcmem srcidx pt srcspace Imp.Nonvolatile-        emit $ Imp.Write destmem destidx pt destspace Imp.Nonvolatile $ Imp.var tmp pt  compileThreadResult ::   SegSpace ->
+ src/Futhark/CodeGen/ImpGen/GPU/Copy.hs view
@@ -0,0 +1,81 @@+-- | General implementation of GPU copying, using LMAD representation.+-- That means the dynamic performance of this kernel depends crucially+-- on the LMAD.  In most cases we should use a more specialised kernel.+-- Written in ImpCode so we can compile it to both CUDA and OpenCL.+module Futhark.CodeGen.ImpGen.GPU.Copy (copyKernel) where++import Control.Monad+import Control.Monad.State+import Data.Foldable (toList)+import Futhark.CodeGen.ImpCode.GPU+import Futhark.IR.Mem.LMAD qualified as LMAD+import Futhark.IR.Prop.Reshape+import Futhark.MonadFreshNames+import Futhark.Util (nubOrd)+import Futhark.Util.IntegralExp (divUp)+import Prelude hiding (quot, rem)++copyKernel ::+  PrimType ->+  (TExp Int64, GroupDim) ->+  (VName, LMAD.LMAD (TExp Int64)) ->+  (VName, LMAD.LMAD (TExp Int64)) ->+  Kernel+copyKernel pt (num_groups, group_dim) (dest_mem, dest_lmad) (src_mem, src_lmad) =+  Kernel+    { kernelBody = body,+      kernelUses =+        let frees =+              nubOrd+                ( foldMap toList dest_lmad+                    <> foldMap toList src_lmad+                    <> toList num_groups+                )+         in map (`ScalarUse` IntType Int64) frees+              ++ map MemoryUse [dest_mem, src_mem],+      kernelNumGroups = [untyped num_groups],+      kernelGroupSize = [group_dim],+      kernelName = nameFromString ("copy_" <> show rank <> "d_" <> prettyString pt),+      kernelFailureTolerant = True,+      kernelCheckLocalMemory = False+    }+  where+    shape = LMAD.shape dest_lmad+    rank = length shape++    body = flip evalState (newNameSource 1000) $ do+      group_id <- newVName "group_id"+      local_id <- newVName "local_id"+      local_size <- newVName "local_size"+      global_id <- newVName "global_id"+      group_iter <- newVName "group_iter"+      let global_id_e =+            ((le64 group_id + le64 group_iter * num_groups) * le64 local_size)+              + le64 local_id++      is <- replicateM rank $ newVName "i"+      let is_e = map untyped (unflattenIndex shape (le64 global_id))+          in_bounds = foldl1 (.&&.) (zipWith (.<.) (map le64 is) shape)++      element <- newVName "element"++      let dec v = DeclareScalar v Nonvolatile $ IntType Int64+          src_o = Count (LMAD.index src_lmad (map le64 is))+          dest_o = Count (LMAD.index dest_lmad (map le64 is))+          copy_elem =+            DeclareScalar element Nonvolatile pt+              <> Read element src_mem src_o pt (Space "device") Nonvolatile+              <> Write dest_mem dest_o pt (Space "device") Nonvolatile (LeafExp element pt)+      pure $+        foldMap dec [group_id, local_id, local_size, global_id]+          <> Op (GetLocalId local_id 0)+          <> Op (GetLocalSize local_size 0)+          <> Op (GetGroupId group_id 0)+          <> For+            group_iter+            (untyped (product shape `divUp` (le64 local_size * num_groups)))+            ( SetScalar global_id (untyped global_id_e)+                <> foldMap dec is+                <> mconcat (zipWith SetScalar is is_e)+                <> If in_bounds copy_elem mempty+            )
src/Futhark/CodeGen/ImpGen/GPU/Group.hs view
@@ -41,9 +41,10 @@   ArrayEntry arr_loc pt <- lookupArray arr   let flat_shape = Shape $ Var (tvVar flat) : drop k (memLocShape arr_loc)   sArray (baseString arr ++ "_flat") pt flat_shape (memLocName arr_loc) $-    IxFun.reshape (memLocIxFun arr_loc) $-      map pe64 $-        shapeDims flat_shape+    fromMaybe (error "flattenArray") $+      IxFun.reshape (memLocIxFun arr_loc) $+        map pe64 $+          shapeDims flat_shape  sliceArray :: Imp.TExp Int64 -> TV Int64 -> VName -> ImpM rep r op VName sliceArray start size arr = do
src/Futhark/IR/Mem.hs view
@@ -584,7 +584,7 @@         MemMem {} -> pure ()         MemAcc {} -> pure ()         MemArray _ _ _ (ArrayIn _ ixfun)-          | IxFun.isLinear ixfun ->+          | IxFun.isDirect ixfun ->               pure ()           | otherwise ->               TC.bad . TC.TypeError $@@ -766,7 +766,7 @@   TC.TypeM rep () matchPatToExp pat e = do   scope <- asksScope removeScopeAliases-  rt <- runReaderT (expReturns $ removeExpAliases e) scope+  rt <- maybe illformed pure $ runReader (expReturns $ removeExpAliases e) scope    let (ctx_ids, val_ts) = unzip $ bodyReturnsFromPat $ removePatAliases pat       (ctx_map_ids, ctx_map_exts) = getExtMaps $ zip ctx_ids [0 .. 1]@@ -780,6 +780,13 @@       </> "cannot match pattern type:"       </> indent 2 (ppTupleLines' $ map pretty val_ts)   where+    illformed =+      TC.bad $+        TC.TypeError . docText $+          "Expression"+            </> indent 2 (pretty e)+            </> "cannot be assigned an index function."+     matches _ _ (MemPrim x) (MemPrim y) = x == y     matches _ _ (MemMem x_space) (MemMem y_space) =       x_space == y_space@@ -1006,49 +1013,55 @@  -- | The return information of an expression.  This can be seen as the -- "return type with memory annotations" of the expression.+--+-- This can produce Nothing, which signifies that the result is an+-- array layout that is not expressible as an index function. expReturns ::   (LocalScope rep m, Mem rep inner) =>   Exp rep ->-  m [ExpReturns]+  m (Maybe [ExpReturns]) expReturns (BasicOp (SubExp se)) =-  pure <$> subExpReturns se+  Just . pure <$> subExpReturns se expReturns (BasicOp (Opaque _ (Var v))) =-  pure <$> varReturns v+  Just . pure <$> varReturns v expReturns (BasicOp (Reshape k newshape v)) = do   (et, _, mem, ixfun) <- arrayVarReturns v-  pure-    [ MemArray et (fmap Free newshape) NoUniqueness $-        Just . ReturnsInBlock mem . existentialiseIxFun [] $-          reshaper ixfun $-            map pe64 (shapeDims newshape)-    ]+  case reshaper k ixfun $ map pe64 $ shapeDims newshape of+    Just ixfun' ->+      pure . Just $+        [ MemArray et (fmap Free newshape) NoUniqueness . Just $+            ReturnsInBlock mem (existentialiseIxFun [] ixfun')+        ]+    Nothing -> pure Nothing   where-    reshaper = case k of-      ReshapeArbitrary -> IxFun.reshape-      ReshapeCoerce -> IxFun.coerce+    reshaper ReshapeArbitrary ixfun =+      IxFun.reshape ixfun+    reshaper ReshapeCoerce ixfun =+      Just . IxFun.coerce ixfun expReturns (BasicOp (Rearrange perm v)) = do   (et, Shape dims, mem, ixfun) <- arrayVarReturns v   let ixfun' = IxFun.permute ixfun perm       dims' = rearrangeShape perm dims-  pure-    [ MemArray et (Shape $ map Free dims') NoUniqueness $-        Just $-          ReturnsInBlock mem $-            existentialiseIxFun [] ixfun'-    ]+  pure $+    Just+      [ MemArray et (Shape $ map Free dims') NoUniqueness $+          Just $+            ReturnsInBlock mem $+              existentialiseIxFun [] ixfun'+      ] expReturns (BasicOp (Index v slice)) = do-  pure . varInfoToExpReturns <$> sliceInfo v slice+  Just . pure . varInfoToExpReturns <$> sliceInfo v slice expReturns (BasicOp (Update _ v _ _)) =-  pure <$> varReturns v+  Just . pure <$> varReturns v expReturns (BasicOp (FlatIndex v slice)) = do-  pure . varInfoToExpReturns <$> flatSliceInfo v slice+  fmap (pure . varInfoToExpReturns) <$> flatSliceInfo v slice expReturns (BasicOp (FlatUpdate v _ _)) =-  pure <$> varReturns v+  Just . pure <$> varReturns v expReturns (BasicOp op) =-  extReturns . staticShapes <$> basicOpType op+  Just . extReturns . staticShapes <$> basicOpType op expReturns e@(DoLoop merge _ _) = do   t <- expExtType e-  zipWithM typeWithDec t $ map fst merge+  Just <$> zipWithM typeWithDec t (map fst merge)   where     typeWithDec t p =       case (t, paramDec p) of@@ -1073,18 +1086,20 @@     isMergeVar v = find ((== v) . paramName . snd) $ zip [0 ..] mergevars     mergevars = map fst merge expReturns (Apply _ _ ret _) =-  pure $ map (funReturnsToExpReturns . fst) ret+  pure $ Just $ map (funReturnsToExpReturns . fst) ret expReturns (Match _ _ _ (MatchDec ret _)) =-  pure $ map bodyReturnsToExpReturns ret+  pure $ Just $ map bodyReturnsToExpReturns ret expReturns (Op op) =-  opReturns op+  Just <$> opReturns op expReturns (WithAcc inputs lam) =-  (<>)-    <$> (concat <$> mapM inputReturns inputs)-    <*>-    -- XXX: this is a bit dubious because it enforces extra copies.  I-    -- think WithAcc should perhaps have a return annotation like If.-    pure (extReturns $ staticShapes $ drop num_accs $ lambdaReturnType lam)+  Just+    <$> ( (<>)+            <$> (concat <$> mapM inputReturns inputs)+            <*>+            -- XXX: this is a bit dubious because it enforces extra copies.  I+            -- think WithAcc should perhaps have a return annotation like If.+            pure (extReturns $ staticShapes $ drop num_accs $ lambdaReturnType lam)+        )   where     inputReturns (_, arrs, _) = mapM varReturns arrs     num_accs = length inputs@@ -1107,14 +1122,13 @@   (Monad m, HasScope rep m, Mem rep inner) =>   VName ->   FlatSlice SubExp ->-  m (MemInfo SubExp NoUniqueness MemBind)+  m (Maybe (MemInfo SubExp NoUniqueness MemBind)) flatSliceInfo v slice@(FlatSlice offset idxs) = do   (et, _, mem, ixfun) <- arrayVarReturns v   map (fmap pe64) idxs     & FlatSlice (pe64 offset)     & IxFun.flatSlice ixfun-    & ArrayIn mem-    & MemArray et (Shape (flatSliceDims slice)) NoUniqueness+    & fmap (MemArray et (Shape (flatSliceDims slice)) NoUniqueness . ArrayIn mem)     & pure  class IsOp op => OpReturns op where
src/Futhark/IR/Mem/IxFun.hs view
@@ -7,7 +7,6 @@     Shape,     LMAD (..),     LMADDim (..),-    Monotonicity (..),     index,     mkExistential,     iota,@@ -19,20 +18,15 @@     flatSlice,     rebase,     shape,-    lmadShape,+    permutation,     rank,-    linearWithOffset,-    rearrangeWithOffset,     isDirect,-    isLinear,     substituteInIxFun,     substituteInLMAD,     existentialize,     closeEnough,     equivalent,-    hasOneLmad,     permuteInv,-    conservativeFlatten,     disjoint,     disjoint2,     disjoint3,@@ -43,25 +37,27 @@ import Control.Category import Control.Monad import Control.Monad.State-import Data.Function (on, (&))-import Data.List (sort, sortBy, zip4, zipWith4)-import Data.List.NonEmpty (NonEmpty (..))-import Data.List.NonEmpty qualified as NE+import Data.List (sort, zip4) import Data.Map.Strict qualified as M-import Data.Maybe (isJust) import Data.Traversable import Futhark.Analysis.PrimExp import Futhark.Analysis.PrimExp.Convert-import Futhark.IR.Mem.LMAD+import Futhark.IR.Mem.LMAD hiding+  ( flatSlice,+    index,+    iota,+    mkExistential,+    permutation,+    permute,+    reshape,+    shape,+    slice,+  )+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.IR.Prop import Futhark.IR.Syntax-  ( DimIndex (..),-    FlatDimIndex (..),-    FlatSlice (..),+  ( FlatSlice (..),     Slice (..),-    dimFix,-    flatSliceDims,-    flatSliceStrides,     unitSlice,   ) import Futhark.IR.Syntax.Core (Ext (..))@@ -71,8 +67,6 @@ import Futhark.Util.Pretty import Prelude hiding (gcd, id, mod, (.)) -type Indices num = [num]- -- | An index function is a mapping from a multidimensional array -- index space (the domain) to a one-dimensional memory index space. -- Essentially, it explains where the element at position @[i,j,p]@ of@@ -80,23 +74,20 @@ -- constitutes its memory.  For example, we can use this to -- distinguish row-major and column-major representations. ----- An index function is represented as a sequence of 'LMAD's.+-- An index function is represented as an LMAD. data IxFun num = IxFun-  { ixfunLMADs :: NonEmpty (LMAD num),+  { ixfunLMAD :: LMAD num,     -- | the shape of the support array, i.e., the original array     --   that birthed (is the start point) of this index function.-    base :: Shape num,-    -- | ignoring permutations, is the index function contiguous?-    contiguous :: Bool+    base :: Shape num   }   deriving (Show, Eq)  instance Pretty num => Pretty (IxFun num) where-  pretty (IxFun lmads oshp cg) =+  pretty (IxFun lmad oshp) =     braces . semistack $       [ "base:" <+> brackets (commasep $ map pretty oshp),-        "contiguous:" <+> if cg then "true" else "false",-        "LMADs:" <+> brackets (commastack $ NE.toList $ NE.map pretty lmads)+        "LMAD:" <+> pretty lmad       ]  instance Substitute num => Substitute (IxFun num) where@@ -117,23 +108,8 @@ -- It is important that the traversal order here is the same as in -- mkExistential. instance Traversable IxFun where-  traverse f (IxFun lmads oshp cg) =-    IxFun <$> traverse (traverse f) lmads <*> traverse f oshp <*> pure cg--(++@) :: [a] -> NonEmpty a -> NonEmpty a-es ++@ (ne :| nes) = case es of-  e : es' -> e :| es' ++ [ne] ++ nes-  [] -> ne :| nes--(@++@) :: NonEmpty a -> NonEmpty a -> NonEmpty a-(x :| xs) @++@ (y :| ys) = x :| xs ++ [y] ++ ys--setLMADPermutation :: Permutation -> LMAD num -> LMAD num-setLMADPermutation perm lmad =-  lmad {lmadDims = zipWith (\dim p -> dim {ldPerm = p}) (lmadDims lmad) perm}--setLMADShape :: Shape num -> LMAD num -> LMAD num-setLMADShape shp lmad = lmad {lmadDims = zipWith (\dim s -> dim {ldShape = s}) (lmadDims lmad) shp}+  traverse f (IxFun lmad oshp) =+    IxFun <$> traverse f lmad <*> traverse f oshp  -- | Substitute a name with a PrimExp in an index function. substituteInIxFun ::@@ -141,44 +117,39 @@   M.Map a (TPrimExp t a) ->   IxFun (TPrimExp t a) ->   IxFun (TPrimExp t a)-substituteInIxFun tab (IxFun lmads oshp cg) =+substituteInIxFun tab (IxFun lmad oshp) =   IxFun-    (NE.map (substituteInLMAD tab) lmads)+    (substituteInLMAD tab lmad)     (map (TPrimExp . substituteInPrimExp tab' . untyped) oshp)-    cg   where     tab' = fmap untyped tab  -- | Is this is a row-major array? isDirect :: (Eq num, IntegralExp num) => IxFun num -> Bool-isDirect ixfun@(IxFun (LMAD offset dims :| []) oshp True) =+isDirect (IxFun (LMAD offset dims) oshp) =   let strides_expected = reverse $ scanl (*) 1 (reverse (tail oshp))-   in hasContiguousPerm ixfun-        && length oshp == length dims+   in length oshp == length dims         && offset == 0         && all-          (\(LMADDim s n p _, m, d, se) -> s == se && n == d && p == m)+          (\(LMADDim s n p, m, d, se) -> s == se && n == d && p == m)           (zip4 dims [0 .. length dims - 1] oshp strides_expected)-isDirect _ = False --- | Is index function "analyzable", i.e., consists of one LMAD-hasOneLmad :: IxFun num -> Bool-hasOneLmad (IxFun (_ :| []) _ _) = True-hasOneLmad _ = False- -- | Does the index function have an ascending permutation? hasContiguousPerm :: IxFun num -> Bool-hasContiguousPerm (IxFun (lmad :| []) _ _) =-  let perm = lmadPermutation lmad+hasContiguousPerm (IxFun lmad _) =+  let perm = LMAD.permutation lmad    in perm == sort perm-hasContiguousPerm _ = False  -- | The index space of the index function.  This is the same as the -- shape of arrays that the index function supports. shape :: (Eq num, IntegralExp num) => IxFun num -> Shape num-shape (IxFun (lmad :| _) _ _) =-  permuteFwd (lmadPermutation lmad) $ lmadShapeBase lmad+shape (IxFun lmad _) =+  permuteFwd (LMAD.permutation lmad) $ LMAD.shapeBase lmad +-- | The permutation of the first LMAD of the index function.+permutation :: IxFun num -> Permutation+permutation = map LMAD.ldPerm . LMAD.dims . ixfunLMAD+ -- | Compute the flat memory index for a complete set @inds@ of array indices -- and a certain element size @elem_size@. index ::@@ -186,52 +157,24 @@   IxFun num ->   Indices num ->   num-index = indexFromLMADs . ixfunLMADs-  where-    indexFromLMADs ::-      (IntegralExp num, Eq num) =>-      NonEmpty (LMAD num) ->-      Indices num ->-      num-    indexFromLMADs (lmad :| []) inds = indexLMAD lmad inds-    indexFromLMADs (lmad1 :| lmad2 : lmads) inds =-      let i_flat = indexLMAD lmad1 inds-          new_inds = unflattenIndex (permuteFwd (lmadPermutation lmad2) $ lmadShapeBase lmad2) i_flat-       in indexFromLMADs (lmad2 :| lmads) new_inds-    indexLMAD ::-      (IntegralExp num, Eq num) =>-      LMAD num ->-      Indices num ->-      num-    indexLMAD lmad@(LMAD off dims) inds =-      let prod =-            sum $-              zipWith-                flatOneDim-                (map ldStride dims)-                (permuteInv (lmadPermutation lmad) inds)-       in off + prod+index = LMAD.index . ixfunLMAD  -- | iota with offset. iotaOffset :: IntegralExp num => num -> Shape num -> IxFun num-iotaOffset o ns = IxFun (makeRotIota Inc o ns :| []) ns True+iotaOffset o ns = IxFun (LMAD.iota o ns) ns  -- | iota. iota :: IntegralExp num => Shape num -> IxFun num iota = iotaOffset 0 --- | Create a contiguous single-LMAD index function that is--- existential in everything, with the provided permutation,--- monotonicity, and contiguousness.-mkExistential :: Int -> [(Int, Monotonicity)] -> Bool -> Int -> IxFun (Ext a)-mkExistential basis_rank perm contig start =-  IxFun (NE.singleton lmad) basis contig+-- | Create a single-LMAD index function that is+-- existential in everything, with the provided permutation.+mkExistential :: Int -> [Int] -> Int -> IxFun (Ext a)+mkExistential basis_rank perm start =+  IxFun (LMAD.mkExistential perm start) basis   where     basis = take basis_rank $ map Ext [start + 1 + dims_rank * 2 ..]     dims_rank = length perm-    lmad = LMAD (Ext start) $ zipWith onDim perm [0 ..]-    onDim (p, mon) i =-      LMADDim (Ext (start + 1 + i * 2)) (Ext (start + 2 + i * 2)) p mon  -- | Permute dimensions. permute ::@@ -239,114 +182,8 @@   IxFun num ->   Permutation ->   IxFun num-permute (IxFun (lmad :| lmads) oshp cg) perm_new =-  let perm_cur = lmadPermutation lmad-      perm = map (perm_cur !!) perm_new-   in IxFun (setLMADPermutation perm lmad :| lmads) oshp cg---- | Handle the case where a slice can stay within a single LMAD.-sliceOneLMAD ::-  (Eq num, IntegralExp num) =>-  IxFun num ->-  Slice num ->-  Maybe (IxFun num)-sliceOneLMAD (IxFun (lmad@(LMAD _ ldims) :| lmads) oshp cg) (Slice is) = do-  let perm = lmadPermutation lmad-      is' = permuteInv perm is-      cg' = cg && slicePreservesContiguous lmad (Slice is')-  let lmad' = foldl sliceOne (LMAD (lmadOffset lmad) []) $ zip is' ldims-      -- need to remove the fixed dims from the permutation-      perm' =-        updatePerm perm $-          map fst $-            filter (isJust . dimFix . snd) $-              zip [0 .. length is' - 1] is'--  pure $ IxFun (setLMADPermutation perm' lmad' :| lmads) oshp cg'-  where-    updatePerm ps inds = concatMap decrease ps-      where-        decrease p =-          let f n i-                | i == p = -1-                | i > p = n-                | n /= -1 = n + 1-                | otherwise = n-              d = foldl f 0 inds-           in [p - d | d /= -1]--    -- XXX: TODO: what happens to r on a negative-stride slice; is there-    -- such a case?-    sliceOne ::-      (Eq num, IntegralExp num) =>-      LMAD num ->-      (DimIndex num, LMADDim num) ->-      LMAD num-    sliceOne (LMAD off dims) (DimFix i, LMADDim s _x _ _) =-      LMAD (off + flatOneDim s i) dims-    sliceOne (LMAD off dims) (DimSlice _ ne _, LMADDim 0 _ p _) =-      LMAD off (dims ++ [LMADDim 0 ne p Unknown])-    sliceOne (LMAD off dims) (dmind, dim@(LMADDim _ n _ _))-      | dmind == unitSlice 0 n = LMAD off (dims ++ [dim])-    sliceOne (LMAD off dims) (dmind, LMADDim s n p m)-      | dmind == DimSlice (n - 1) n (-1) =-          let off' = off + flatOneDim s (n - 1)-           in LMAD off' (dims ++ [LMADDim (s * (-1)) n p (invertMonotonicity m)])-    sliceOne (LMAD off dims) (DimSlice b ne 0, LMADDim s _ p _) =-      LMAD (off + flatOneDim s b) (dims ++ [LMADDim 0 ne p Unknown])-    sliceOne (LMAD off dims) (DimSlice bs ns ss, LMADDim s _ p m) =-      let m' = case sgn ss of-            Just 1 -> m-            Just (-1) -> invertMonotonicity m-            _ -> Unknown-       in LMAD (off + s * bs) (dims ++ [LMADDim (ss * s) ns p m'])--    slicePreservesContiguous ::-      (Eq num, IntegralExp num) =>-      LMAD num ->-      Slice num ->-      Bool-    slicePreservesContiguous (LMAD _ dims) (Slice slc) =-      -- remove from the slice the LMAD dimensions that have stride 0.-      -- If the LMAD was contiguous in mem, then these dims will not-      -- influence the contiguousness of the result.-      -- Also normalize the input slice, i.e., 0-stride and size-1-      -- slices are rewritten as DimFixed.-      let (dims', slc') =-            unzip $-              filter ((/= 0) . ldStride . fst) $-                zip dims $-                  map normIndex slc-          -- Check that:-          -- 1. a clean split point exists between Fixed and Sliced dims-          -- 2. the outermost sliced dim has +/- 1 stride.-          -- 3. the rest of inner sliced dims are full.-          (_, success) =-            foldl-              ( \(found, res) (slcdim, LMADDim _ n _ _) ->-                  case (slcdim, found) of-                    (DimFix {}, True) -> (found, False)-                    (DimFix {}, False) -> (found, res)-                    (DimSlice _ _ ds, False) ->-                      -- outermost sliced dim: +/-1 stride-                      let res' = (ds == 1 || ds == -1)-                       in (True, res && res')-                    (DimSlice _ ne ds, True) ->-                      -- inner sliced dim: needs to be full-                      let res' = (n == ne) && (ds == 1 || ds == -1)-                       in (found, res && res')-              )-              (False, True)-              $ zip slc' dims'-       in success--    normIndex ::-      (Eq num, IntegralExp num) =>-      DimIndex num ->-      DimIndex num-    normIndex (DimSlice b 1 _) = DimFix b-    normIndex (DimSlice b _ 0) = DimFix b-    normIndex d = d+permute (IxFun lmad oshp) perm_new =+  IxFun (LMAD.permute lmad perm_new) oshp  -- | Slice an index function. slice ::@@ -354,46 +191,23 @@   IxFun num ->   Slice num ->   IxFun num-slice ixfun@(IxFun (lmad@(LMAD _ _) :| lmads) oshp cg) dim_slices+slice ixfun@(IxFun lmad@(LMAD _ _) oshp) (Slice is)   -- Avoid identity slicing.-  | unSlice dim_slices == map (unitSlice 0) (shape ixfun) = ixfun-  | Just ixfun' <- sliceOneLMAD ixfun dim_slices = ixfun'+  | is == map (unitSlice 0) (shape ixfun) = ixfun   | otherwise =-      case sliceOneLMAD (iota (lmadShape lmad)) dim_slices of-        Just (IxFun (lmad' :| []) _ cg') ->-          IxFun (lmad' :| lmad : lmads) oshp (cg && cg')-        _ -> error "slice: reached impossible case"+      IxFun (LMAD.slice lmad (Slice is)) oshp  -- | Flat-slice an index function. flatSlice ::   (Eq num, IntegralExp num) =>   IxFun num ->   FlatSlice num ->-  IxFun num-flatSlice ixfun@(IxFun (LMAD offset (dim : dims) :| lmads) oshp cg) (FlatSlice new_offset is)-  | hasContiguousPerm ixfun =-      let lmad =-            LMAD-              (offset + new_offset * ldStride dim)-              (map (helper $ ldStride dim) is <> dims)-              & setLMADPermutation [0 ..]-       in IxFun (lmad :| lmads) oshp cg-  where-    helper s0 (FlatDimIndex n s) =-      let new_mon = if s0 * s == 1 then Inc else Unknown-       in LMADDim (s0 * s) n 0 new_mon-flatSlice (IxFun (lmad :| lmads) oshp cg) s@(FlatSlice new_offset _) =-  IxFun (LMAD (new_offset * base_stride) (new_dims <> tail_dims) :| lmad : lmads) oshp cg-  where-    tail_shapes = tail $ lmadShape lmad-    base_stride = product tail_shapes-    tail_strides = tail $ scanr (*) 1 tail_shapes-    tail_dims = zipWith4 LMADDim tail_strides tail_shapes [length new_shapes ..] (repeat Inc)-    new_shapes = flatSliceDims s-    new_strides = map (* base_stride) $ flatSliceStrides s-    new_dims = zipWith4 LMADDim new_strides new_shapes [0 ..] (repeat Inc)+  Maybe (IxFun num)+flatSlice (IxFun lmad oshp) s = do+  lmad' <- LMAD.flatSlice lmad s+  Just $ IxFun lmad' oshp --- | Handle the case where a reshape operation can stay inside a single LMAD.+-- | Reshape an index function. -- -- There are four conditions that all must hold for the result of a reshape -- operation to remain in the one-LMAD domain:@@ -402,82 +216,18 @@ --       the LMAD dimensions that were *not* reshape coercions. --   (2) the repetition of dimensions of the underlying LMAD must --       refer only to the coerced-dimensions of the reshape operation.---   (3) finally, the underlying memory is contiguous (and monotonous). ----- If any of these conditions do not hold, then the reshape operation will--- conservatively add a new LMAD to the list, leading to a representation that--- provides less opportunities for further analysis.-reshapeOneLMAD ::-  (Eq num, IntegralExp num) =>-  IxFun num ->-  Shape num ->-  Maybe (IxFun num)-reshapeOneLMAD ixfun@(IxFun (lmad@(LMAD off dims) :| lmads) oldbase cg) newshape = do-  let perm = lmadPermutation lmad-      dims_perm = permuteFwd perm dims-      mid_dims = take (length dims) dims_perm-      mon = ixfunMonotonicity ixfun--  guard $-    -- checking conditions (2)-    all (\(LMADDim s _ _ _) -> s /= 0) mid_dims-      &&-      -- checking condition (1)-      consecutive 0 (map ldPerm mid_dims)-      &&-      -- checking condition (3)-      hasContiguousPerm ixfun-      && cg-      && (mon == Inc || mon == Dec)--  -- make new permutation-  let rsh_len = length newshape-      diff = length newshape - length dims-      iota_shape = [0 .. length newshape - 1]-      perm' =-        map-          ( \i ->-              let ind = i - diff-               in if (i >= 0) && (i < rsh_len)-                    then i -- already checked mid_dims not affected-                    else ldPerm (dims !! ind) + diff-          )-          iota_shape-      -- split the dimensions-      (support_inds, repeat_inds) =-        foldl-          (\(sup, rpt) (shpdim, ip) -> ((ip, shpdim) : sup, rpt))-          ([], [])-          $ reverse-          $ zip newshape perm'--      (sup_inds, support) = unzip $ sortBy (compare `on` fst) support_inds-      (rpt_inds, repeats) = unzip repeat_inds-      LMAD off' dims_sup = makeRotIota mon off support-      repeats' = map (\n -> LMADDim 0 n 0 Unknown) repeats-      dims' =-        map snd $-          sortBy (compare `on` fst) $-            zip sup_inds dims_sup ++ zip rpt_inds repeats'-      lmad' = LMAD off' dims'-  pure $ IxFun (setLMADPermutation perm' lmad' :| lmads) oldbase cg-  where-    consecutive _ [] = True-    consecutive i [p] = i == p-    consecutive i ps = and $ zipWith (==) ps [i, i + 1 ..]---- | Reshape an index function.+-- If any of these conditions do not hold, then the reshape operation+-- will conservatively add a new LMAD to the list, leading to a+-- representation that provides less opportunities for further+-- analysis reshape ::   (Eq num, IntegralExp num) =>   IxFun num ->   Shape num ->-  IxFun num-reshape ixfun new_shape-  | Just ixfun' <- reshapeOneLMAD ixfun new_shape = ixfun'-reshape (IxFun (lmad0 :| lmad0s) oshp cg) new_shape =-  case iota new_shape of-    IxFun (lmad :| []) _ _ -> IxFun (lmad :| lmad0 : lmad0s) oshp cg-    _ -> error "reshape: reached impossible case"+  Maybe (IxFun num)+reshape (IxFun lmad _) new_shape =+  IxFun <$> LMAD.reshape lmad new_shape <*> pure new_shape  -- | Coerce an index function to look like it has a new shape. -- Dynamically the shape must be the same.@@ -486,18 +236,15 @@   IxFun num ->   Shape num ->   IxFun num-coerce (IxFun (lmad :| lmads) oshp cg) new_shape =-  IxFun (onLMAD lmad :| lmads) oshp cg+coerce (IxFun lmad _) new_shape =+  IxFun (onLMAD lmad) new_shape   where     onLMAD (LMAD offset dims) = LMAD offset $ zipWith onDim dims new_shape     onDim ld d = ld {ldShape = d}  -- | The number of dimensions in the domain of the input function.-rank ::-  IntegralExp num =>-  IxFun num ->-  Int-rank (IxFun (LMAD _ sss :| _) _ _) = length sss+rank :: IntegralExp num => IxFun num -> Int+rank (IxFun (LMAD _ sss) _) = length sss  -- | Essentially @rebase new_base ixfun = ixfun o new_base@ -- Core soundness condition: @base ixfun == shape new_base@@@ -509,15 +256,6 @@ -- We can often stay in that domain if the original ixfun is essentially a -- slice, e.g. `x[i, (k1,m,s1), (k2,n,s2)] = orig`. ----- XXX: TODO: handle repetitions in both lmads.------ How to handle repeated dimensions in the original?------   (a) Shave them off of the last lmad of original---   (b) Compose the result from (a) with the first---       lmad of the new base---   (c) apply a repeat operation on the result of (b).--- -- However, I strongly suspect that for in-place update what we need is actually -- the INVERSE of the rebase function, i.e., given an index function new-base -- and another one orig, compute the index function ixfun0 such that:@@ -527,177 +265,67 @@ -- -- because then I can go bottom up and compose with ixfun0 all the index -- functions corresponding to the memory block associated with ixfun.-rebaseNice ::-  (Eq num, IntegralExp num) =>-  IxFun num ->-  IxFun num ->-  Maybe (IxFun num)-rebaseNice-  new_base@(IxFun (lmad_base :| lmads_base) _ cg_base)-  ixfun@(IxFun lmads shp cg) = do-    let (lmad :| lmads') = NE.reverse lmads-        dims = lmadDims lmad-        perm = lmadPermutation lmad-        perm_base = lmadPermutation lmad_base--    guard $-      -- Core rebase condition.-      base ixfun == shape new_base-        -- Conservative safety conditions: ixfun is contiguous and has known-        -- monotonicity for all dimensions.-        && cg-        && all ((/= Unknown) . ldMon) dims-        -- XXX: We should be able to handle some basic cases where both index-        -- functions have non-trivial permutations.-        && (hasContiguousPerm ixfun || hasContiguousPerm new_base)-        -- We need the permutations to be of the same size if we want to compose-        -- them.  They don't have to be of the same size if the ixfun has a trivial-        -- permutation.  Supporting this latter case allows us to rebase when ixfun-        -- has been created by slicing with fixed dimensions.-        && (length perm == length perm_base || hasContiguousPerm ixfun)-        -- To not have to worry about ixfun having non-1 strides, we also check that-        -- it is a row-major array (modulo permutation, which is handled-        -- separately).  Accept a non-full innermost dimension.  XXX: Maybe this can-        -- be less conservative?-        && and-          ( zipWith3-              (\sn ld inner -> sn == ldShape ld || (inner && ldStride ld == 1))-              shp-              dims-              (replicate (length dims - 1) False ++ [True])-          )--    -- Compose permutations, reverse strides and adjust offset if necessary.-    let perm_base' =-          if hasContiguousPerm ixfun-            then perm_base-            else map (perm !!) perm_base-        lmad_base' = setLMADPermutation perm_base' lmad_base-        dims_base = lmadDims lmad_base'-        n_fewer_dims = length dims_base - length dims-        (dims_base', offs_contrib) =-          unzip $-            zipWith-              ( \(LMADDim s1 n1 p1 _) (LMADDim _ _ _ m2) ->-                  let (s', off')-                        | m2 == Inc = (s1, 0)-                        | otherwise = (s1 * (-1), s1 * (n1 - 1))-                   in (LMADDim s' n1 (p1 - n_fewer_dims) Inc, off')-              )-              -- If @dims@ is morally a slice, it might have fewer dimensions than-              -- @dims_base@.  Drop extraneous outer dimensions.-              (drop n_fewer_dims dims_base)-              dims-        off_base = lmadOffset lmad_base' + sum offs_contrib-        lmad_base''-          | lmadOffset lmad == 0 = LMAD off_base dims_base'-          | otherwise =-              -- If the innermost dimension of the ixfun was not full (but still-              -- had a stride of 1), add its offset relative to the new base.-              setLMADShape-                (lmadShape lmad)-                ( LMAD-                    (off_base + ldStride (last dims_base) * lmadOffset lmad)-                    dims_base'-                )-        new_base' = IxFun (lmad_base'' :| lmads_base) shp cg_base-        IxFun lmads_base' _ _ = new_base'-        lmads'' = lmads' ++@ lmads_base'-    pure $ IxFun lmads'' shp (cg && cg_base)---- | Rebase an index function on top of a new base. rebase ::   (Eq num, IntegralExp num) =>   IxFun num ->   IxFun num ->-  IxFun num-rebase new_base@(IxFun lmads_base shp_base cg_base) ixfun@(IxFun lmads shp cg)-  | Just ixfun' <- rebaseNice new_base ixfun = ixfun'-  -- In the general case just concatenate LMADs since this refers to index-  -- function composition, which is always safe.-  | otherwise =-      let (lmads_base', shp_base') =-            if base ixfun == shape new_base-              then (lmads_base, shp_base)-              else-                let IxFun lmads' shp_base'' _ = reshape new_base shp-                 in (lmads', shp_base'')-       in IxFun (lmads @++@ lmads_base') shp_base' (cg && cg_base)---- | If the memory support of the index function is contiguous and row-major--- (i.e., no transpositions, repetitions, rotates, etc.), then this should--- return the offset from which the memory-support of this index function--- starts.-linearWithOffset ::-  (Eq num, IntegralExp num) =>-  IxFun num ->-  num ->-  Maybe num-linearWithOffset ixfun@(IxFun (lmad :| []) _ cg) elem_size-  | hasContiguousPerm ixfun && cg && ixfunMonotonicity ixfun == Inc =-      Just $ lmadOffset lmad * elem_size-linearWithOffset _ _ = Nothing---- | Similar restrictions to @linearWithOffset@ except for transpositions, which--- are returned together with the offset.-rearrangeWithOffset ::-  (Eq num, IntegralExp num) =>-  IxFun num ->-  num ->-  Maybe (num, [(Int, num)])-rearrangeWithOffset (IxFun (lmad :| []) oshp cg) elem_size = do-  -- Note that @cg@ describes whether the index function is-  -- contiguous, *ignoring permutations*.  This function requires that-  -- functionality.-  let perm = lmadPermutation lmad-      perm_contig = [0 .. length perm - 1]-  offset <--    linearWithOffset-      (IxFun (setLMADPermutation perm_contig lmad :| []) oshp cg)-      elem_size-  pure (offset, zip perm (permuteFwd perm (lmadShapeBase lmad)))-rearrangeWithOffset _ _ = Nothing---- | Is this a row-major array starting at offset zero?-isLinear :: (Eq num, IntegralExp num) => IxFun num -> Bool-isLinear = (== Just 0) . flip linearWithOffset 1--flatOneDim ::-  (Eq num, IntegralExp num) =>-  num ->-  num ->-  num-flatOneDim s i-  | s == 0 = 0-  | otherwise = i * s+  Maybe (IxFun num)+rebase new_base@(IxFun lmad_base _) ixfun@(IxFun lmad shp) = do+  let dims = LMAD.dims lmad+      perm = LMAD.permutation lmad+      perm_base = LMAD.permutation lmad_base --- | Check monotonicity of an index function.-ixfunMonotonicity ::-  (Eq num, IntegralExp num) =>-  IxFun num ->-  Monotonicity-ixfunMonotonicity (IxFun (lmad :| lmads) _ _) =-  let mon0 = lmadMonotonicityRots lmad-   in if all ((== mon0) . lmadMonotonicityRots) lmads-        then mon0-        else Unknown-  where-    lmadMonotonicityRots ::-      (Eq num, IntegralExp num) =>-      LMAD num ->-      Monotonicity-    lmadMonotonicityRots (LMAD _ dims)-      | all (isMonDim Inc) dims = Inc-      | all (isMonDim Dec) dims = Dec-      | otherwise = Unknown+  guard $+    -- Core rebase condition.+    base ixfun == shape new_base+      -- XXX: We should be able to handle some basic cases where both index+      -- functions have non-trivial permutations.+      && (hasContiguousPerm ixfun || hasContiguousPerm new_base)+      -- We need the permutations to be of the same size if we want to compose+      -- them.  They don't have to be of the same size if the ixfun has a trivial+      -- permutation.  Supporting this latter case allows us to rebase when ixfun+      -- has been created by slicing with fixed dimensions.+      && (length perm == length perm_base || hasContiguousPerm ixfun)+      -- To not have to worry about ixfun having non-1 strides, we also check that+      -- it is a row-major array (modulo permutation, which is handled+      -- separately).  Accept a non-full outermost dimension.  XXX: Maybe this can+      -- be less conservative?+      && and+        ( zipWith3+            (\sn ld inner -> inner || sn == ldShape ld)+            shp+            dims+            (True : replicate (length dims - 1) False)+        ) -    isMonDim ::-      (Eq num, IntegralExp num) =>-      Monotonicity ->-      LMADDim num ->-      Bool-    isMonDim mon (LMADDim s _ _ ldmon) =-      s == 0 || mon == ldmon+  -- Compose permutations, reverse strides and adjust offset if necessary.+  let perm_base' =+        if hasContiguousPerm ixfun+          then perm_base+          else map (perm !!) perm_base+      lmad_base' = LMAD.setPermutation perm_base' lmad_base+      dims_base = LMAD.dims lmad_base'+      n_fewer_dims = length dims_base - length dims+      (dims_base', offs_contrib) =+        unzip $+          zipWith+            ( \(LMADDim s1 n1 p1) (LMADDim {}) ->+                let (s', off') = (s1, 0)+                 in (LMADDim s' n1 (p1 - n_fewer_dims), off')+            )+            -- If @dims@ is morally a slice, it might have fewer dimensions than+            -- @dims_base@.  Drop extraneous outer dimensions.+            (drop n_fewer_dims dims_base)+            dims+      off_base = LMAD.offset lmad_base' + sum offs_contrib+      lmad_base'' =+        LMAD.setShape+          (LMAD.shape lmad)+          ( LMAD+              (off_base + ldStride (last dims_base) * LMAD.offset lmad)+              dims_base'+          )+  pure $ IxFun lmad_base'' shp  -- | Turn all the leaves of the index function into 'Ext's.  We --  require that there's only one LMAD, that the index function is@@ -725,31 +353,22 @@ closeEnough :: IxFun num -> IxFun num -> Bool closeEnough ixf1 ixf2 =   (length (base ixf1) == length (base ixf2))-    && (NE.length (ixfunLMADs ixf1) == NE.length (ixfunLMADs ixf2))-    && all closeEnoughLMADs (NE.zip (ixfunLMADs ixf1) (ixfunLMADs ixf2))-    -- This treats ixf1 as the "declared type" that we are matching against.-    && (contiguous ixf1 <= contiguous ixf2)+    && closeEnoughLMADs (ixfunLMAD ixf1) (ixfunLMAD ixf2)   where-    closeEnoughLMADs :: (LMAD num, LMAD num) -> Bool-    closeEnoughLMADs (lmad1, lmad2) =-      length (lmadDims lmad1) == length (lmadDims lmad2)-        && map ldPerm (lmadDims lmad1)-          == map ldPerm (lmadDims lmad2)+    closeEnoughLMADs lmad1 lmad2 =+      length (LMAD.dims lmad1) == length (LMAD.dims lmad2)+        && map ldPerm (LMAD.dims lmad1) == map ldPerm (LMAD.dims lmad2)  -- | Returns true if two 'IxFun's are equivalent. -- -- Equivalence in this case is defined as having the same number of LMADs, with--- each pair of LMADs matching in permutation, offsets, strides and rotations.+-- each pair of LMADs matching in permutation, offsets, and strides. equivalent :: Eq num => IxFun num -> IxFun num -> Bool equivalent ixf1 ixf2 =-  NE.length (ixfunLMADs ixf1) == NE.length (ixfunLMADs ixf2)-    && all equivalentLMADs (NE.zip (ixfunLMADs ixf1) (ixfunLMADs ixf2))+  equivalentLMADs (ixfunLMAD ixf1) (ixfunLMAD ixf2)   where-    equivalentLMADs (lmad1, lmad2) =-      length (lmadDims lmad1) == length (lmadDims lmad2)-        && map ldPerm (lmadDims lmad1)-          == map ldPerm (lmadDims lmad2)-        && lmadOffset lmad1-          == lmadOffset lmad2-        && map ldStride (lmadDims lmad1)-          == map ldStride (lmadDims lmad2)+    equivalentLMADs lmad1 lmad2 =+      length (LMAD.dims lmad1) == length (LMAD.dims lmad2)+        && map ldPerm (LMAD.dims lmad1) == map ldPerm (LMAD.dims lmad2)+        && LMAD.offset lmad1 == LMAD.offset lmad2+        && map ldStride (LMAD.dims lmad1) == map ldStride (LMAD.dims lmad2)
src/Futhark/IR/Mem/LMAD.hs view
@@ -1,40 +1,62 @@ -- | This module contains a representation of linear-memory accessor -- descriptors (LMAD); see work by Zhu, Hoeflinger and David.+--+-- This module is designed to be used as a qualified import, as the+-- exported names are quite generic. module Futhark.IR.Mem.LMAD   ( Shape,+    Indices,     LMAD (..),     LMADDim (..),-    Monotonicity (..),     Permutation,-    lmadShape,-    lmadShapeBase,+    index,+    slice,+    flatSlice,+    reshape,+    permute,+    shape,+    permutation,+    shapeBase,+    setPermutation,+    setShape,     substituteInLMAD,     permuteInv,     permuteFwd,-    conservativeFlatten,     disjoint,     disjoint2,     disjoint3,     dynamicEqualsLMAD,-    lmadPermutation,-    makeRotIota,-    invertMonotonicity,+    contiguous,+    memcpyable,+    noPermutation,+    iota,+    mkExistential,   ) where  import Control.Category import Control.Monad+import Data.Foldable (toList) import Data.Function (on, (&))-import Data.List (elemIndex, partition, sortBy, zipWith4)+import Data.List (elemIndex, partition, sort, sortBy) import Data.Map.Strict qualified as M-import Data.Maybe (fromJust, isNothing)+import Data.Maybe (fromJust, isJust, isNothing) import Data.Traversable import Futhark.Analysis.AlgSimplify qualified as AlgSimplify import Futhark.Analysis.PrimExp import Futhark.Analysis.PrimExp.Convert import Futhark.IR.Mem.Interval import Futhark.IR.Prop-import Futhark.IR.Syntax (Type)+import Futhark.IR.Syntax+  ( DimIndex (..),+    Ext (..),+    FlatDimIndex (..),+    FlatSlice (..),+    Slice (..),+    Type,+    dimFix,+    unitSlice,+  ) import Futhark.IR.Syntax.Core (VName (..)) import Futhark.Transform.Rename import Futhark.Transform.Substitute@@ -46,51 +68,26 @@ -- | The shape of an index function. type Shape num = [num] -type Permutation = [Int]+-- | Indices passed to an LMAD.  Must always match the rank of the LMAD.+type Indices num = [num] --- | The physical element ordering alongside a dimension, i.e. the--- sign of the stride.-data Monotonicity-  = -- | Increasing.-    Inc-  | -- | Decreasing.-    Dec-  | -- | Unknown.-    Unknown-  deriving (Show, Eq)+-- | A complete permutation.+type Permutation = [Int]  -- | A single dimension in an 'LMAD'. data LMADDim num = LMADDim   { ldStride :: num,     ldShape :: num,-    ldPerm :: Int,-    ldMon :: Monotonicity+    ldPerm :: Int   }-  deriving (Show, Eq)--instance Ord Monotonicity where-  (<=) _ Inc = True-  (<=) Unknown _ = True-  (<=) _ Unknown = False-  (<=) Inc Dec = False-  (<=) _ Dec = True--instance Ord num => Ord (LMADDim num) where-  (LMADDim s1 q1 p1 m1) <= (LMADDim s2 q2 p2 m2) =-    ([q1, s1] < [q2, s2])-      || ( ([q1, s1] == [q2, s2])-             && ( (p1 < p2)-                    || ( (p1 == p2)-                           && (m1 <= m2)-                       )-                )-         )+  deriving (Show, Eq, Ord) --- | LMAD's representation consists of a general offset and for each dimension a--- stride, number of elements (or shape), permutation, and--- monotonicity. Note that the permutation is not strictly necessary in that the--- permutation can be performed directly on LMAD dimensions, but then it is--- difficult to extract the permutation back from an LMAD.+-- | LMAD's representation consists of a general offset and for each+-- dimension a stride, number of elements (or shape), and+-- permutation. Note that the permutation is not strictly necessary in+-- that the permutation can be performed directly on LMAD dimensions,+-- but then it is difficult to extract the permutation back from an+-- LMAD. -- -- LMAD algebra is closed under composition w.r.t. operators such as -- permute, index and slice.  However, other operations, such as@@ -116,22 +113,18 @@ --    \{ ~ \sigma + i_1 * s_1 + \ldots + i_m * s_m ~ | ~ 0 \leq i_1 < n_1, \ldots, 0 \leq i_m < n_m ~ \} -- \] data LMAD num = LMAD-  { lmadOffset :: num,-    lmadDims :: [LMADDim num]+  { offset :: num,+    dims :: [LMADDim num]   }   deriving (Show, Eq, Ord) -instance Pretty Monotonicity where-  pretty = pretty . show- instance Pretty num => Pretty (LMAD num) where   pretty (LMAD offset dims) =     braces . semistack $       [ "offset:" <+> group (pretty offset),         "strides:" <+> p ldStride,         "shape:" <+> p ldShape,-        "permutation:" <+> p ldPerm,-        "monotonicity:" <+> p ldMon+        "permutation:" <+> p ldPerm       ]     where       p f = group $ brackets $ align $ commasep $ map (pretty . f) dims@@ -146,7 +139,7 @@   freeIn' = foldMap freeIn'  instance FreeIn num => FreeIn (LMADDim num) where-  freeIn' (LMADDim s n _ _) = freeIn' s <> freeIn' n+  freeIn' (LMADDim s n _) = freeIn' s <> freeIn' n  instance Functor LMAD where   fmap = fmapDefault@@ -158,16 +151,188 @@   traverse f (LMAD offset dims) =     LMAD <$> f offset <*> traverse f' dims     where-      f' (LMADDim s n p m) = LMADDim <$> f s <*> f n <*> pure p <*> pure m+      f' (LMADDim s n p) = LMADDim <$> f s <*> f n <*> pure p -invertMonotonicity :: Monotonicity -> Monotonicity-invertMonotonicity Inc = Dec-invertMonotonicity Dec = Inc-invertMonotonicity Unknown = Unknown+flatOneDim ::+  (Eq num, IntegralExp num) =>+  num ->+  num ->+  num+flatOneDim s i+  | s == 0 = 0+  | otherwise = i * s -lmadPermutation :: LMAD num -> Permutation-lmadPermutation = map ldPerm . lmadDims+index :: (IntegralExp num, Eq num) => LMAD num -> Indices num -> num+index lmad@(LMAD off dims) inds =+  off + sum prods+  where+    prods =+      zipWith+        flatOneDim+        (map ldStride dims)+        (permuteInv (permutation lmad) inds) +setLMADPermutation :: Permutation -> LMAD num -> LMAD num+setLMADPermutation perm lmad =+  lmad {dims = zipWith (\dim p -> dim {ldPerm = p}) (dims lmad) perm}++-- | Handle the case where a slice can stay within a single LMAD.+slice ::+  (Eq num, IntegralExp num) =>+  LMAD num ->+  Slice num ->+  LMAD num+slice lmad@(LMAD _ ldims) (Slice is) =+  let perm = permutation lmad+      is' = permuteInv perm is+      lmad' = foldl sliceOne (LMAD (offset lmad) []) $ zip is' ldims+      -- need to remove the fixed dims from the permutation+      perm' =+        updatePerm perm $+          map fst $+            filter (isJust . dimFix . snd) $+              zip [0 .. length is' - 1] is'+   in setLMADPermutation perm' lmad'+  where+    updatePerm ps inds = concatMap decrease ps+      where+        decrease p =+          let f n i+                | i == p = -1+                | i > p = n+                | n /= -1 = n + 1+                | otherwise = n+              d = foldl f 0 inds+           in [p - d | d /= -1]++    sliceOne ::+      (Eq num, IntegralExp num) =>+      LMAD num ->+      (DimIndex num, LMADDim num) ->+      LMAD num+    sliceOne (LMAD off dims) (DimFix i, LMADDim s _x _) =+      LMAD (off + flatOneDim s i) dims+    sliceOne (LMAD off dims) (DimSlice _ ne _, LMADDim 0 _ p) =+      LMAD off (dims ++ [LMADDim 0 ne p])+    sliceOne (LMAD off dims) (dmind, dim@(LMADDim _ n _))+      | dmind == unitSlice 0 n = LMAD off (dims ++ [dim])+    sliceOne (LMAD off dims) (dmind, LMADDim s n p)+      | dmind == DimSlice (n - 1) n (-1) =+          let off' = off + flatOneDim s (n - 1)+           in LMAD off' (dims ++ [LMADDim (s * (-1)) n p])+    sliceOne (LMAD off dims) (DimSlice b ne 0, LMADDim s _ p) =+      LMAD (off + flatOneDim s b) (dims ++ [LMADDim 0 ne p])+    sliceOne (LMAD off dims) (DimSlice bs ns ss, LMADDim s _ p) =+      LMAD (off + s * bs) (dims ++ [LMADDim (ss * s) ns p])++hasContiguousPerm :: LMAD num -> Bool+hasContiguousPerm lmad = perm == sort perm+  where+    perm = permutation lmad++-- | Flat-slice an LMAD.+flatSlice ::+  (IntegralExp num) =>+  LMAD num ->+  FlatSlice num ->+  Maybe (LMAD num)+flatSlice lmad@(LMAD offset (dim : dims)) (FlatSlice new_offset is)+  | hasContiguousPerm lmad =+      Just $+        LMAD+          (offset + new_offset * ldStride dim)+          (map (helper $ ldStride dim) is <> dims)+          & setLMADPermutation [0 ..]+  where+    helper s0 (FlatDimIndex n s) = LMADDim (s0 * s) n 0+flatSlice _ _ = Nothing++-- | Handle the case where a reshape operation can stay inside a+-- single LMAD.  See "Futhark.IR.Mem.IxFun.reshape" for+-- conditions.+reshape ::+  (Eq num, IntegralExp num) => LMAD num -> Shape num -> Maybe (LMAD num)+--+-- First a special case for when we are merely injecting unit+-- dimensions into a non-permuted LMAD.+reshape lmad@(LMAD off dims) newshape+  | sort (permutation lmad) == permutation lmad,+    Just dims' <- addingVacuous 0 newshape dims =+      Just $ LMAD off dims'+  where+    addingVacuous i (dnew : dnews) (dold : dolds)+      | dnew == ldShape dold =+          (dold {ldPerm = i} :) <$> addingVacuous (i + 1) dnews dolds+    addingVacuous i (1 : dnews) dolds =+      (LMADDim 0 1 i :) <$> addingVacuous (i + 1) dnews dolds+    addingVacuous _ [] [] = Just []+    addingVacuous _ _ _ = Nothing++-- Then the general case.+reshape lmad@(LMAD off dims) newshape = do+  let perm = permutation lmad+      dims_perm = permuteFwd perm dims+      mid_dims = take (length dims) dims_perm++  guard $+    -- checking conditions (2)+    all (\(LMADDim s _ _) -> s /= 0) mid_dims+      &&+      -- checking condition (1)+      consecutive 0 (map ldPerm mid_dims)+      &&+      -- checking condition (3)+      hasContiguousPerm lmad+      && all+        (\(ld, se) -> ldStride ld == se)+        (zip dims (reverse $ scanl (*) 1 (reverse (tail (shape lmad)))))++  -- make new permutation+  let rsh_len = length newshape+      diff = length newshape - length dims+      iota_shape = [0 .. length newshape - 1]+      perm' =+        map+          ( \i ->+              let ind = i - diff+               in if (i >= 0) && (i < rsh_len)+                    then i -- already checked mid_dims not affected+                    else ldPerm (dims !! ind) + diff+          )+          iota_shape+      -- split the dimensions+      (support_inds, repeat_inds) =+        foldl+          (\(sup, rpt) (shpdim, ip) -> ((ip, shpdim) : sup, rpt))+          ([], [])+          $ reverse+          $ zip newshape perm'++      (sup_inds, support) = unzip $ sortBy (compare `on` fst) support_inds+      (rpt_inds, repeats) = unzip repeat_inds+      LMAD off' dims_sup = iota off support+      repeats' = map (\n -> LMADDim 0 n 0) repeats+      dims' =+        map snd $+          sortBy (compare `on` fst) $+            zip sup_inds dims_sup ++ zip rpt_inds repeats'+      lmad' = LMAD off' dims'+  Just $ setLMADPermutation perm' lmad'+  where+    consecutive _ [] = True+    consecutive i [p] = i == p+    consecutive i ps = and $ zipWith (==) ps [i, i + 1 ..]++permutation :: LMAD num -> Permutation+permutation = map ldPerm . dims++setPermutation :: Permutation -> LMAD num -> LMAD num+setPermutation perm lmad =+  lmad {dims = zipWith (\dim p -> dim {ldPerm = p}) (dims lmad) perm}++setShape :: Shape num -> LMAD num -> LMAD num+setShape shp lmad = lmad {dims = zipWith (\dim s -> dim {ldShape = s}) (dims lmad) shp}+ -- | Substitute a name with a PrimExp in an LMAD. substituteInLMAD ::   Ord a =>@@ -175,29 +340,19 @@   LMAD (TPrimExp t a) ->   LMAD (TPrimExp t a) substituteInLMAD tab (LMAD offset dims) =-  let offset' = sub offset-      dims' =-        map-          ( \(LMADDim s n p m) ->-              LMADDim-                (sub s)-                (sub n)-                p-                m-          )-          dims-   in LMAD offset' dims'+  LMAD (sub offset) $+    map (\(LMADDim s n p) -> LMADDim (sub s) (sub n) p) dims   where     tab' = fmap untyped tab     sub = TPrimExp . substituteInPrimExp tab' . untyped  -- | Shape of an LMAD.-lmadShape :: LMAD num -> Shape num-lmadShape lmad = permuteInv (lmadPermutation lmad) $ lmadShapeBase lmad+shape :: LMAD num -> Shape num+shape lmad = permuteInv (permutation lmad) $ shapeBase lmad  -- | Shape of an LMAD, ignoring permutations.-lmadShapeBase :: LMAD num -> Shape num-lmadShapeBase = map ldShape . lmadDims+shapeBase :: LMAD num -> Shape num+shapeBase = map ldShape . dims  permuteFwd :: Permutation -> [a] -> [a] permuteFwd ps elems = map (elems !!) ps@@ -205,28 +360,37 @@ permuteInv :: Permutation -> [a] -> [a] permuteInv ps elems = map snd $ sortBy (compare `on` fst) $ zip ps elems --- | Generalised iota with user-specified offset and rotates.-makeRotIota ::+-- | Generalised iota with user-specified offset.+iota ::   IntegralExp num =>-  Monotonicity ->   -- | Offset   num ->   -- | Shape   [num] ->   LMAD num-makeRotIota mon off ns-  | mon == Inc || mon == Dec =-      let rk = length ns-          ss0 = reverse $ take rk $ scanl (*) 1 $ reverse ns-          ss =-            if mon == Inc-              then ss0-              else map (* (-1)) ss0-          ps = map fromIntegral [0 .. rk - 1]-          fi = replicate rk mon-       in LMAD off $ zipWith4 LMADDim ss ns ps fi-  | otherwise = error "makeRotIota: requires Inc or Dec"+iota off ns =+  let rk = length ns+      ss = reverse $ take rk $ scanl (*) 1 $ reverse ns+      ps = map fromIntegral [0 .. rk - 1]+   in LMAD off $ zipWith3 LMADDim ss ns ps +-- | Create an LMAD that is existential in everything, with the+-- provided permutation.+mkExistential :: [Int] -> Int -> LMAD (Ext a)+mkExistential perm start =+  lmad+  where+    lmad = LMAD (Ext start) $ zipWith onDim perm [0 ..]+    onDim p i =+      LMADDim (Ext (start + 1 + i * 2)) (Ext (start + 2 + i * 2)) p++-- | Permute dimensions.+permute :: LMAD num -> Permutation -> LMAD num+permute lmad perm_new =+  let perm_cur = permutation lmad+      perm = map (perm_cur !!) perm_new+   in setPermutation perm lmad+ -- | Computes the maximum span of an 'LMAD'. The result is the lowest and -- highest flat values representable by that 'LMAD'. flatSpan :: LMAD (TPrimExp Int64 VName) -> TPrimExp Int64 VName@@ -248,7 +412,7 @@ -- conservativeFlatten :: (IntegralExp e, Ord e, Pretty e) => LMAD e -> LMAD e conservativeFlatten :: LMAD (TPrimExp Int64 VName) -> Maybe (LMAD (TPrimExp Int64 VName)) conservativeFlatten (LMAD offset []) =-  pure $ LMAD offset [LMADDim 1 1 0 Inc]+  pure $ LMAD offset [LMADDim 1 1 0] conservativeFlatten l@(LMAD _ [_]) =   pure l conservativeFlatten l@(LMAD offset dims) = do@@ -257,7 +421,7 @@       gcd       (ldStride $ head dims)       $ map ldStride dims-  pure $ LMAD offset [LMADDim strd (shp + 1) 0 Unknown]+  pure $ LMAD offset [LMADDim strd (shp + 1) 0]   where     shp = flatSpan l @@ -440,12 +604,12 @@ lmadToIntervals :: LMAD (TPrimExp Int64 VName) -> (AlgSimplify.SofP, [Interval]) lmadToIntervals (LMAD offset []) = (AlgSimplify.simplify0 $ untyped offset, [Interval 0 1 1]) lmadToIntervals lmad@(LMAD offset dims0) =-  (offset', map helper $ permuteInv (lmadPermutation lmad) dims0)+  (offset', map helper $ permuteInv (permutation lmad) dims0)   where     offset' = AlgSimplify.simplify0 $ untyped offset      helper :: LMADDim (TPrimExp Int64 VName) -> Interval-    helper (LMADDim strd shp _ _) = do+    helper (LMADDim strd shp _) = do       Interval 0 (AlgSimplify.simplify' shp) (AlgSimplify.simplify' strd)  -- | Dynamically determine if two 'LMADDim' are equal.@@ -456,15 +620,52 @@   ldStride dim1 .==. ldStride dim2     .&&. ldShape dim1 .==. ldShape dim2     .&&. fromBool (ldPerm dim1 == ldPerm dim2)-    .&&. fromBool (ldMon dim1 == ldMon dim2)  -- | Dynamically determine if two 'LMAD' are equal. -- -- True if offset and constituent 'LMADDim' are equal. dynamicEqualsLMAD :: Eq num => LMAD (TPrimExp t num) -> LMAD (TPrimExp t num) -> TPrimExp Bool num dynamicEqualsLMAD lmad1 lmad2 =-  lmadOffset lmad1 .==. lmadOffset lmad2+  offset lmad1 .==. offset lmad2     .&&. foldr       ((.&&.) . uncurry dynamicEqualsLMADDim)       true-      (zip (lmadDims lmad1) (lmadDims lmad2))+      (zip (dims lmad1) (dims lmad2))++-- | True if these LMADs represent the same function (ignoring+-- offset).+compatible ::+  Eq num =>+  LMAD (TPrimExp Int64 num) ->+  LMAD (TPrimExp Int64 num) ->+  TPrimExp Bool num+compatible x y =+  foldl1 (.&&.) $ zipWith dynamicEqualsLMADDim (dims x) (dims y)++-- | True if this LMAD corresponds to an array without "holes".  This+-- implies it can be copied with a memcpy()-like operation.+contiguous ::+  (Pretty num, Eq num) =>+  LMAD (TPrimExp Int64 num) ->+  TPrimExp Bool num+contiguous lmad =+  foldl1 (.&&.) $ zipWith (.==.) (toList lmad) lmad'+  where+    lmad' = toList (iota (offset lmad) $ map ldShape $ dims lmad)++-- | True if these LMADs have the same contiguous representation, such+-- that one can be copied to the other with a @memcpy()@-like+-- operation.+memcpyable ::+  (Pretty num, Eq num) =>+  LMAD (TPrimExp Int64 num) ->+  LMAD (TPrimExp Int64 num) ->+  TPrimExp Bool num+memcpyable dest_lmad src_lmad =+  contiguous dest_lmad .&&. compatible dest_lmad src_lmad++-- | Remove the permutation of an LMAD by actually applying it to the+-- dimensions.+noPermutation :: LMAD t -> LMAD t+noPermutation lmad =+  lmad {dims = rearrangeShape (permutation lmad) $ dims lmad}
src/Futhark/IR/Parse.hs view
@@ -17,9 +17,8 @@  import Data.Char (isAlpha) import Data.Functor-import Data.List (singleton, zipWith4)+import Data.List (singleton) import Data.List.NonEmpty (NonEmpty (..))-import Data.List.NonEmpty qualified as NE import Data.Maybe import Data.Set qualified as S import Data.Text qualified as T@@ -68,9 +67,6 @@     pTag = "_" *> L.decimal <* notFollowedBy (satisfy constituent)     exprBox = ("<{" <>) . (<> "}>") <$> (chunk "<{" *> manyTill anySingle (chunk "}>")) -pBool :: Parser Bool-pBool = choice [keyword "true" $> True, keyword "false" $> False]- pInt :: Parser Int pInt = lexeme L.decimal @@ -975,24 +971,16 @@ pIxFunBase pNum =   braces $ do     base <- pLab "base" $ brackets (pNum `sepBy` pComma) <* pSemi-    ct <- pLab "contiguous" $ pBool <* pSemi-    lmads <- pLab "LMADs" $ brackets (pLMAD `sepBy1` pComma)-    pure $ IxFun.IxFun (NE.fromList lmads) base ct+    lmad <- pLab "LMAD" pLMAD+    pure $ IxFun.IxFun lmad base   where     pLab s m = keyword s *> pColon *> m-    pMon =-      choice-        [ "Inc" $> IxFun.Inc,-          "Dec" $> IxFun.Dec,-          "Unknown" $> IxFun.Unknown-        ]     pLMAD = braces $ do       offset <- pLab "offset" pNum <* pSemi       strides <- pLab "strides" $ brackets (pNum `sepBy` pComma) <* pSemi       shape <- pLab "shape" $ brackets (pNum `sepBy` pComma) <* pSemi-      perm <- pLab "permutation" $ brackets (pInt `sepBy` pComma) <* pSemi-      mon <- pLab "monotonicity" $ brackets (pMon `sepBy` pComma)-      pure $ IxFun.LMAD offset $ zipWith4 IxFun.LMADDim strides shape perm mon+      perm <- pLab "permutation" $ brackets (pInt `sepBy` pComma)+      pure $ IxFun.LMAD offset $ zipWith3 IxFun.LMADDim strides shape perm  pPrimExpLeaf :: Parser VName pPrimExpLeaf = pVName
src/Futhark/Internalise/ReplaceRecords.hs view
@@ -4,6 +4,7 @@ -- around huge records of which only a tiny part is needed. module Futhark.Internalise.ReplaceRecords (transformProg) where +import Control.Monad import Control.Monad.Reader import Control.Monad.State import Data.Map.Strict qualified as M
src/Futhark/Internalise/TypesValues.hs view
@@ -21,6 +21,7 @@   ) where +import Control.Monad import Control.Monad.Free (Free (..)) import Control.Monad.State import Data.Bitraversable (bitraverse)
src/Futhark/LSP/Handlers.hs view
@@ -89,8 +89,8 @@ -- | Given an 'IORef' tracking the state, produce a set of handlers. -- When we want to add more features to the language server, this is -- the thing to change.-handlers :: IORef State -> Handlers (LspM ())-handlers state_mvar =+handlers :: IORef State -> ClientCapabilities -> Handlers (LspM ())+handlers state_mvar _ =   mconcat     [ onInitializeHandler,       onDocumentOpenHandler state_mvar,
src/Futhark/Optimise/ArrayShortCircuiting/ArrayCoalescing.hs view
@@ -17,7 +17,6 @@ import Data.Function ((&)) import Data.List qualified as L import Data.List.NonEmpty (NonEmpty (..))-import Data.List.NonEmpty qualified as NE import Data.Map.Strict qualified as M import Data.Maybe import Data.Sequence (Seq (..))@@ -421,8 +420,10 @@                 (aggSummaryMapPartial (scalarTable td_env) $ unSegSpace space0)                 (S.toList s)             Undeterminable -> pure Undeterminable-        let res = noMemOverlap td_env destination_uses source_writes-        if res+        -- Do not allow short-circuiting from a segop-local memory+        -- block (not in the topdown scope) to an outer memory block.+        if dstmem entry `M.member` scope td_env+          && noMemOverlap td_env destination_uses source_writes           then pure bu_env_f           else do             let (ac, inh) = markFailedCoal (activeCoals bu_env_f, inhibit bu_env_f) k@@ -484,8 +485,8 @@                     Just (Coalesced knd mbd@(MemBlock _ _ _ ixfn) _) -> pure $                       case freeVarSubstitutions (scope td_env) (scalarTable td_env) ixfn of                         Just fv_subst ->-                          if ixfunPermutation ixfn-                            == ixfunPermutation (ixfun $ fromJust $ getScopeMemInfo (patElemName p) $ scope td_env)+                          if IxFun.permutation ixfn+                            == IxFun.permutation (ixfun $ fromJust $ getScopeMemInfo (patElemName p) $ scope td_env)                             then                               let entry =                                     coal_entry@@ -506,9 +507,6 @@    foldM checkMergeeOverlap bu_env''' mergee_writes -ixfunPermutation :: IxFun -> [Int]-ixfunPermutation = map IxFun.ldPerm . IxFun.lmadDims . NE.head . IxFun.ixfunLMADs- -- | Given a pattern element and the corresponding kernel result, try to put the -- kernel result directly in the memory block of pattern element makeSegMapCoals ::@@ -534,8 +532,7 @@       case M.lookup pat_mem active of         Nothing ->           -- We are not in a transitive case-          case ( IxFun.hasOneLmad pat_ixf-                   && maybe False (pat_mem `nameIn`) (M.lookup return_mem inhb),+          case ( maybe False (pat_mem `nameIn`) (M.lookup return_mem inhb),                  Coalesced                    InPlaceCoal                    (MemBlock tp return_shp pat_mem $ resultSlice pat_ixf)@@ -1259,8 +1256,7 @@                         _ -> (failed, s_acc) -- fail!  ixfunToAccessSummary :: IxFun.IxFun (TPrimExp Int64 VName) -> AccessSummary-ixfunToAccessSummary (IxFun.IxFun (lmad NE.:| []) _ _) = Set $ S.singleton lmad-ixfunToAccessSummary _ = Undeterminable+ixfunToAccessSummary (IxFun.IxFun lmad _) = Set $ S.singleton lmad  -- | Check safety conditions 2 and 5 and update new substitutions: -- called on the pat-elements of loop and if-then-else expressions.@@ -1365,9 +1361,8 @@                       Nothing ->                         ind_y                  in (m_y, alias_fn ind, oneName m_x <> y_al, x_deps0, certs <> certs'')-          success0 = IxFun.hasOneLmad ind_yx           m_b_aliased_m_yx = areAnyAliased td_env m_b [m_yx] -- m_b \= m_yx-       in if success0 && not m_b_aliased_m_yx && isInScope td_env m_yx -- nameIn m_yx (alloc td_env)+       in if not m_b_aliased_m_yx && isInScope td_env m_yx -- nameIn m_yx (alloc td_env)       -- Finally update the @activeCoals@ table with a fresh       --   binding for @m_b@; if such one exists then overwrite.       -- Also, add all variables from the alias chain of @b@ to@@ -1562,7 +1557,10 @@   where     updateIndFunSlice :: IxFun -> FlatSlice SubExp -> IxFun     updateIndFunSlice ind_fun (FlatSlice offset dims) =-      IxFun.flatSlice ind_fun $ FlatSlice (pe64 offset) $ map (fmap pe64) dims+      fromMaybe (error "updateIndFunSlice") $+        IxFun.flatSlice ind_fun $+          FlatSlice (pe64 offset) $+            map (fmap pe64) dims  -- CASE b) @let x = concat(a, b^{lu})@ genCoalStmtInfo lutab _ scopetab (Let pat aux (BasicOp (Concat concat_dim (b0 :| bs) _)))
src/Futhark/Optimise/ArrayShortCircuiting/MemRefAggreg.hs view
@@ -134,12 +134,12 @@         Constant _ -> Just (ws, ws)         Var x -> Just (ws, ws ++ mapMaybe (getDirAliasedIxfn td_env coal_tab) [x]) getUseSumFromStm td_env coal_tab (Let (Pat [x]) _ (BasicOp (FlatUpdate _ (FlatSlice offset slc) v)))-  | Just (m_b, m_x, x_ixfn) <- getDirAliasedIxfn td_env coal_tab (patElemName x) =-      let x_ixfn_slc = IxFun.flatSlice x_ixfn $ FlatSlice (pe64 offset) $ map (fmap pe64) slc-          r1 = (m_b, m_x, x_ixfn_slc)-       in case getDirAliasedIxfn td_env coal_tab v of-            Nothing -> Just ([r1], [r1])-            Just r2 -> Just ([r1], [r1, r2])+  | Just (m_b, m_x, x_ixfn) <- getDirAliasedIxfn td_env coal_tab (patElemName x) = do+      x_ixfn_slc <- IxFun.flatSlice x_ixfn $ FlatSlice (pe64 offset) $ map (fmap pe64) slc+      let r1 = (m_b, m_x, x_ixfn_slc)+      case getDirAliasedIxfn td_env coal_tab v of+        Nothing -> Just ([r1], [r1])+        Just r2 -> Just ([r1], [r1, r2]) -- getUseSumFromStm td_env coal_tab (Let (Pat ys) _ (BasicOp bop)) = --   let wrt = mapMaybe (getDirAliasedIxfn td_env coal_tab . patElemName) ys --    in trace ("getUseBla: " <> show bop) $ pure (wrt, wrt)@@ -251,7 +251,7 @@         <> fromMaybe mempty (M.lookup m (m_alias td_env))     mbLmad indfun       | Just subs <- freeVarSubstitutions (scope td_env) (scals bu_env) indfun,-        (IxFun.IxFun (lmad :| []) _ _) <- IxFun.substituteInIxFun subs indfun =+        (IxFun.IxFun lmad _) <- IxFun.substituteInIxFun subs indfun =           Just lmad     mbLmad _ = Nothing     addLmads wrts uses etry =@@ -458,7 +458,7 @@           new_offset = replaceIteratorWith lower_bound offset0           new_lmad =             IxFun.LMAD new_offset $-              IxFun.LMADDim new_stride spn 0 IxFun.Inc : map incPerm dims0+              IxFun.LMADDim new_stride spn 0 : map incPerm dims0       if new_var `nameIn` freeIn new_lmad         then pure Undeterminable         else pure $ Set $ S.singleton new_lmad
src/Futhark/Optimise/ArrayShortCircuiting/TopdownAnalysis.hs view
@@ -27,7 +27,7 @@ import Futhark.IR.Mem.IxFun qualified as IxFun import Futhark.Optimise.ArrayShortCircuiting.DataStructs -type DirAlias = IxFun -> IxFun+type DirAlias = IxFun -> Maybe IxFun -- ^ A direct aliasing transformation  type InvAlias = Maybe (IxFun -> IxFun)@@ -69,23 +69,23 @@  -- | Get alias and (direct) index function mapping from expression getDirAliasFromExp :: Exp (Aliases rep) -> Maybe (VName, DirAlias)-getDirAliasFromExp (BasicOp (SubExp (Var x))) = Just (x, id)-getDirAliasFromExp (BasicOp (Opaque _ (Var x))) = Just (x, id)+getDirAliasFromExp (BasicOp (SubExp (Var x))) = Just (x, Just)+getDirAliasFromExp (BasicOp (Opaque _ (Var x))) = Just (x, Just) getDirAliasFromExp (BasicOp (Reshape ReshapeCoerce shp x)) =-  Just (x, (`IxFun.coerce` shapeDims (fmap pe64 shp)))+  Just (x, Just . (`IxFun.coerce` shapeDims (fmap pe64 shp))) getDirAliasFromExp (BasicOp (Reshape ReshapeArbitrary shp x)) =   Just (x, (`IxFun.reshape` shapeDims (fmap pe64 shp))) getDirAliasFromExp (BasicOp (Rearrange _ _)) =   Nothing getDirAliasFromExp (BasicOp (Index x slc)) =-  Just (x, (`IxFun.slice` (Slice $ map (fmap pe64) $ unSlice slc)))-getDirAliasFromExp (BasicOp (Update _ x _ _elm)) = Just (x, id)+  Just (x, Just . (`IxFun.slice` (Slice $ map (fmap pe64) $ unSlice slc)))+getDirAliasFromExp (BasicOp (Update _ x _ _elm)) = Just (x, Just) getDirAliasFromExp (BasicOp (FlatIndex x (FlatSlice offset idxs))) =   Just     ( x,       (`IxFun.flatSlice` FlatSlice (pe64 offset) (map (fmap pe64) idxs))     )-getDirAliasFromExp (BasicOp (FlatUpdate x _ _)) = Just (x, id)+getDirAliasFromExp (BasicOp (FlatUpdate x _ _)) = Just (x, Just) getDirAliasFromExp _ = Nothing  -- | This was former @createsAliasedArrOK@ from DataStructs@@ -268,7 +268,8 @@ walkAliasTab alias_tab vtab x   | Just (x0, alias0, _) <- M.lookup x alias_tab = do       Coalesced knd (MemBlock pt shp vname ixf) substs <- walkAliasTab alias_tab vtab x0-      pure $ Coalesced knd (MemBlock pt shp vname $ alias0 ixf) substs+      ixf' <- alias0 ixf+      pure $ Coalesced knd (MemBlock pt shp vname ixf') substs walkAliasTab _ _ _ = Nothing  -- | We assume @x@ is in @vartab@ and we add the variables that @x@ aliases
src/Futhark/Optimise/BlkRegTiling.hs view
@@ -20,12 +20,12 @@  import Control.Monad import Data.List qualified as L-import Data.List.NonEmpty qualified as NE import Data.Map.Strict qualified as M import Data.Maybe import Data.Sequence qualified as Seq import Futhark.IR.GPU import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.MonadFreshNames import Futhark.Optimise.TileLoops.Shared import Futhark.Tools@@ -143,12 +143,12 @@         | [slc_X'] <- patNames pat,           slc_X == slc_X',           Just ixf_fn <- M.lookup x ixfn_env,-          (IxFun.IxFun lmads _ _) <- ixf_fn =-            all innerHasStride1 $ NE.toList lmads+          (IxFun.IxFun lmad _) <- ixf_fn =+            innerHasStride1 lmad       isInnerCoal _ _ _ =         error "kkLoopBody.isInnerCoal: not an error, but I would like to know why!"       innerHasStride1 lmad =-        let lmad_dims = IxFun.lmadDims lmad+        let lmad_dims = LMAD.dims lmad             q = length lmad_dims             last_perm = IxFun.ldPerm $ last lmad_dims             stride = IxFun.ldStride $ last lmad_dims
src/Futhark/Optimise/Simplify/Rules/Simple.hs view
@@ -68,7 +68,7 @@     op1 == op2,     Just res <- doBinOp op1 x1 x2 =       Just (BinOp op1 (Constant res) y2, cs)-simplifyBinOp look _ (BinOp Add {} e1 e2)+simplifyBinOp look _ (BinOp (Add it ovf) e1 e2)   | isCt0 e1 = resIsSubExp e2   | isCt0 e2 = resIsSubExp e1   -- x+(y-x) => y@@ -76,13 +76,20 @@     Just (BasicOp (BinOp Sub {} e2_a e2_b), cs) <- look v2,     e2_b == e1 =       Just (SubExp e2_a, cs)+  -- x+(-1*y) => x-y+  | Var v2 <- e2,+    Just (BasicOp (BinOp Mul {} (Constant (IntValue x)) e3), cs) <- look v2,+    valueIntegral x == (-1 :: Int) =+      Just (BinOp (Sub it ovf) e1 e3, cs) simplifyBinOp _ _ (BinOp FAdd {} e1 e2)   | isCt0 e1 = resIsSubExp e2   | isCt0 e2 = resIsSubExp e1 simplifyBinOp look _ (BinOp sub@(Sub t _) e1 e2)   | isCt0 e2 = resIsSubExp e1-  -- Cases for simplifying (a+b)-b and permutations.-+  | e1 == e2 = Just (SubExp (intConst t 0), mempty)+  --+  -- Below are cases for simplifying (a+b)-b and permutations.+  --   -- (e1_a+e1_b)-e1_a == e1_b   | Var v1 <- e1,     Just (BasicOp (BinOp Add {} e1_a e1_b), cs) <- look v1,
src/Futhark/Optimise/TileLoops/Shared.hs view
@@ -39,11 +39,7 @@ index :: MonadBuilder m => String -> VName -> [VName] -> m VName index se_desc arr outer_indices = do   arr_t <- lookupType arr-  let shape = arrayShape arr_t-      inner_dims = shapeDims $ stripDims (length outer_indices) shape-      untouched d = DimSlice (intConst Int64 0) d (intConst Int64 1)-      inner_slices = map untouched inner_dims-      slice = Slice $ map (DimFix . Var) outer_indices ++ inner_slices+  let slice = fullSlice arr_t $ map (DimFix . Var) outer_indices   letExp se_desc $ BasicOp $ Index arr slice  update :: MonadBuilder m => String -> VName -> [VName] -> SubExp -> m VName@@ -295,23 +291,23 @@        in (lam_op, ne) changeWithEnv with_env _ = pure with_env -composeIxfuns :: IxFnEnv -> VName -> VName -> (IxFun -> IxFun) -> TileM IxFnEnv+composeIxfuns :: IxFnEnv -> VName -> VName -> (IxFun -> Maybe IxFun) -> TileM IxFnEnv composeIxfuns env y x ixf_fun =-  case M.lookup x env of-    Just ixf -> pure $ M.insert y (ixf_fun ixf) env+  case ixf_fun =<< M.lookup x env of+    Just ixf -> pure $ M.insert y ixf env     Nothing -> do       tp <- lookupType x-      case tp of-        Array _ptp shp _u -> do-          let shp' = map ExpMem.pe64 (shapeDims shp)-          pure $ M.insert y (ixf_fun $ IxFun.iota shp') env-        _ -> pure env+      pure $ case tp of+        Array _ptp shp _u+          | Just ixf <- ixf_fun $ IxFun.iota $ map ExpMem.pe64 (shapeDims shp) ->+              M.insert y ixf env+        _ -> env  changeIxFnEnv :: IxFnEnv -> VName -> Exp GPU -> TileM IxFnEnv changeIxFnEnv env y (BasicOp (Reshape ReshapeArbitrary shp_chg x)) =   composeIxfuns env y x (`IxFun.reshape` fmap ExpMem.pe64 (shapeDims shp_chg)) changeIxFnEnv env y (BasicOp (Reshape ReshapeCoerce shp_chg x)) =-  composeIxfuns env y x (`IxFun.coerce` fmap ExpMem.pe64 (shapeDims shp_chg))+  composeIxfuns env y x (Just . (`IxFun.coerce` fmap ExpMem.pe64 (shapeDims shp_chg))) changeIxFnEnv env y (BasicOp (Manifest perm x)) = do   tp <- lookupType x   case tp of@@ -321,9 +317,9 @@       pure $ M.insert y ixfn env     _ -> error "In TileLoops/Shared.hs, changeIxFnEnv: manifest applied to a non-array!" changeIxFnEnv env y (BasicOp (Rearrange perm x)) =-  composeIxfuns env y x (`IxFun.permute` perm)+  composeIxfuns env y x (Just . (`IxFun.permute` perm)) changeIxFnEnv env y (BasicOp (Index x slc)) =-  composeIxfuns env y x (`IxFun.slice` (Slice $ map (fmap ExpMem.pe64) $ unSlice slc))+  composeIxfuns env y x (Just . (`IxFun.slice` Slice (map (fmap ExpMem.pe64) $ unSlice slc))) changeIxFnEnv env y (BasicOp (Opaque _ (Var x))) =-  composeIxfuns env y x id+  composeIxfuns env y x Just changeIxFnEnv env _ _ = pure env
src/Futhark/Pass/ExpandAllocations.hs view
@@ -30,7 +30,6 @@ import Futhark.Transform.Rename (renameStm) import Futhark.Transform.Substitute import Futhark.Util (mapAccumLM)-import Futhark.Util.IntegralExp import Prelude hiding (quot)  -- | The memory expansion pass definition.@@ -538,28 +537,26 @@    pure (slice_stms' <> stmsFromList alloc_stms, mconcat rebases)   where-    expand (mem, (offset, total_size, space)) = do+    expand (mem, (_offset, total_size, space)) = do       let allocpat = Pat [PatElem mem $ MemMem space]       pure         ( Let allocpat (defAux ()) $ Op $ Alloc total_size space,-          M.singleton mem $ newBase offset+          M.singleton mem newBase         )      num_threads' = pe64 num_threads     gtid = le64 $ segFlat kspace +    untouched d = DimSlice 0 d 1+     -- For the variant allocations, we add an inner dimension,     -- which is then offset by a thread-specific amount.-    newBase size_per_thread (old_shape, pt) =-      let elems_per_thread =-            pe64 size_per_thread `quot` primByteSize pt-          root_ixfun = IxFun.iota [elems_per_thread, num_threads']+    newBase (old_shape, _pt) =+      let root_ixfun = IxFun.iota $ old_shape ++ [num_threads']           offset_ixfun =             IxFun.slice root_ixfun . Slice $-              [DimSlice 0 num_threads' 1, DimFix gtid]-       in if length old_shape == 1-            then IxFun.coerce offset_ixfun old_shape-            else IxFun.reshape offset_ixfun old_shape+              map untouched old_shape ++ [DimFix gtid]+       in offset_ixfun  -- | A map from memory block names to new index function bases. type RebaseMap = M.Map VName (([TPrimExp Int64 VName], PrimType) -> IxFun)@@ -622,11 +619,16 @@ offsetMemoryInStm :: Stm GPUMem -> OffsetM (Scope GPUMem, Stm GPUMem) offsetMemoryInStm (Let pat dec e) = do   e' <- offsetMemoryInExp e-  pat' <- offsetMemoryInPat pat =<< expReturns e'+  pat' <-+    offsetMemoryInPat pat+      =<< maybe (throwError "offsetMemoryInStm: ill-typed") pure+      =<< expReturns e'   scope <- askScope   -- Try to recompute the index function.  Fall back to creating rebase   -- operations with the RebaseMap.-  rts <- runReaderT (expReturns e') scope+  rts <-+    maybe (throwError "offsetMemoryInStm: ill-typed") pure $+      runReader (expReturns e') scope   let pat'' = Pat $ zipWith pick (patElems pat') rts       stm = Let pat'' dec e'   let scope' = scopeOf stm <> scope@@ -659,32 +661,48 @@         pure . PatElem name . MemArray pt shape u . ArrayIn mem $           fmap (fmap unExt) ixfun     onPE pe _ = do-      new_dec <- offsetMemoryInMemBound $ patElemDec pe+      new_dec <- offsetMemoryInMemBound (patElemName pe) $ patElemDec pe       pure pe {patElemDec = new_dec}     unExt (Ext i) = patElemName (pes !! i)     unExt (Free v) = v  offsetMemoryInParam :: Param (MemBound u) -> OffsetM (Param (MemBound u)) offsetMemoryInParam fparam = do-  fparam' <- offsetMemoryInMemBound $ paramDec fparam+  fparam' <- offsetMemoryInMemBound (paramName fparam) $ paramDec fparam   pure fparam {paramDec = fparam'} -offsetMemoryInMemBound :: MemBound u -> OffsetM (MemBound u)-offsetMemoryInMemBound summary@(MemArray pt shape u (ArrayIn mem ixfun)) = do+offsetMemoryInMemBound :: VName -> MemBound u -> OffsetM (MemBound u)+offsetMemoryInMemBound v summary@(MemArray pt shape u (ArrayIn mem ixfun)) = do   new_base <- lookupNewBase mem (IxFun.base ixfun, pt)-  pure . fromMaybe summary $ do-    new_base' <- new_base-    pure $ MemArray pt shape u $ ArrayIn mem $ IxFun.rebase new_base' ixfun-offsetMemoryInMemBound summary = pure summary+  case new_base of+    Nothing -> pure summary+    Just new_base' -> do+      let problem =+            throwError . unlines $+              [ "offsetMemoryInMemBound",+                prettyString v,+                prettyString new_base',+                prettyString ixfun+              ]+      ixfun' <- maybe problem pure $ IxFun.rebase new_base' ixfun+      pure $ MemArray pt shape u $ ArrayIn mem ixfun'+offsetMemoryInMemBound _ summary = pure summary  offsetMemoryInBodyReturns :: BodyReturns -> OffsetM BodyReturns offsetMemoryInBodyReturns br@(MemArray pt shape u (ReturnsInBlock mem ixfun))   | Just ixfun' <- isStaticIxFun ixfun = do       new_base <- lookupNewBase mem (IxFun.base ixfun', pt)-      pure . fromMaybe br $ do-        new_base' <- new_base-        pure . MemArray pt shape u . ReturnsInBlock mem $-          IxFun.rebase (fmap (fmap Free) new_base') ixfun+      case new_base of+        Nothing -> pure br+        Just new_base' -> do+          let problem =+                throwError . unlines $+                  [ "offsetMemoryInBodyReturns",+                    prettyString new_base',+                    prettyString ixfun+                  ]+          ixfun'' <- maybe problem pure $ IxFun.rebase (fmap (fmap Free) new_base') ixfun+          pure $ MemArray pt shape u $ ReturnsInBlock mem ixfun'' offsetMemoryInBodyReturns br = pure br  offsetMemoryInLambda :: Lambda GPUMem -> OffsetM (Lambda GPUMem)
src/Futhark/Pass/ExplicitAllocations.hs view
@@ -43,7 +43,6 @@ import Data.Either (partitionEithers) import Data.Foldable (toList) import Data.List (foldl', transpose, zip4)-import Data.List.NonEmpty qualified as NE import Data.Map.Strict qualified as M import Data.Maybe import Data.Set qualified as S@@ -186,6 +185,40 @@ allocForArray t space = do   allocForArray' t space +-- | Repair an expression that cannot be assigned an index function.+-- There is a simple remedy for this: normalise the input arrays and+-- try again.+repairExpression ::+  (Allocable fromrep torep inner) =>+  Exp torep ->+  AllocM fromrep torep (Exp torep)+repairExpression (BasicOp (Reshape k shape v)) = do+  v_mem <- fst <$> lookupArraySummary v+  space <- lookupMemSpace v_mem+  v' <- snd <$> ensureDirectArray (Just space) v+  pure $ BasicOp $ Reshape k shape v'+repairExpression e =+  error $ "repairExpression:\n" <> prettyString e++expReturns' ::+  (Allocable fromrep torep inner) =>+  Exp torep ->+  AllocM fromrep torep ([ExpReturns], Exp torep)+expReturns' e = do+  maybe_rts <- expReturns e+  case maybe_rts of+    Just rts -> pure (rts, e)+    Nothing -> do+      e' <- repairExpression e+      let bad =+            error . unlines $+              [ "expReturns': impossible index transformation",+                prettyString e,+                prettyString e'+              ]+      rts <- fromMaybe bad <$> expReturns e'+      pure (rts, e')+ allocsForStm ::   (Allocable fromrep torep inner) =>   [Ident] ->@@ -194,10 +227,10 @@ allocsForStm idents e = do   def_space <- askDefaultSpace   hints <- expHints e-  rts <- expReturns e+  (rts, e') <- expReturns' e   pes <- allocsForPat def_space idents rts hints-  dec <- mkExpDecM (Pat pes) e-  pure $ Let (Pat pes) (defAux dec) e+  dec <- mkExpDecM (Pat pes) e'+  pure $ Let (Pat pes) (defAux dec) e'  patWithAllocations ::   (MonadBuilder m, Mem (Rep m) inner) =>@@ -209,7 +242,7 @@ patWithAllocations def_space names e hints = do   ts' <- instantiateShapes' names <$> expExtType e   let idents = zipWith Ident names ts'-  rts <- expReturns e+  rts <- fromMaybe (error "patWithAllocations: ill-typed") <$> expReturns e   Pat <$> allocsForPat def_space idents rts hints  mkMissingIdents :: MonadFreshNames m => [Ident] -> [ExpReturns] -> m [Ident]@@ -344,11 +377,9 @@   mem_space <- lookupMemSpace mem   default_space <- askDefaultSpace   let space = fromMaybe default_space space_ok-  if numLMADs ixfun == 1-    && ixFunPerm ixfun == [0 .. IxFun.rank ixfun - 1]+  if IxFun.permutation ixfun == [0 .. IxFun.rank ixfun - 1]     && length (IxFun.base ixfun) == IxFun.rank ixfun     && maybe True (== mem_space) space_ok-    && IxFun.contiguous ixfun     then pure (mem, v)     else allocLinearArray space (baseString v) v @@ -527,6 +558,22 @@     _ ->       error $ "allocPermArray: " ++ prettyString t +ensurePermArray ::+  (Allocable fromrep torep inner) =>+  Maybe Space ->+  [Int] ->+  VName ->+  AllocM fromrep torep (VName, VName)+ensurePermArray space_ok perm v = do+  (mem, ixfun) <- lookupArraySummary v+  mem_space <- lookupMemSpace mem+  default_space <- askDefaultSpace+  if length (IxFun.base ixfun) == length (IxFun.shape ixfun)+    && IxFun.permutation ixfun == perm+    && maybe True (== mem_space) space_ok+    then pure (mem, v)+    else allocPermArray (fromMaybe default_space space_ok) perm (baseString v) v+ allocLinearArray ::   (Allocable fromrep torep inner) =>   Space ->@@ -710,25 +757,16 @@ allocInLambda params body =   mkLambda params . allocInStms (bodyStms body) $ pure $ bodyResult body -numLMADs :: IxFun -> Int-numLMADs = length . IxFun.ixfunLMADs--ixFunPerm :: IxFun -> [Int]-ixFunPerm = map IxFun.ldPerm . IxFun.lmadDims . NE.head . IxFun.ixfunLMADs--ixFunMon :: IxFun -> [IxFun.Monotonicity]-ixFunMon = map IxFun.ldMon . IxFun.lmadDims . NE.head . IxFun.ixfunLMADs- data MemReq-  = MemReq Space [Int] [IxFun.Monotonicity] Rank Bool-  | NeedsLinearisation Space+  = MemReq Space [Int] Rank+  | NeedsNormalisation Space   deriving (Eq, Show)  combMemReqs :: MemReq -> MemReq -> MemReq-combMemReqs x@NeedsLinearisation {} _ = x-combMemReqs _ y@NeedsLinearisation {} = y-combMemReqs x@(MemReq x_space _ _ _ _) y@MemReq {} =-  if x == y then x else NeedsLinearisation x_space+combMemReqs x@NeedsNormalisation {} _ = x+combMemReqs _ y@NeedsNormalisation {} = y+combMemReqs x@(MemReq x_space _ _) y@MemReq {} =+  if x == y then x else NeedsNormalisation x_space  type MemReqType = MemInfo (Ext SubExp) NoUniqueness MemReq @@ -738,13 +776,13 @@ combMemReqTypes x _ = x  contextRets :: MemReqType -> [MemInfo d u r]-contextRets (MemArray _ shape _ (MemReq space _ _ (Rank base_rank) _)) =+contextRets (MemArray _ shape _ (MemReq space _ (Rank base_rank))) =   -- Memory + offset + base_rank + (stride,size)*rank.   MemMem space     : MemPrim int64     : replicate base_rank (MemPrim int64)     ++ replicate (2 * shapeRank shape) (MemPrim int64)-contextRets (MemArray _ shape _ (NeedsLinearisation space)) =+contextRets (MemArray _ shape _ (NeedsNormalisation space)) =   -- Memory + offset + (base,stride,size)*rank.   MemMem space     : MemPrim int64@@ -771,15 +809,10 @@         (Array pt shape u, MemArray _ _ _ (ArrayIn mem ixfun)) -> do           space <- lookupMemSpace mem           pure . MemArray pt shape u $-            if numLMADs ixfun == 1-              then-                MemReq-                  space-                  (ixFunPerm ixfun)-                  (ixFunMon ixfun)-                  (Rank $ length $ IxFun.base ixfun)-                  (IxFun.contiguous ixfun)-              else NeedsLinearisation space+            MemReq+              space+              (IxFun.permutation ixfun)+              (Rank $ length $ IxFun.base ixfun)         (_, MemMem space) -> pure $ MemMem space         (_, MemPrim pt) -> pure $ MemPrim pt         (_, MemAcc acc ispace ts u) -> pure $ MemAcc acc ispace ts u@@ -800,17 +833,16 @@         res_rets_acc ++ [inspect ctx_offset req]       ) -    arrayInfo rank (NeedsLinearisation space) =-      (space, [0 .. rank - 1], repeat IxFun.Inc, rank, True)-    arrayInfo _ (MemReq space perm mon (Rank base_rank) contig) =-      (space, perm, mon, base_rank, contig)+    arrayInfo rank (NeedsNormalisation space) =+      (space, [0 .. rank - 1], rank)+    arrayInfo _ (MemReq space perm (Rank base_rank)) =+      (space, perm, base_rank)      inspect ctx_offset (MemArray pt shape u req) =       let shape' = fmap (adjustExt num_new_ctx) shape-          (space, perm, mon, base_rank, contig) = arrayInfo (shapeRank shape) req+          (space, perm, base_rank) = arrayInfo (shapeRank shape) req        in MemArray pt shape' u . ReturnsNewBlock space ctx_offset $-            convert-              <$> IxFun.mkExistential base_rank (zip perm mon) contig (ctx_offset + 1)+            convert <$> IxFun.mkExistential base_rank perm (ctx_offset + 1)     inspect _ (MemAcc acc ispace ts u) = MemAcc acc ispace ts u     inspect _ (MemPrim pt) = MemPrim pt     inspect _ (MemMem space) = MemMem space@@ -828,13 +860,14 @@   Body torep ->   AllocM fromrep torep (Body torep) addCtxToMatchBody reqs body = buildBody_ $ do-  res <- zipWithM linearIfNeeded reqs =<< bodyBind body+  res <- zipWithM normaliseIfNeeded reqs =<< bodyBind body   ctx <- concat <$> mapM resCtx res   pure $ ctx ++ res   where-    linearIfNeeded (MemArray _ _ _ (NeedsLinearisation space)) (SubExpRes cs (Var v)) =-      SubExpRes cs . Var . snd <$> ensureRowMajorArray (Just space) v-    linearIfNeeded _ res =+    normaliseIfNeeded (MemArray _ shape _ (NeedsNormalisation space)) (SubExpRes cs (Var v)) =+      SubExpRes cs . Var . snd+        <$> ensurePermArray (Just space) [0 .. shapeRank shape - 1] v+    normaliseIfNeeded _ res =       pure res      resCtx (SubExpRes _ Constant {}) =@@ -1136,7 +1169,7 @@       innerUsage inner      simplifyPat (Pat pes) e = do-      rets <- expReturns e+      rets <- fromMaybe (error "simplifyPat: ill-typed") <$> expReturns e       Pat <$> zipWithM update pes rets       where         names = map patElemName pes
src/Futhark/Passes.hs view
@@ -1,12 +1,12 @@ -- | Optimisation pipelines. module Futhark.Passes   ( standardPipeline,-    sequentialPipeline,-    kernelsPipeline,-    sequentialCpuPipeline,+    seqPipeline,     gpuPipeline,+    seqmemPipeline,+    gpumemPipeline,     mcPipeline,-    multicorePipeline,+    mcmemPipeline,   ) where @@ -82,8 +82,8 @@  -- | The pipeline used by the CUDA and OpenCL backends, but before -- adding memory information.  Includes 'standardPipeline'.-kernelsPipeline :: Pipeline SOACS GPU-kernelsPipeline =+gpuPipeline :: Pipeline SOACS GPU+gpuPipeline =   standardPipeline     >>> onePass extractKernels     >>> passes@@ -110,8 +110,8 @@  -- | The pipeline used by the sequential backends.  Turns all -- parallelism into sequential loops.  Includes 'standardPipeline'.-sequentialPipeline :: Pipeline SOACS Seq-sequentialPipeline =+seqPipeline :: Pipeline SOACS Seq+seqPipeline =   standardPipeline     >>> onePass firstOrderTransform     >>> passes@@ -119,11 +119,11 @@         inPlaceLoweringSeq       ] --- | Run 'sequentialPipeline', then add memory information (and+-- | Run 'seqPipeline', then add memory information (and -- optimise it slightly).-sequentialCpuPipeline :: Pipeline SOACS SeqMem-sequentialCpuPipeline =-  sequentialPipeline+seqmemPipeline :: Pipeline SOACS SeqMem+seqmemPipeline =+  seqPipeline     >>> onePass Seq.explicitAllocations     >>> passes       [ performCSE False,@@ -140,11 +140,11 @@         simplifySeqMem       ] --- | Run 'kernelsPipeline', then add memory information (and optimise+-- | Run 'gpuPipeline', then add memory information (and optimise -- it a lot).-gpuPipeline :: Pipeline SOACS GPUMem-gpuPipeline =-  kernelsPipeline+gpumemPipeline :: Pipeline SOACS GPUMem+gpumemPipeline =+  gpuPipeline     >>> onePass GPU.explicitAllocations     >>> passes       [ simplifyGPUMem,@@ -185,8 +185,8 @@       ]  -- | Run 'mcPipeline' and then add memory information.-multicorePipeline :: Pipeline SOACS MCMem-multicorePipeline =+mcmemPipeline :: Pipeline SOACS MCMem+mcmemPipeline =   mcPipeline     >>> onePass MC.explicitAllocations     >>> passes
src/Futhark/Util/Pretty.hs view
@@ -46,7 +46,7 @@ import Data.Text qualified as T import Numeric.Half import Prettyprinter-import Prettyprinter.Render.Terminal (AnsiStyle, Color (..), bgColor, bgColorDull, bold, color, colorDull)+import Prettyprinter.Render.Terminal (AnsiStyle, Color (..), bgColor, bgColorDull, bold, color, colorDull, italicized, underlined) import Prettyprinter.Render.Terminal qualified import Prettyprinter.Render.Text qualified import Prettyprinter.Symbols.Ascii
src/Language/Futhark/Parser.hs view
@@ -5,7 +5,7 @@     parseExp,     parseModExp,     parseType,-    parseDecOrExpIncrM,+    parseDecOrExp,     SyntaxError (..),     Comment (..),   )@@ -57,29 +57,13 @@   Either SyntaxError UncheckedTypeExp parseType = parse futharkType --- | Parse an Futhark expression incrementally from monadic actions, using the--- 'FilePath' as the source name for error messages.-parseExpIncrM ::-  Monad m =>-  m T.Text ->-  FilePath ->-  T.Text ->-  m (Either SyntaxError UncheckedExp)-parseExpIncrM fetch file program =-  getLinesFromM fetch $ fmap fst <$> parseInMonad expression file program---- | Parse either an expression or a declaration incrementally;--- favouring declarations in case of ambiguity.-parseDecOrExpIncrM ::-  Monad m =>-  m T.Text ->+-- | Parse either an expression or a declaration; favouring+-- declarations in case of ambiguity.+parseDecOrExp ::   FilePath ->   T.Text ->-  m (Either SyntaxError (Either UncheckedDec UncheckedExp))-parseDecOrExpIncrM fetch file input =-  case parseInMonad declaration file input of-    Value Left {} -> fmap Right <$> parseExpIncrM fetch file input-    Value (Right (d, _)) -> pure $ Right $ Left d-    GetLine _ -> do-      l <- fetch-      parseDecOrExpIncrM fetch file $ input <> "\n" <> l+  Either SyntaxError (Either UncheckedDec UncheckedExp)+parseDecOrExp file input =+  case parse declaration file input of+    Left {} -> Right <$> parseExp file input+    Right d -> Right $ Left d
src/Language/Futhark/Parser/Lexer.x view
@@ -3,7 +3,7 @@ -- | The Futhark lexer.  Takes a string, produces a list of tokens with position information. module Language.Futhark.Parser.Lexer   ( Token(..)-  , scanTokens+  , getToken   , scanTokensText   ) where @@ -12,7 +12,7 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.Read as T-import Data.Char (ord, toLower, digitToInt)+import Data.Char (chr, ord, toLower) import Data.Int (Int8, Int16, Int32, Int64) import Data.Word (Word8) import Data.Loc (Loc (..), L(..), Pos(..))@@ -20,7 +20,7 @@  import Language.Futhark.Core (Int8, Int16, Int32, Int64,                               Word8, Word16, Word32, Word64,-                              Name, nameFromText, nameToText)+                              Name, nameFromText, nameToText, nameFromString) import Language.Futhark.Prop (leadingOperator) import Language.Futhark.Syntax (BinOp(..)) import Language.Futhark.Parser.Lexer.Wrapper@@ -34,7 +34,6 @@ @declit = [0-9][0-9_]* @binlit = 0[bB][01][01_]* @romlit = 0[rR][IVXLCDM][IVXLCDM_]*-@intlit = @hexlit|@binlit|@declit|@romlit @reallit = (([0-9][0-9_]*("."[0-9][0-9_]*)?))([eE][\+\-]?[0-9]+)? @hexreallit = 0[xX][0-9a-fA-F][0-9a-fA-F_]*"."[0-9a-fA-F][0-9a-fA-F_]*([pP][\+\-]?[0-9_]+) @@ -54,7 +53,7 @@ tokens :-    $white+                               ;-  @doc                     { tokenM $ pure . DOC . T.intercalate "\n" .+  @doc                     { tokenS $ DOC . T.intercalate "\n" .                                       map (T.drop 3 . T.stripStart) .                                            T.split (== '\n') . ("--"<>) .                                            T.drop 4 }@@ -91,62 +90,123 @@   "$"                      { tokenC DOLLAR }   "???"                    { tokenC HOLE } -  @declit                  { tokenS $ \s -> NATLIT (nameFromText s) (readIntegral s) }-  @intlit i8               { tokenM $ pure . I8LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='i') }-  @intlit i16              { tokenM $ pure . I16LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='i') }-  @intlit i32              { tokenM $ pure . I32LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='i') }-  @intlit i64              { tokenM $ pure . I64LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='i') }-  @intlit u8               { tokenM $ pure . U8LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='u') }-  @intlit u16              { tokenM $ pure . U16LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='u') }-  @intlit u32              { tokenM $ pure . U32LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='u') }-  @intlit u64              { tokenM $ pure . U64LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='u') }-  @intlit                  { tokenM $ pure . INTLIT . readIntegral . T.filter (/= '_') }+  @declit                  { \s -> decToken (NATLIT (nameFromBS s)) s } -  [\n[^\.]] ^ @reallit f16     { tokenM $ fmap F16LIT . tryRead "f16" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }-  [\n[^\.]] ^ @reallit f32     { tokenM $ fmap F32LIT . tryRead "f32" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }-  [\n[^\.]] ^ @reallit f64     { tokenM $ fmap F64LIT . tryRead "f64" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }-  [\n[^\.]] ^ @reallit         { tokenM $ fmap FLOATLIT . tryRead "f64" . suffZero . T.filter (/= '_') }-  @hexreallit f16          { tokenM $ fmap F16LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 }-  @hexreallit f32          { tokenM $ fmap F32LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 }-  @hexreallit f64          { tokenM $ fmap F64LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 }-  @hexreallit              { tokenM $ fmap FLOATLIT . readHexRealLit . T.filter (/= '_') }-  "'" @charlit "'"         { tokenM $ fmap CHARLIT . tryRead "char" }-  \" @stringcharlit* \"    { tokenM $ fmap (STRINGLIT . T.pack) . tryRead "string"  }+  @declit i8               { decToken I8LIT . BS.dropEnd 2 }+  @binlit i8               { binToken I8LIT . BS.drop 2 . BS.dropEnd 2 }+  @hexlit i8               { hexToken I8LIT . BS.drop 2 . BS.dropEnd 2 }+  @romlit i8               { romToken I8LIT . BS.drop 2 . BS.dropEnd 2 } -  @identifier              { tokenS keyword }+  @declit i16              { decToken I16LIT . BS.dropEnd 3 }+  @binlit i16              { binToken I16LIT . BS.drop 2 . BS.dropEnd 3 }+  @hexlit i16              { hexToken I16LIT . BS.drop 2 . BS.dropEnd 3 }+  @romlit i16              { romToken I16LIT . BS.drop 2 . BS.dropEnd 3 }++  @declit i32              { decToken I32LIT . BS.dropEnd 3 }+  @binlit i32              { binToken I32LIT . BS.drop 2 . BS.dropEnd 3 }+  @hexlit i32              { hexToken I32LIT . BS.drop 2 . BS.dropEnd 3 }+  @romlit i32              { romToken I32LIT . BS.drop 2 . BS.dropEnd 3 }++  @declit i64              { decToken I64LIT . BS.dropEnd 3 }+  @binlit i64              { binToken I64LIT . BS.drop 2 . BS.dropEnd 3 }+  @hexlit i64              { hexToken I64LIT . BS.drop 2 . BS.dropEnd 3 }+  @romlit i64              { romToken I64LIT . BS.drop 2 . BS.dropEnd 3 }++  @declit u8               { decToken U8LIT . BS.dropEnd 2 }+  @binlit u8               { binToken U8LIT . BS.drop 2 . BS.dropEnd 2 }+  @hexlit u8               { hexToken U8LIT . BS.drop 2 . BS.dropEnd 2 }+  @romlit u8               { romToken U8LIT . BS.drop 2 . BS.dropEnd 2 }++  @declit u16              { decToken U16LIT . BS.dropEnd 3 }+  @binlit u16              { binToken U16LIT . BS.drop 2 . BS.dropEnd 3 }+  @hexlit u16              { hexToken U16LIT . BS.drop 2 . BS.dropEnd 3 }+  @romlit u16              { romToken U16LIT . BS.drop 2 . BS.dropEnd 3 }++  @declit u32              { decToken U32LIT . BS.dropEnd 3 }+  @binlit u32              { binToken U32LIT . BS.drop 2 . BS.dropEnd 3 }+  @hexlit u32              { hexToken U32LIT . BS.drop 2 . BS.dropEnd 3 }+  @romlit u32              { romToken U32LIT . BS.drop 2 . BS.dropEnd 3 }++  @declit u64              { decToken U64LIT . BS.dropEnd 3 }+  @binlit u64              { binToken U64LIT . BS.drop 2 . BS.dropEnd 3 }+  @hexlit u64              { hexToken U64LIT . BS.drop 2 . BS.dropEnd 3 }+  @romlit u64              { romToken U64LIT . BS.drop 2 . BS.dropEnd 3 }++  @declit                  { decToken INTLIT }+  @binlit                  { binToken INTLIT . BS.drop 2 }+  @hexlit                  { hexToken INTLIT . BS.drop 2 }+  @romlit                  { romToken INTLIT . BS.drop 2 }++  [\n[^\.]] ^ @reallit f16 { tokenS $ F16LIT . tryRead "f16" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }+  [\n[^\.]] ^ @reallit f32 { tokenS $ F32LIT . tryRead "f32" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }+  [\n[^\.]] ^ @reallit f64 { tokenS $ F64LIT . tryRead "f64" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }+  [\n[^\.]] ^ @reallit     { tokenS $ FLOATLIT . tryRead "f64" . suffZero . T.filter (/= '_') }+  @hexreallit f16          { tokenS $ F16LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 }+  @hexreallit f32          { tokenS $ F32LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 }+  @hexreallit f64          { tokenS $ F64LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 }+  @hexreallit              { tokenS $ FLOATLIT . readHexRealLit . T.filter (/= '_') }+  "'" @charlit "'"         { tokenS $ CHARLIT . tryRead "char" }+  \" @stringcharlit* \"    { tokenS $ STRINGLIT . T.pack . tryRead "string"  }++  "true"                   { tokenC TRUE }+  "false"                  { tokenC FALSE }+  "if"                     { tokenC IF }+  "then"                   { tokenC THEN }+  "else"                   { tokenC ELSE }+  "def"                    { tokenC DEF }+  "let"                    { tokenC LET }+  "loop"                   { tokenC LOOP }+  "in"                     { tokenC IN }+  "val"                    { tokenC VAL }+  "for"                    { tokenC FOR }+  "do"                     { tokenC DO }+  "with"                   { tokenC WITH }+  "local"                  { tokenC LOCAL }+  "open"                   { tokenC OPEN }+  "include"                { tokenC INCLUDE }+  "import"                 { tokenC IMPORT }+  "type"                   { tokenC TYPE }+  "entry"                  { tokenC ENTRY }+  "module"                 { tokenC MODULE }+  "while"                  { tokenC WHILE }+  "assert"                 { tokenC ASSERT }+  "match"                  { tokenC MATCH }+  "case"                   { tokenC CASE }++  @identifier              { tokenS $ ID . nameFromText }+   "#" @identifier          { tokenS $ CONSTRUCTOR . nameFromText . T.drop 1 } -  @binop                   { tokenM $ pure . symbol [] . nameFromText }-  @qualbinop               { tokenM $ \s -> do (qs,k) <- mkQualId s; pure (symbol qs k) }+  @binop                   { tokenS $ symbol [] . nameFromText }+  @qualbinop               { tokenS $ uncurry symbol . mkQualId } { -getToken :: Alex (Lexeme Token)-getToken = do-  inp@(_,_,_,n) <- alexGetInput-  sc <- alexGetStartCode-  case alexScan inp sc of-    AlexEOF -> do pos <- alexGetPos-                  pure (pos, pos, EOF)+nameFromBS :: BS.ByteString -> Name+nameFromBS = nameFromString . map (chr . fromIntegral) . BS.unpack++getToken :: AlexInput -> Either LexerError (AlexInput, (Pos, Pos, Token))+getToken state@(pos,c,s,n) =+  case alexScan state 0 of+    AlexEOF -> Right (state, (pos, pos, EOF))     AlexError (pos,_,_,_) ->-      alexError (Loc pos pos) "Invalid lexical syntax."-    AlexSkip  inp' _len -> do-      alexSetInput inp'-      getToken-    AlexToken inp'@(_,_,_,n') _ action -> let len = n'-n in do-      alexSetInput inp'-      action inp len+      Left $ LexerError (Loc pos pos) "Invalid lexical syntax."+    AlexSkip state' _len ->+      getToken state'+    AlexToken state'@(pos',_,_,n') _ action -> do+      let x = action (BS.take (n'-n) s)+      x `seq` Right (state', (pos, pos', x))  scanTokens :: Pos -> BS.ByteString -> Either LexerError ([L Token], Pos)-scanTokens pos str =-  runAlex pos str $ do-  fix $ \loop -> do-    tok <- getToken-    case tok of-      (start, end, EOF) ->-        pure ([], end)-      (start, end, t) -> do-        (rest, endpos) <- loop-        pure (L (Loc start end) t : rest, endpos)+scanTokens pos str = loop $ initialLexerState pos str+  where+   loop s = do+     (s', tok) <- getToken s+     case tok of+       (start, end, EOF) ->+         pure ([], end)+       (start, end, t) -> do+         (rest, endpos) <- loop s'+         pure (L (Loc start end) t : rest, endpos)  -- | Given a starting position, produce tokens from the given text (or -- a lexer error).  Returns the final position.
src/Language/Futhark/Parser/Lexer/Tokens.hs view
@@ -5,28 +5,27 @@ -- Also defines other useful building blocks for constructing tokens. module Language.Futhark.Parser.Lexer.Tokens   ( Token (..),-    Lexeme,     fromRoman,     symbol,     mkQualId,-    tokenPosM,-    tokenM,     tokenC,-    keyword,     tokenS,-    indexing,     suffZero,     tryRead,-    readIntegral,+    decToken,+    binToken,+    hexToken,+    romToken,+    advance,     readHexRealLit,   ) where  import Data.ByteString.Lazy qualified as BS-import Data.Char (digitToInt, ord)+import Data.Char (ord) import Data.Either-import Data.List (find, foldl')-import Data.Loc (Loc (..), Pos (..))+import Data.List (find)+import Data.Loc (Pos (..)) import Data.Text qualified as T import Data.Text.Encoding qualified as T import Data.Text.Read qualified as T@@ -41,7 +40,6 @@     Word64,     Word8,   )-import Language.Futhark.Parser.Lexer.Wrapper import Language.Futhark.Prop (leadingOperator) import Language.Futhark.Syntax (BinOp, nameFromText, nameToText) import Numeric.Half@@ -133,94 +131,68 @@   | HOLE   deriving (Show, Eq, Ord) -keyword :: T.Text -> Token-keyword s =-  case s of-    "true" -> TRUE-    "false" -> FALSE-    "if" -> IF-    "then" -> THEN-    "else" -> ELSE-    "def" -> DEF-    "let" -> LET-    "loop" -> LOOP-    "in" -> IN-    "val" -> VAL-    "for" -> FOR-    "do" -> DO-    "with" -> WITH-    "local" -> LOCAL-    "open" -> OPEN-    "include" -> INCLUDE-    "import" -> IMPORT-    "type" -> TYPE-    "entry" -> ENTRY-    "module" -> MODULE-    "while" -> WHILE-    "assert" -> ASSERT-    "match" -> MATCH-    "case" -> CASE-    _ -> ID $ nameFromText s--indexing :: (Loc, T.Text) -> Alex Name-indexing (loc, s) = case keyword s of-  ID v -> pure v-  _ -> alexError loc $ "Cannot index keyword '" <> s <> "'."--mkQualId :: T.Text -> Alex ([Name], Name)+mkQualId :: T.Text -> ([Name], Name) mkQualId s = case reverse $ T.splitOn "." s of   [] -> error "mkQualId: no components"-  k : qs -> pure (map nameFromText (reverse qs), nameFromText k)+  k : qs -> (map nameFromText (reverse qs), nameFromText k)  -- | Suffix a zero if the last character is dot. suffZero :: T.Text -> T.Text suffZero s = if T.last s == '.' then s <> "0" else s -tryRead :: Read a => String -> T.Text -> Alex a+tryRead :: Read a => String -> T.Text -> a tryRead desc s = case reads s' of-  [(x, "")] -> pure x+  [(x, "")] -> x   _ -> error $ "Invalid " ++ desc ++ " literal: `" ++ T.unpack s ++ "'."   where     s' = T.unpack s -readIntegral :: Integral a => T.Text -> a-readIntegral s-  | "0x" `T.isPrefixOf` s || "0X" `T.isPrefixOf` s = parseBase 16 (T.drop 2 s)-  | "0b" `T.isPrefixOf` s || "0B" `T.isPrefixOf` s = parseBase 2 (T.drop 2 s)-  | "0r" `T.isPrefixOf` s || "0R" `T.isPrefixOf` s = fromRoman (T.drop 2 s)-  | otherwise = parseBase 10 s-  where-    parseBase base = T.foldl (\acc c -> acc * base + fromIntegral (digitToInt c)) 0+{-# INLINE tokenC #-}+tokenC :: a -> BS.ByteString -> a+tokenC v _ = v -tokenC :: a -> (Pos, Char, BS.ByteString, Int64) -> Int64 -> Alex (Lexeme a)-tokenC v = tokenS $ const v+{-# INLINE decToken #-}+decToken :: Integral a => (a -> Token) -> BS.ByteString -> Token+decToken f = f . BS.foldl' digit 0+  where+    digit x c =+      if c >= 48 && c <= 57+        then x * 10 + fromIntegral (c - 48)+        else x -tokenS :: (T.Text -> a) -> (Pos, Char, BS.ByteString, Int64) -> Int64 -> Alex (Lexeme a)-tokenS f = tokenM $ pure . f+{-# INLINE binToken #-}+binToken :: Integral a => (a -> Token) -> BS.ByteString -> Token+binToken f = f . BS.foldl' digit 0+  where+    digit x c =+      if c >= 48 && c <= 49+        then x * 2 + fromIntegral (c - 48)+        else x -type Lexeme a = (Pos, Pos, a)+{-# INLINE hexToken #-}+hexToken :: Integral a => (a -> Token) -> BS.ByteString -> Token+hexToken f = f . BS.foldl' digit 0+  where+    digit x c+      | c >= 48 && c <= 57 =+          x * 16 + fromIntegral (c - 48)+      | c >= 65 && c <= 70 =+          x * 16 + fromIntegral (10 + c - 65)+      | c >= 97 && c <= 102 =+          x * 16 + fromIntegral (10 + c - 97)+      | otherwise =+          x -tokenM ::-  (T.Text -> Alex a) ->-  (Pos, Char, BS.ByteString, Int64) ->-  Int64 ->-  Alex (Lexeme a)-tokenM f = tokenPosM (f . snd)+{-# INLINE romToken #-}+romToken :: Integral a => (a -> Token) -> BS.ByteString -> Token+romToken f = tokenS $ f . fromRoman -tokenPosM ::-  ((Loc, T.Text) -> Alex a) ->-  (Pos, Char, BS.ByteString, Int64) ->-  Int64 ->-  Alex (Lexeme a)-tokenPosM f (pos, _, s, _) len = do-  x <- f (Loc pos pos', T.decodeUtf8 $ BS.toStrict s')-  pure (pos, pos', x)-  where-    pos' = advance pos s'-    s' = BS.take len s+{-# INLINE tokenS #-}+tokenS :: (T.Text -> a) -> BS.ByteString -> a+tokenS f = f . T.decodeUtf8 . BS.toStrict  advance :: Pos -> BS.ByteString -> Pos-advance orig_pos = foldl' advance' orig_pos . init . BS.unpack+advance orig_pos = BS.foldl' advance' orig_pos . BS.init   where     advance' (Pos f !line !col !addr) c       | c == nl = Pos f (line + 1) 1 (addr + 1)@@ -261,7 +233,7 @@     Nothing -> 0     Just (d, n) -> n + fromRoman (T.drop (T.length d) s) -readHexRealLit :: RealFloat a => T.Text -> Alex a+readHexRealLit :: RealFloat a => T.Text -> a readHexRealLit s =   let num = T.drop 2 s    in -- extract number into integer, fractional and (optional) exponent@@ -276,5 +248,5 @@                   fracLen = fromIntegral $ T.length f                   fracVal = fracPart / (16.0 ** fracLen)                   totalVal = (intPart + fracVal) * (2.0 ** exponent)-               in pure totalVal+               in totalVal             _ -> error "bad hex real literal"
src/Language/Futhark/Parser/Lexer/Wrapper.hs view
@@ -1,27 +1,18 @@ {-# OPTIONS_GHC -funbox-strict-fields #-}  -- | Utility definitions used by the lexer.  None of the default Alex--- "wrappers" are precisely what we need.  The code here is based on--- the "monad-bytestring" wrapper.  The code here is completely--- Futhark-agnostic, and perhaps it can even serve as inspiration for--- other Alex lexer wrappers.+-- "wrappers" are precisely what we need.  The code here is highly+-- minimalistic.  Lexers should not be complicated! module Language.Futhark.Parser.Lexer.Wrapper-  ( runAlex,-    Alex,+  ( initialLexerState,     AlexInput,     alexInputPrevChar,-    Byte,     LexerError (..),-    alexSetInput,-    alexGetInput,     alexGetByte,-    alexGetStartCode,-    alexError,     alexGetPos,   ) where -import Control.Applicative (liftA) import Data.ByteString.Internal qualified as BS (w2c) import Data.ByteString.Lazy qualified as BS import Data.Int (Int64)@@ -61,6 +52,9 @@           n' = n + 1        in p' `seq` cs' `seq` n' `seq` Just (b, (p', c, cs', n')) +alexGetPos :: AlexInput -> Pos+alexGetPos (pos, _, _, _) = pos+ tabSize :: Int tabSize = 8 @@ -70,71 +64,11 @@ alexMove (Pos !f !l _ !a) '\n' = Pos f (l + 1) 1 (a + 1) alexMove (Pos !f !l !c !a) _ = Pos f l (c + 1) (a + 1) -data AlexState = AlexState-  { alex_pos :: !Pos, -- position at current input location-    alex_bpos :: !Int64, -- bytes consumed so far-    alex_inp :: BS.ByteString, -- the current input-    alex_chr :: !Char, -- the character before the input-    alex_scd :: !Int -- the current startcode-  }--runAlex :: Pos -> BS.ByteString -> Alex a -> Either LexerError a-runAlex start_pos input (Alex f) =-  case f-    ( AlexState-        { alex_pos = start_pos,-          alex_bpos = 0,-          alex_inp = input,-          alex_chr = '\n',-          alex_scd = 0-        }-    ) of-    Left msg -> Left msg-    Right (_, a) -> Right a--newtype Alex a = Alex {unAlex :: AlexState -> Either LexerError (AlexState, a)}+initialLexerState :: Pos -> BS.ByteString -> AlexInput+initialLexerState start_pos input =+  (start_pos, '\n', input, 0)  data LexerError = LexerError Loc T.Text  instance Show LexerError where   show (LexerError _ s) = T.unpack s--instance Functor Alex where-  fmap = liftA--instance Applicative Alex where-  pure a = Alex $ \s -> Right (s, a)-  fa <*> a = Alex $ \s -> case unAlex fa s of-    Left msg -> Left msg-    Right (s', f) -> case unAlex a s' of-      Left msg -> Left msg-      Right (s'', b) -> Right (s'', f b)--instance Monad Alex where-  m >>= k = Alex $ \s -> case unAlex m s of-    Left msg -> Left msg-    Right (s', a) -> unAlex (k a) s'--alexGetInput :: Alex AlexInput-alexGetInput =-  Alex $ \s@AlexState {alex_pos = pos, alex_bpos = bpos, alex_chr = c, alex_inp = inp} ->-    Right (s, (pos, c, inp, bpos))--alexSetInput :: AlexInput -> Alex ()-alexSetInput (pos, c, inp, bpos) =-  Alex $ \s -> case s-    { alex_pos = pos,-      alex_bpos = bpos,-      alex_chr = c,-      alex_inp = inp-    } of-    state@AlexState {} -> Right (state, ())--alexError :: Loc -> T.Text -> Alex a-alexError loc message = Alex $ const $ Left $ LexerError loc message--alexGetStartCode :: Alex Int-alexGetStartCode = Alex $ \s@AlexState {alex_scd = sc} -> Right (s, sc)--alexGetPos :: Alex Pos-alexGetPos = Alex $ \s -> Right (s, alex_pos s)
src/Language/Futhark/Parser/Monad.hs view
@@ -6,12 +6,9 @@ module Language.Futhark.Parser.Monad   ( ParserMonad,     ParserState,-    ReadLineMonad (..),     Comment (..),-    parseInMonad,     parse,     parseWithComments,-    getLinesFromM,     lexer,     mustBeEmpty,     arrayFromList,@@ -38,19 +35,20 @@   ) where -import Control.Applicative (liftA) import Control.Monad import Control.Monad.Except (ExceptT, MonadError (..), runExceptT) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.State import Data.Array hiding (index)+import Data.ByteString.Lazy qualified as BS import Data.List.NonEmpty qualified as NE import Data.Monoid import Data.Text qualified as T+import Data.Text.Encoding qualified as T import Futhark.Util.Loc import Futhark.Util.Pretty hiding (line, line') import Language.Futhark.Parser.Lexer-import Language.Futhark.Parser.Lexer.Wrapper (LexerError (..))+import Language.Futhark.Parser.Lexer.Wrapper (AlexInput, LexerError (..), initialLexerState) import Language.Futhark.Pretty () import Language.Futhark.Prop import Language.Futhark.Syntax@@ -105,38 +103,10 @@     parserInput :: T.Text,     -- | Note: reverse order.     parserComments :: [Comment],-    parserLexical :: ([L Token], Pos)+    parserLexerState :: AlexInput   } -type ParserMonad = ExceptT SyntaxError (StateT ParserState ReadLineMonad)--data ReadLineMonad a-  = Value a-  | GetLine (Maybe T.Text -> ReadLineMonad a)--readLineFromMonad :: ReadLineMonad (Maybe T.Text)-readLineFromMonad = GetLine Value--instance Monad ReadLineMonad where-  Value x >>= f = f x-  GetLine g >>= f = GetLine $ g >=> f--instance Functor ReadLineMonad where-  fmap = liftA--instance Applicative ReadLineMonad where-  pure = Value-  (<*>) = ap--getLinesFromM :: Monad m => m T.Text -> ReadLineMonad a -> m a-getLinesFromM _ (Value x) = pure x-getLinesFromM fetch (GetLine f) = do-  s <- fetch-  getLinesFromM fetch $ f $ Just s--getNoLines :: ReadLineMonad a -> Either SyntaxError a-getNoLines (Value x) = Right x-getNoLines (GetLine f) = getNoLines $ f Nothing+type ParserMonad = ExceptT SyntaxError (State ParserState)  arrayFromList :: [a] -> Array Int a arrayFromList l = listArray (0, length l - 1) l@@ -169,9 +139,6 @@   where     field (name, pat) = RecordFieldExplicit name <$> patternExp pat <*> pure loc -eof :: Pos -> L Token-eof pos = L (Loc pos pos) EOF- binOpName :: L Token -> (QualName Name, Loc) binOpName (L loc (SYMBOL _ qs op)) = (QualName qs op, loc) binOpName t = error $ "binOpName: unexpected " ++ show t@@ -181,12 +148,6 @@   AppExp (BinOp (QualName qs op, srclocOf loc) NoInfo (x, NoInfo) (y, NoInfo) (srcspan x y)) NoInfo binOp _ t _ = error $ "binOp: unexpected " ++ show t -getTokens :: ParserMonad ([L Token], Pos)-getTokens = lift $ gets parserLexical--putTokens :: ([L Token], Pos) -> ParserMonad ()-putTokens l = lift $ modify $ \env -> env {parserLexical = l}- putComment :: Comment -> ParserMonad () putComment c = lift $ modify $ \env ->   env {parserComments = c : parserComments env}@@ -208,42 +169,21 @@ primNegate (UnsignedValue v) = UnsignedValue $ intNegate v primNegate (BoolValue v) = BoolValue $ not v -readLine :: ParserMonad (Maybe T.Text)-readLine = do-  s <- lift $ lift readLineFromMonad-  case s of-    Just s' ->-      lift $ modify $ \env -> env {parserInput = parserInput env <> "\n" <> s'}-    Nothing -> pure ()-  pure s- lexer :: (L Token -> ParserMonad a) -> ParserMonad a lexer cont = do-  (ts, pos) <- getTokens-  case ts of-    [] -> do-      ended <- lift $ runExceptT $ cont $ eof pos-      case ended of-        Right x -> pure x-        Left parse_e -> do-          line <- readLine-          ts' <--            case line of-              Nothing -> throwError parse_e-              Just line' -> pure $ scanTokensText (advancePos pos '\n') line'-          (ts'', pos') <- either (throwError . lexerErrToParseErr) pure ts'-          case ts'' of-            [] -> cont $ eof pos-            xs -> do-              putTokens (xs, pos')-              lexer cont-    (L loc (COMMENT text) : xs) -> do-      putComment $ Comment loc text-      putTokens (xs, pos)-      lexer cont-    (x : xs) -> do-      putTokens (xs, pos)-      cont x+  ls <- lift $ gets parserLexerState+  case getToken ls of+    Left e ->+      throwError $ lexerErrToParseErr e+    Right (ls', (start, end, tok)) -> do+      let loc = Loc start end+      lift $ modify $ \s -> s {parserLexerState = ls'}+      case tok of+        COMMENT text -> do+          putComment $ Comment loc text+          lexer cont+        _ ->+          cont $ L loc tok  parseError :: (L Token, [String]) -> ParserMonad a parseError (L loc EOF, expected) =@@ -257,7 +197,7 @@ parseError (L loc _, expected) = do   input <- lift $ gets parserInput   let ~(Loc (Pos _ _ _ beg) (Pos _ _ _ end)) = locOf loc-      tok_src = T.take (end - beg + 1) $ T.drop beg input+      tok_src = T.take (end - beg) $ T.drop beg input   parseErrorAt loc . Just . T.unlines $     [ "Unexpected token: '" <> tok_src <> "'",       "Expected one of the following: " <> T.unwords (map T.pack expected)@@ -288,23 +228,23 @@ lexerErrToParseErr :: LexerError -> SyntaxError lexerErrToParseErr (LexerError loc msg) = SyntaxError loc msg -parseInMonad ::+parseWithComments ::   ParserMonad a ->   FilePath ->   T.Text ->-  ReadLineMonad (Either SyntaxError (a, [Comment]))-parseInMonad p file program =-  either-    (pure . Left . lexerErrToParseErr)-    (fmap onRes . runStateT (runExceptT p) . env)-    (scanTokensText (Pos file 1 1 0) program)+  Either SyntaxError (a, [Comment])+parseWithComments p file program =+  onRes $ runState (runExceptT p) env   where-    env = ParserState file program []+    env =+      ParserState+        file+        program+        []+        (initialLexerState start $ BS.fromStrict . T.encodeUtf8 $ program)+    start = Pos file 1 1 0     onRes (Left err, _) = Left err     onRes (Right x, s) = Right (x, reverse $ parserComments s)--parseWithComments :: ParserMonad a -> FilePath -> T.Text -> Either SyntaxError (a, [Comment])-parseWithComments p file program = join $ getNoLines $ parseInMonad p file program  parse :: ParserMonad a -> FilePath -> T.Text -> Either SyntaxError a parse p file program = fst <$> parseWithComments p file program
src/Language/Futhark/Parser/Parser.y view
@@ -8,9 +8,6 @@   , futharkType   , parse   , parseWithComments-  , ReadLineMonad (..)-  , getLinesFromM-  , parseInMonad   , SyntaxError(..)   , Comment(..)   )@@ -212,9 +209,12 @@     | Doc Dec_          { addDoc $1 $2 }  Decs :: { [UncheckedDec] }-      :          { [] }-      | Dec Decs { $1 : $2 }+      : Decs_     { reverse $1 } +Decs_ :: { [UncheckedDec] }+      :           { [] }+      | Decs_ Dec { $2 : $1 }+ Dec_ :: { UncheckedDec }     : Val               { ValDec $1 }     | TypeAbbr          { TypeDec $1 }@@ -320,9 +320,12 @@         { addAttrSpec $2 $4 }  Specs :: { [SpecBase NoInfo Name] }-       : Spec Specs { $1 : $2 }-       |            { [] }+       : Specs_      { reverse $1 } +Specs_ :: { [SpecBase NoInfo Name] }+       : Specs_ Spec { $2 : $1 }+       |             { [] }+ SizeBinder :: { SizeBinder Name }             : '[' id ']'  { let L _ (ID name) = $2 in SizeBinder name (srcspan $1 $>) }             | '...[' id ']' { let L _ (ID name) = $2 in SizeBinder name (srcspan $1 $>) }@@ -600,9 +603,9 @@                         StringLit (BS.unpack (T.encodeUtf8 s)) (srclocOf loc) }      | hole           { Hole NoInfo (srclocOf $1) }      | '(' Exp ')'            { Parens $2 (srcspan $1 $>) }-     | '(' Exp ',' Exps1 ')'  { TupLit ($2 : fst $4 : snd $4) (srcspan $1 $>) }+     | '(' Exp ',' Exps1 ')'  { TupLit ($2 : $4) (srcspan $1 $>) }      | '('      ')'           { TupLit [] (srcspan $1 $>) }-     | '[' Exps1 ']'          { ArrayLit (fst $2:snd $2) NoInfo (srcspan $1 $>) }+     | '[' Exps1 ']'          { ArrayLit $2 NoInfo (srcspan $1 $>) }      | '['       ']'          { ArrayLit [] NoInfo (srcspan $1 $>) }       | id { let L loc (ID v)  = $1 in Var (QualName [] v) NoInfo (srclocOf loc) }@@ -651,14 +654,12 @@         | false  { (BoolValue False, $1) }         | NumLit { $1 } -Exps1 :: { (UncheckedExp, [UncheckedExp]) }-       : Exps1_ { case reverse (snd $1 : fst $1) of-                    []   -> (snd $1, [])-                    y:ys -> (y, ys) }+Exps1 :: { [UncheckedExp] }+       : Exps1_ { reverse $1 } -Exps1_ :: { ([UncheckedExp], UncheckedExp) }-        : Exps1_ ',' Exp { (snd $1 : fst $1, $3) }-        | Exp            { ([], $1) }+Exps1_ :: { [UncheckedExp] }+        : Exps1_ ',' Exp { $3 : $1 }+        | Exp            { [$1] }  FieldAccesses :: { [(Name, Loc)] }                : '.' FieldId FieldAccesses { $2 : $3 }
unittests/Futhark/IR/Mem/IxFunTests.hs view
@@ -8,6 +8,7 @@ import Data.Function ((&)) import Data.List qualified as L import Data.Map qualified as M+import Data.Text qualified as T import Futhark.Analysis.PrimExp.Convert import Futhark.IR.Mem.IxFun qualified as IxFunLMAD import Futhark.IR.Mem.IxFun.Alg qualified as IxFunAlg@@ -17,7 +18,7 @@ import Futhark.IR.Syntax import Futhark.IR.Syntax.Core () import Futhark.Util.IntegralExp qualified as IE-import Futhark.Util.Pretty qualified as PR+import Futhark.Util.Pretty import Test.Tasty import Test.Tasty.HUnit import Prelude hiding (span)@@ -47,42 +48,42 @@           ([], x)           strides -compareIxFuns :: IxFunLMAD.IxFun Int -> IxFunAlg.IxFun Int -> Assertion-compareIxFuns ixfunLMAD ixfunAlg =+compareIxFuns :: Maybe (IxFunLMAD.IxFun Int) -> IxFunAlg.IxFun Int -> Assertion+compareIxFuns (Just ixfunLMAD) ixfunAlg =   let lmadShape = IxFunLMAD.shape ixfunLMAD       algShape = IxFunAlg.shape ixfunAlg       points = allPoints lmadShape       resLMAD = map (IxFunLMAD.index ixfunLMAD) points       resAlg = map (IxFunAlg.index ixfunAlg) points       errorMessage =-        "lmad ixfun:  "-          ++ PR.prettyString ixfunLMAD-          ++ "\n"-          ++ "alg ixfun:   "-          ++ PR.prettyString ixfunAlg-          ++ "\n"-          ++ "lmad shape:  "-          ++ show lmadShape-          ++ "\n"-          ++ "alg shape:   "-          ++ show algShape-          ++ "\n"-          ++ "lmad points length: "-          ++ show (length resLMAD)-          ++ "\n"-          ++ "alg points length:  "-          ++ show (length resAlg)-          ++ "\n"-          ++ "lmad points: "-          ++ show resLMAD-          ++ "\n"-          ++ "alg points:  "-          ++ show resAlg+        T.unpack . docText $+          "lmad ixfun:  " <> pretty ixfunLMAD+            </> "alg ixfun:   " <> pretty ixfunAlg+            </> "lmad shape:  " <> pretty lmadShape+            </> "alg shape:   " <> pretty algShape+            </> "lmad points length: " <> pretty (length resLMAD)+            </> "alg points length:  " <> pretty (length resAlg)+            </> "lmad points: " <> pretty resLMAD+            </> "alg points:  " <> pretty resAlg    in (lmadShape == algShape && resLMAD == resAlg) @? errorMessage+compareIxFuns Nothing ixfunAlg =+  assertFailure $+    unlines+      [ "lmad ixfun: Nothing",+        "alg ixfun:  " <> prettyString ixfunAlg+      ]  compareOps :: IxFunWrap.IxFun Int -> Assertion compareOps (ixfunLMAD, ixfunAlg) = compareIxFuns ixfunLMAD ixfunAlg +compareOpsFailure :: IxFunWrap.IxFun Int -> Assertion+compareOpsFailure (Nothing, _) = pure ()+compareOpsFailure (Just ixfunLMAD, ixfunAlg) =+  assertFailure . T.unpack . docText $+    "Not supposed to be representable as LMAD."+      </> "lmad ixfun: " <> pretty ixfunLMAD+      </> "alg ixfun:  " <> pretty ixfunAlg+ -- XXX: Clean this up. n :: Int n = 19@@ -102,10 +103,11 @@     concat       [ test_iota,         test_slice_iota,-        test_reshape_slice_iota1,+        test_slice_reshape_iota1,         test_permute_slice_iota,+        test_reshape_iota,         test_reshape_permute_iota,-        test_reshape_slice_iota2,+        test_slice_reshape_iota2,         test_reshape_slice_iota3,         test_complex1,         test_complex2,@@ -113,6 +115,8 @@         test_rebase2,         test_rebase3,         test_rebase4_5,+        test_rebase6,+        test_rebase7,         test_flatSlice_iota,         test_slice_flatSlice_iota,         test_flatSlice_flatSlice_iota,@@ -129,194 +133,161 @@  test_iota :: [TestTree] test_iota =-  singleton $-    testCase "iota" $-      compareOps $-        iota [n]+  singleton . testCase "iota" . compareOps $+    iota [n]  test_slice_iota :: [TestTree] test_slice_iota =-  singleton $-    testCase "slice . iota" $-      compareOps $-        slice (iota [n, n, n]) slice3+  singleton . testCase "slice . iota" . compareOps $+    slice (iota [n, n, n]) slice3 -test_reshape_slice_iota1 :: [TestTree]-test_reshape_slice_iota1 =-  singleton $-    testCase "reshape . slice . iota 1" $-      compareOps $-        reshape-          (slice (iota [n, n, n]) slice3)-          [n `P.div` 2, n `P.div` 3]+test_slice_reshape_iota1 :: [TestTree]+test_slice_reshape_iota1 =+  singleton . testCase "slice . reshape . iota 1" . compareOps $+    slice (reshape (iota [n, n, n]) [n `P.div` 2, n `P.div` 3, 1]) slice3  test_permute_slice_iota :: [TestTree] test_permute_slice_iota =-  singleton $-    testCase "permute . slice . iota" $-      compareOps $-        permute (slice (iota [n, n, n]) slice3) [1, 0]+  singleton . testCase "permute . slice . iota" . compareOps $+    permute (slice (iota [n, n, n]) slice3) [1, 0] +test_reshape_iota :: [TestTree]+test_reshape_iota =+  -- This tests a pattern that occurs with ScalarSpace.+  singleton . testCase "reshape . zeroslice . iota" . compareOps $+    let s = Slice [DimSlice 0 n 0, DimSlice 0 n 1]+     in reshape (slice (iota [n, n]) s) [1, n, 1, n]+ test_reshape_permute_iota :: [TestTree] test_reshape_permute_iota =   -- negative reshape test-  singleton $-    testCase "reshape . permute . iota" $-      compareOps $-        let newdims = [n * n, n]-         in reshape (permute (iota [n, n, n]) [1, 2, 0]) newdims+  singleton . testCase "reshape . permute . iota" . compareOpsFailure $+    let newdims = [n * n, n]+     in reshape (permute (iota [n, n, n]) [1, 2, 0]) newdims -test_reshape_slice_iota2 :: [TestTree]-test_reshape_slice_iota2 =-  -- negative reshape test-  singleton $-    testCase "reshape . slice . iota 2" $-      compareOps $-        let newdims = [n * n, n]-            slc =-              Slice-                [ DimFix (n `P.div` 2),-                  DimSlice (n - 1) n (-1),-                  DimSlice 0 n 1,-                  DimSlice (n - 1) n (-1)-                ]-         in reshape (slice (iota [n, n, n, n]) slc) newdims+test_slice_reshape_iota2 :: [TestTree]+test_slice_reshape_iota2 =+  singleton . testCase "slice . reshape . iota 2" . compareOps $+    let newdims = [n * n, n]+        slc =+          Slice+            [ DimFix (n `P.div` 2),+              DimSlice 0 n 1+            ]+     in slice (reshape (iota [n, n, n, n]) newdims) slc  test_reshape_slice_iota3 :: [TestTree] test_reshape_slice_iota3 =   -- negative reshape test-  singleton $-    testCase "reshape . slice . iota 3" $-      compareOps $-        let newdims = [n * n, n]-            slc =-              Slice-                [ DimFix (n `P.div` 2),-                  DimSlice 0 n 1,-                  DimSlice 0 (n `P.div` 2) 1,-                  DimSlice 0 n 1-                ]-         in reshape (slice (iota [n, n, n, n]) slc) newdims+  singleton . testCase "reshape . slice . iota 3" . compareOpsFailure $+    let newdims = [n * n, n]+        slc =+          Slice+            [ DimFix (n `P.div` 2),+              DimSlice 0 n 1,+              DimSlice 0 (n `P.div` 2) 1,+              DimSlice 0 n 1+            ]+     in reshape (slice (iota [n, n, n, n]) slc) newdims  test_complex1 :: [TestTree] test_complex1 =-  singleton $-    testCase "reshape . permute . slice . permute . slice . iota 1" $-      compareOps $-        let newdims =-              [ n,-                n,-                n,-                (n `P.div` 3) - 2-              ]-            slice33 =-              Slice-                [ DimSlice (n - 1) (n `P.div` 3) (-1),-                  DimSlice (n - 1) n (-1),-                  DimSlice (n - 1) n (-1),-                  DimSlice 0 n 1-                ]-            ixfun = permute (slice (iota [n, n, n, n, n]) slice33) [3, 1, 2, 0]-            m = n `P.div` 3-            slice1 =-              Slice-                [ DimSlice 0 n 1,-                  DimSlice (n - 1) n (-1),-                  DimSlice (n - 1) n (-1),-                  DimSlice 1 (m - 2) (-1)-                ]-            ixfun' = reshape (slice ixfun slice1) newdims-         in ixfun'+  singleton . testCase "permute . slice . permute . slice . iota 1" . compareOps $+    let slice33 =+          Slice+            [ DimSlice (n - 1) (n `P.div` 3) (-1),+              DimSlice (n - 1) n (-1),+              DimSlice (n - 1) n (-1),+              DimSlice 0 n 1+            ]+        ixfun = permute (slice (iota [n, n, n, n, n]) slice33) [3, 1, 2, 0]+        m = n `P.div` 3+        slice1 =+          Slice+            [ DimSlice 0 n 1,+              DimSlice (n - 1) n (-1),+              DimSlice (n - 1) n (-1),+              DimSlice 1 (m - 2) (-1)+            ]+        ixfun' = slice ixfun slice1+     in ixfun'  test_complex2 :: [TestTree] test_complex2 =-  singleton $-    testCase "reshape . permute . slice . permute . slice . iota 2" $-      compareOps $-        let newdims =-              [ n,-                n * n,-                (n `P.div` 3) - 2-              ]-            slc2 =-              Slice-                [ DimFix (n `P.div` 2),-                  DimSlice (n - 1) (n `P.div` 3) (-1),-                  DimSlice (n - 1) n (-1),-                  DimSlice (n - 1) n (-1),-                  DimSlice 0 n 1-                ]-            ixfun = permute (slice (iota [n, n, n, n, n]) slc2) [3, 1, 2, 0]-            m = n `P.div` 3-            slice1 =-              Slice-                [ DimSlice 0 n 1,-                  DimSlice (n - 1) n (-1),-                  DimSlice (n - 1) n (-1),-                  DimSlice 1 (m - 2) (-1)-                ]-            ixfun' = reshape (slice ixfun slice1) newdims-         in ixfun'+  singleton . testCase "permute . slice . permute . slice . iota 2" . compareOps $+    let slc2 =+          Slice+            [ DimFix (n `P.div` 2),+              DimSlice (n - 1) (n `P.div` 3) (-1),+              DimSlice (n - 1) n (-1),+              DimSlice (n - 1) n (-1),+              DimSlice 0 n 1+            ]+        ixfun = permute (slice (iota [n, n, n, n, n]) slc2) [3, 1, 2, 0]+        m = n `P.div` 3+        slice1 =+          Slice+            [ DimSlice 0 n 1,+              DimSlice (n - 1) n (-1),+              DimSlice (n - 1) n (-1),+              DimSlice 1 (m - 2) (-1)+            ]+        ixfun' = slice ixfun slice1+     in ixfun'  test_rebase1 :: [TestTree] test_rebase1 =-  singleton $-    testCase "rebase 1" $-      compareOps $-        let slice_base =-              Slice-                [ DimFix (n `P.div` 2),-                  DimSlice 2 (n - 2) 1,-                  DimSlice 3 (n - 3) 1-                ]-            ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]-            ixfn_orig = permute (iota [n - 3, n - 2]) [1, 0]-            ixfn_rebase = rebase ixfn_base ixfn_orig-         in ixfn_rebase+  singleton . testCase "rebase 1" . compareOpsFailure $+    let slice_base =+          Slice+            [ DimFix (n `P.div` 2),+              DimSlice 2 (n - 2) 1,+              DimSlice 3 (n - 3) 1+            ]+        ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]+        ixfn_orig = permute (iota [n - 3, n - 2]) [1, 0]+        ixfn_rebase = rebase ixfn_base ixfn_orig+     in ixfn_rebase  test_rebase2 :: [TestTree] test_rebase2 =-  singleton $-    testCase "rebase 2" $-      compareOps $-        let slice_base =-              Slice-                [ DimFix (n `P.div` 2),-                  DimSlice (n - 1) (n - 2) (-1),-                  DimSlice (n - 1) (n - 3) (-1)-                ]-            slice_orig =-              Slice-                [ DimSlice (n - 4) (n - 3) (-1),-                  DimSlice (n - 3) (n - 2) (-1)-                ]-            ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]-            ixfn_orig = permute (slice (iota [n - 3, n - 2]) slice_orig) [1, 0]-            ixfn_rebase = rebase ixfn_base ixfn_orig-         in ixfn_rebase+  singleton . testCase "rebase 2" . compareOpsFailure $+    let slice_base =+          Slice+            [ DimFix (n `P.div` 2),+              DimSlice (n - 1) (n - 2) (-1),+              DimSlice (n - 1) (n - 3) (-1)+            ]+        slice_orig =+          Slice+            [ DimSlice (n - 4) (n - 3) (-1),+              DimSlice (n - 3) (n - 2) (-1)+            ]+        ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]+        ixfn_orig = permute (slice (iota [n - 3, n - 2]) slice_orig) [1, 0]+        ixfn_rebase = rebase ixfn_base ixfn_orig+     in ixfn_rebase  test_rebase3 :: [TestTree] test_rebase3 =-  singleton $-    testCase "rebase full orig but not monotonic" $-      compareOps $-        let n2 = (n - 2) `P.div` 3-            n3 = (n - 3) `P.div` 2-            slice_base =-              Slice-                [ DimFix (n `P.div` 2),-                  DimSlice (n - 1) n2 (-3),-                  DimSlice (n - 1) n3 (-2)-                ]-            slice_orig =-              Slice-                [ DimSlice (n3 - 1) n3 (-1),-                  DimSlice (n2 - 1) n2 (-1)-                ]-            ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]-            ixfn_orig = permute (slice (iota [n3, n2]) slice_orig) [1, 0]-            ixfn_rebase = rebase ixfn_base ixfn_orig-         in ixfn_rebase+  singleton . testCase "rebase full orig but not monotonic" . compareOpsFailure $+    let n2 = (n - 2) `P.div` 3+        n3 = (n - 3) `P.div` 2+        slice_base =+          Slice+            [ DimFix (n `P.div` 2),+              DimSlice (n - 1) n2 (-3),+              DimSlice (n - 1) n3 (-2)+            ]+        slice_orig =+          Slice+            [ DimSlice (n3 - 1) n3 (-1),+              DimSlice (n2 - 1) n2 (-1)+            ]+        ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]+        ixfn_orig = permute (slice (iota [n3, n2]) slice_orig) [1, 0]+        ixfn_rebase = rebase ixfn_base ixfn_orig+     in ixfn_rebase  test_rebase4_5 :: [TestTree] test_rebase4_5 =@@ -335,54 +306,67 @@           ]       ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]       ixfn_orig = permute (slice (iota [n3, n2]) slice_orig) [1, 0]-   in [ testCase "rebase mixed monotonicities" $-          compareOps $-            rebase ixfn_base ixfn_orig+   in [ testCase "rebase mixed monotonicities" . compareOpsFailure $+          rebase ixfn_base ixfn_orig       ] +-- Imitates a case from memory expansion.+test_rebase6 :: [TestTree]+test_rebase6 =+  [ testCase "rebase . slice1 . iota" . compareOps $+      rebase+        (slice (iota [n, n, n]) (Slice [DimSlice 0 n 1, DimSlice 0 n 1]))+        ( slice+            (iota [n, n])+            (Slice [DimSlice 1 (n - 1) 1, DimSlice 0 n 1])+        )+  ]++-- Imitates another case from memory expansion.+test_rebase7 :: [TestTree]+test_rebase7 =+  [ testCase "rebase . slice2 . iota" . compareOps $+      rebase+        (slice (iota [n, n, n]) (Slice [DimSlice 0 n 1, DimSlice 0 n 1]))+        ( slice+            (iota [n, n])+            (Slice [DimSlice 0 (n - 1) 1, DimSlice 0 n 1])+        )+  ]+ test_flatSlice_iota :: [TestTree] test_flatSlice_iota =-  singleton $-    testCase "flatSlice . iota" $-      compareOps $-        flatSlice (iota [n * n * n * n]) $-          FlatSlice 2 [FlatDimIndex (n * 2) 4, FlatDimIndex n 3, FlatDimIndex 1 2]+  singleton . testCase "flatSlice . iota" . compareOps $+    flatSlice (iota [n * n * n * n]) $+      FlatSlice 2 [FlatDimIndex (n * 2) 4, FlatDimIndex n 3, FlatDimIndex 1 2]  test_slice_flatSlice_iota :: [TestTree] test_slice_flatSlice_iota =-  singleton $-    testCase "slice . flatSlice . iota " $-      compareOps $-        slice (flatSlice (iota [2 + n * n * n]) flat_slice) $-          Slice [DimFix 2, DimSlice 0 n 1, DimFix 0]+  singleton . testCase "slice . flatSlice . iota " . compareOps $+    slice (flatSlice (iota [2 + n * n * n]) flat_slice) $+      Slice [DimFix 2, DimSlice 0 n 1, DimFix 0]   where     flat_slice = FlatSlice 2 [FlatDimIndex (n * n) 1, FlatDimIndex n 1, FlatDimIndex 1 1]  test_flatSlice_flatSlice_iota :: [TestTree] test_flatSlice_flatSlice_iota =-  singleton $-    testCase "flatSlice . flatSlice . iota " $-      compareOps $-        flatSlice (flatSlice (iota [10 * 10]) flat_slice_1) flat_slice_2+  singleton . testCase "flatSlice . flatSlice . iota " . compareOps $+    flatSlice (flatSlice (iota [10 * 10]) flat_slice_1) flat_slice_2   where     flat_slice_1 = FlatSlice 17 [FlatDimIndex 3 27, FlatDimIndex 3 10, FlatDimIndex 3 1]     flat_slice_2 = FlatSlice 2 [FlatDimIndex 2 (-2)]  test_flatSlice_slice_iota :: [TestTree] test_flatSlice_slice_iota =-  singleton $-    testCase "flatSlice . slice . iota " $-      compareOps $-        flatSlice (slice (iota [210, 100]) $ Slice [DimSlice 10 100 2, DimFix 10]) flat_slice_1+  singleton . testCase "flatSlice . slice . iota " . compareOps $+    flatSlice (slice (iota [210, 100]) $ Slice [DimSlice 10 100 2, DimFix 10]) flat_slice_1   where     flat_slice_1 = FlatSlice 17 [FlatDimIndex 3 27, FlatDimIndex 3 10, FlatDimIndex 3 1]  test_flatSlice_transpose_slice_iota :: [TestTree] test_flatSlice_transpose_slice_iota =-  singleton $-    testCase "flatSlice . transpose . slice . iota " $-      compareOps $-        flatSlice (permute (slice (iota [20, 20]) $ Slice [DimSlice 1 5 2, DimSlice 0 5 2]) [1, 0]) flat_slice_1+  singleton . testCase "flatSlice . transpose . slice . iota " . compareOpsFailure $+    flatSlice (permute (slice (iota [20, 20]) $ Slice [DimSlice 1 5 2, DimSlice 0 5 2]) [1, 0]) flat_slice_1   where     flat_slice_1 = FlatSlice 1 [FlatDimIndex 2 2] @@ -419,15 +403,15 @@ --             lm1 = --               IxFunLMAD.LMAD --                 256---                 [ IxFunLMAD.LMADDim 256 0 (sub64 (num_blocks_8284) 1) 0 IxFunLMAD.Inc,---                   IxFunLMAD.LMADDim 1 0 16 1 IxFunLMAD.Inc,---                   IxFunLMAD.LMADDim 16 0 16 2 IxFunLMAD.Inc+--                 [ IxFunLMAD.LMADDim 256 0 (sub64 (num_blocks_8284) 1) 0 ,+--                   IxFunLMAD.LMADDim 1 0 16 1 ,+--                   IxFunLMAD.LMADDim 16 0 16 2 --                 ] --             lm2 :: IxFunLMAD.LMAD (TPrimExp Int64 VName) --             lm2 = --               IxFunLMAD.LMAD --                 (add_nw64 (add_nw64 (add_nw64 (add_nw64 (mul_nw64 (256) (num_blocks_8284)) (256)) (mul_nw64 (gtid_8472) (mul_nw64 (256) (num_blocks_8284)))) (mul_nw64 (gtid_8473) (256))) (mul_nw64 (gtid_8474) (16)))---                 [IxFunLMAD.LMADDim 1 0 16 0 IxFunLMAD.Inc]+--                 [IxFunLMAD.LMADDim 1 0 16 0 ] --          in testCase (pretty lm1 <> " and " <> pretty lm2) $ IxFunLMAD.disjoint2 lessthans nonnegs lm1 lm2 @? "Failed" --       ] @@ -480,37 +464,37 @@               lm1 =                 IxFunLMAD.LMAD                   (add_nw64 (mul64 block_size_12121 i_12214) (mul_nw64 (add_nw64 gtid_12553 1) (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))-                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (add64 1 i_12214) gtid_12553) 1) 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 (block_size_12121 + 1) 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (add64 1 i_12214) gtid_12553) 1) 0,+                    IxFunLMAD.LMADDim 1 (block_size_12121 + 1) 1                   ]                lm2 =                 IxFunLMAD.LMAD                   (block_size_12121 * i_12214)-                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0,+                    IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1                   ]                lm_w =                 IxFunLMAD.LMAD                   (add_nw64 (add64 (add64 1 n_blab) (mul64 block_size_12121 i_12214)) (mul_nw64 gtid_12553 (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))-                  [ IxFunLMAD.LMADDim n_blab block_size_12121 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 block_size_12121 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim n_blab block_size_12121 0,+                    IxFunLMAD.LMADDim 1 block_size_12121 1                   ]                lm_blocks =                 IxFunLMAD.LMAD                   (block_size_12121 * i_12214 + n_blab + 1)-                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (i_12214 + 1) 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim n_blab block_size_12121 1 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 block_size_12121 2 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (i_12214 + 1) 0,+                    IxFunLMAD.LMADDim n_blab block_size_12121 1,+                    IxFunLMAD.LMADDim 1 block_size_12121 2                   ]                lm_lower_per =                 IxFunLMAD.LMAD                   (block_size_12121 * i_12214)-                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (i_12214 + 1) 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 (block_size_12121 + 1) 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (i_12214 + 1) 0,+                    IxFunLMAD.LMADDim 1 (block_size_12121 + 1) 1                   ]                res1 = disjointTester asserts lessthans lm1 lm_w@@ -539,36 +523,36 @@               lm1 =                 IxFunLMAD.LMAD                   (add_nw64 (add64 n_blab (sub64 (sub64 (mul64 n_blab (add64 1 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) 1)) (mul_nw64 (add_nw64 gtid_12553 1) (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))-                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (sub64 (sub64 (sdiv64 (sub64 n_blab 1) block_size_12121) i_12214) 1) gtid_12553) 1) 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim n_blab block_size_12121 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (sub64 (sub64 (sdiv64 (sub64 n_blab 1) block_size_12121) i_12214) 1) gtid_12553) 1) 0,+                    IxFunLMAD.LMADDim n_blab block_size_12121 1                   ]                lm2 =                 IxFunLMAD.LMAD                   (add_nw64 (sub64 (sub64 (mul64 n_blab (add64 1 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) 1) (mul_nw64 (add_nw64 gtid_12553 1) (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))-                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (sub64 (sub64 (sdiv64 (sub64 n_blab 1) block_size_12121) i_12214) 1) gtid_12553) 1) 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (sub64 (sub64 (sdiv64 (sub64 n_blab 1) block_size_12121) i_12214) 1) gtid_12553) 1) 0,+                    IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1                   ]                lm3 =                 IxFunLMAD.LMAD                   (add64 n_blab (sub64 (sub64 (mul64 n_blab (add64 1 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) 1))-                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim n_blab block_size_12121 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0,+                    IxFunLMAD.LMADDim n_blab block_size_12121 1                   ]                lm4 =                 IxFunLMAD.LMAD                   (sub64 (sub64 (mul64 n_blab (add64 1 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) 1)-                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0,+                    IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1                   ]                lm_w =                 IxFunLMAD.LMAD                   (add_nw64 (sub64 (mul64 n_blab (add64 2 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) (mul_nw64 gtid_12553 (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))-                  [ IxFunLMAD.LMADDim n_blab block_size_12121 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 block_size_12121 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim n_blab block_size_12121 0,+                    IxFunLMAD.LMADDim 1 block_size_12121 1                   ]                res1 = disjointTester asserts lessthans lm1 lm_w@@ -589,29 +573,29 @@               lm1 =                 IxFunLMAD.LMAD                   (1024 * num_blocks * (1 + step) + 1024 * step)-                  [ IxFunLMAD.LMADDim (1024 * num_blocks) (num_blocks - step - 1) 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 32 32 1 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 32 2 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (1024 * num_blocks) (num_blocks - step - 1) 0,+                    IxFunLMAD.LMADDim 32 32 1,+                    IxFunLMAD.LMADDim 1 32 2                   ]                lm_w1 =                 IxFunLMAD.LMAD                   (1024 * num_blocks * step + 1024 * step)-                  [ IxFunLMAD.LMADDim 32 32 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 32 1 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim 32 32 0,+                    IxFunLMAD.LMADDim 1 32 1                   ]                lm_w2 =                 IxFunLMAD.LMAD                   ((1 + step) * 1024 * num_blocks + (1 + step) * 1024)-                  [ IxFunLMAD.LMADDim (1024 * num_blocks) (num_blocks - step - 1) 0 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1024 (num_blocks - step - 1) 1 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1024 1 2 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 32 1 3 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 128 8 4 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 4 8 5 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 32 4 6 IxFunLMAD.Inc,-                    IxFunLMAD.LMADDim 1 4 7 IxFunLMAD.Inc+                  [ IxFunLMAD.LMADDim (1024 * num_blocks) (num_blocks - step - 1) 0,+                    IxFunLMAD.LMADDim 1024 (num_blocks - step - 1) 1,+                    IxFunLMAD.LMADDim 1024 1 2,+                    IxFunLMAD.LMADDim 32 1 3,+                    IxFunLMAD.LMADDim 128 8 4,+                    IxFunLMAD.LMADDim 4 8 5,+                    IxFunLMAD.LMADDim 32 4 6,+                    IxFunLMAD.LMADDim 1 4 7                   ]                asserts =
unittests/Futhark/IR/Mem/IxFunWrapper.hs view
@@ -12,6 +12,7 @@   ) where +import Control.Monad (join) import Futhark.IR.Mem.IxFun qualified as I import Futhark.IR.Mem.IxFun.Alg qualified as IA import Futhark.IR.Syntax (FlatSlice, Slice)@@ -21,52 +22,52 @@  type Permutation = [Int] -type IxFun num = (I.IxFun num, IA.IxFun num)+type IxFun num = (Maybe (I.IxFun num), IA.IxFun num)  iota ::   IntegralExp num =>   Shape num ->   IxFun num-iota x = (I.iota x, IA.iota x)+iota x = (Just $ I.iota x, IA.iota x)  permute ::   IntegralExp num =>   IxFun num ->   Permutation ->   IxFun num-permute (l, a) x = (I.permute l x, IA.permute a x)+permute (l, a) x = (I.permute <$> l <*> pure x, IA.permute a x)  reshape ::   (Eq num, IntegralExp num) =>   IxFun num ->   Shape num ->   IxFun num-reshape (l, a) x = (I.reshape l x, IA.reshape a x)+reshape (l, a) x = (join (I.reshape <$> l <*> pure x), IA.reshape a x)  coerce ::   (Eq num, IntegralExp num) =>   IxFun num ->   Shape num ->   IxFun num-coerce (l, a) x = (I.coerce l x, IA.coerce a x)+coerce (l, a) x = (I.coerce <$> l <*> pure x, IA.coerce a x)  slice ::   (Eq num, IntegralExp num) =>   IxFun num ->   Slice num ->   IxFun num-slice (l, a) x = (I.slice l x, IA.slice a x)+slice (l, a) x = (I.slice <$> l <*> pure x, IA.slice a x)  flatSlice ::   (Eq num, IntegralExp num) =>   IxFun num ->   FlatSlice num ->   IxFun num-flatSlice (l, a) x = (I.flatSlice l x, IA.flatSlice a x)+flatSlice (l, a) x = (join (I.flatSlice <$> l <*> pure x), IA.flatSlice a x)  rebase ::   (Eq num, IntegralExp num) =>   IxFun num ->   IxFun num ->   IxFun num-rebase (l, a) (l1, a1) = (I.rebase l l1, IA.rebase a a1)+rebase (l, a) (l1, a1) = (join (I.rebase <$> l <*> l1), IA.rebase a a1)