packages feed

futhark 0.25.3 → 0.25.4

raw patch · 23 files changed

+266/−187 lines, 23 filesdep ~lspPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: lsp

API changes (from Hackage documentation)

- Futhark.Construct: eIndex :: MonadBuilder m => VName -> m (Exp (Rep m)) -> m (Exp (Rep m))
+ Futhark.Construct: eIndex :: MonadBuilder m => VName -> [m (Exp (Rep m))] -> m (Exp (Rep m))

Files

docs/error-index.rst view
@@ -484,11 +484,12 @@ Whenever ``length`` occurs (as in the composition above), the type checker must *instantiate* the ``[n]`` with the concrete symbolic size of its input array.  But in the composition, that size does not-actually exist until ``filter`` has been run.  For that matter, the-type checker does not know what ``>->`` does, and for all it knows it-may actually apply ``filter`` many times to different arrays, yielding-different sizes.  This makes it impossible to uniquely instantiate the-type of ``length``, and therefore the program is rejected.+actually exist until ``filter`` has been fully applied.  For that+matter, the type checker does not know what ``>->`` does, and for all+it knows it may actually apply ``filter`` many times to different+arrays, yielding different sizes.  This makes it impossible to+uniquely instantiate the type of ``length``, and therefore the program+is rejected.  The common workaround is to use *pipelining* instead of composition whenever we use functions with existential return types:
docs/glossary.rst view
@@ -269,6 +269,12 @@      :term:`polymorphic` functions for each type it is used with.      Performed by the Futhark compiler. +   Name++     A lexical token consisting of alphanumeric characters and+     underscores, for example ``map`` and ``do_it``.  Most variables+     are names.  See also :term:`symbol`.+    Nested data parallelism       Nested :term:`data parallelism` occurs when a parallel construct@@ -346,6 +352,12 @@      Futhark: functions such as ``map``, ``reduce``, ``scan``, and so      on.  They are *second order* because they accept a functional      argument, and so permit :term:`nested data parallelism`.++   Symbol++     A lexical token that consts of symbolic (non-alphabetic+     characters), and can be bound to a value.  Infix operators such+     as ``+`` and ``/`` are symbols.  See also :term:`name`.     Type 
docs/language-reference.rst view
@@ -30,26 +30,46 @@ ------------------------  .. productionlist::-   id: `letter` `constituent`* | "_" `constituent`*+   name: `letter` `constituent`* | "_" `constituent`*    constituent: `letter` | `digit` | "_" | "'"-   quals: (`id` ".")+-   qualid: `id` | `quals` `id`-   binop: `opstartchar` `opchar`*-   qualbinop: `binop` | `quals` `binop` | "`" `qualid` "`"-   fieldid: `decimal` | `id`-   opstartchar: "+" | "-" | "*" | "/" | "%" | "=" | "!" | ">" | "<" | "|" | "&" | "^"-   opchar: `opstartchar` | "."-   constructor: "#" `id`+   quals: (`name` ".")++   qualname: `name` | `quals` `name`+   symbol: `symstartchar` `symchar`*+   qualsymbol: `symbol` | `quals` `symbol` | "`" `qualname` "`"+   fieldid: `decimal` | `name`+   symstartchar: "+" | "-" | "*" | "/" | "%" | "=" | "!" | ">" | "<" | "|" | "&" | "^"+   symchar: `symstartchar` | "."+   constructor: "#" `name`  Many things in Futhark are named. When we are defining something, we-give it an unqualified name (`id`).  When referencing something inside-a module, we use a qualified name (`qualid`).  The constructor names-of a sum type are identifiers prefixed with ``#``, with no space-afterwards.  The fields of a record are named with `fieldid`.  Note-that a `fieldid` can be a decimal number.  Futhark has three distinct-name spaces: terms, module types, and types.  Modules (including-parametric modules) and values both share the term namespace.+give it an unqualified name (`name`).  When referencing something+inside a module, we use a qualified name (`qualname`).  We can also+use symbols (`symbol`, `qualsymbol`), which are treated as infix by+the grammar. +The constructor names of a sum type are identifiers prefixed with+``#``, with no space afterwards.  The fields of a record are named+with `fieldid`.  Note that a `fieldid` can be a decimal number.+Futhark has three distinct name spaces: terms, module types, and+types.  Modules (including parametric modules) and values both share+the term namespace.++.. _reserved:++Reserved names and symbols+~~~~~~~~~~~~~~~~~~~~~~~~~~++A reserved name or symbol may be used only when explicitly present in+the grammar.  In particular, they cannot be bound in definitions.++The following identifier are reserved: ``true``, ``false``, ``if``,+``then``, ``else``, ``def``, ``let``, ``loop``, ``in``, ``val``,+``for``, ``do``, ``with``, ``local``, ``open``, ``include``,+``import``, ``type``, ``entry``, ``module``, ``while``, ``assert``,+``match``, ``case``.++The following symbols are reserved: ``=``.+ .. _primitives:  Primitive Types and Values@@ -106,7 +126,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~  .. productionlist::-   type:   `qualid`+   type:   `qualname`        : | `array_type`        : | `tuple_type`        : | `record_type`@@ -197,7 +217,7 @@  .. productionlist::    function_type: `param_type` "->" `type`-   param_type: `type` | "(" `id` ":" `type` ")"+   param_type: `type` | "(" `name` ":" `type` ")"  Functions are classified via function types, but they are not fully first class.  See :ref:`hofs` for the details.@@ -214,7 +234,7 @@ corresponding Unicode code point.  .. productionlist::-   existential_size: "?" ("[" `id` "]")+ "." `type`+   existential_size: "?" ("[" `name` "]")+ "." `type`  An existential size quantifier brings an unknown size into scope within a type.  This can be used to encode constraints for statically@@ -253,8 +273,8 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  .. productionlist::-   val_bind:   ("def" | "entry" | "let") (`id` | "(" `binop` ")") `type_param`* `pat`* [":" `type`] "=" `exp`-           : | ("def" | "entry" | "let") `pat` `binop` `pat` [":" `type`] "=" `exp`+   val_bind:   ("def" | "entry" | "let") (`name` | "(" `symbol` ")") `type_param`* `pat`* [":" `type`] "=" `exp`+           : | ("def" | "entry" | "let") `pat` `symbol` `pat` [":" `type`] "=" `exp`  **Note:** using ``let`` to define top-level bindings is deprecated. @@ -375,8 +395,8 @@ ~~~~~~~~~~~~~~~~~~  .. productionlist::-   type_bind: ("type" | "type^" | "type~") `id` `type_param`* "=" `type`-   type_param: "[" `id` "]" | "'" `id` | "'~" `id` | "'^" `id`+   type_bind: ("type" | "type^" | "type~") `name` `type_param`* "=" `type`+   type_param: "[" `name` "]" | "'" `name` | "'~" `name` | "'^" `name`  Type abbreviations function as shorthands for the purpose of documentation or brevity.  After a type binding ``type t1 = t2``, the@@ -433,7 +453,7 @@  .. productionlist::    atom:   `literal`-       : | `qualid` ("." `fieldid`)*+       : | `qualname` ("." `fieldid`)*        : | `stringlit`        : | `charlit`        : | "(" ")"@@ -441,18 +461,18 @@        : | "(" `exp` ("," `exp`)* ")"        : | "{" "}"        : | "{" `field` ("," `field`)* "}"-       : | `qualid` "[" `index` ("," `index`)* "]"+       : | `qualname` "[" `index` ("," `index`)* "]"        : | "(" `exp` ")" "[" `index` ("," `index`)* "]"        : | `quals` "." "(" `exp` ")"        : | "[" `exp` ("," `exp`)* "]"-       : | "(" `qualbinop` ")"-       : | "(" `exp` `qualbinop` ")"-       : | "(" `qualbinop` `exp` ")"+       : | "(" `qualsymbol` ")"+       : | "(" `exp` `qualsymbol` ")"+       : | "(" `qualsymbol` `exp` ")"        : | "(" ( "." `field` )+ ")"        : | "(" "." "[" `index` ("," `index`)* "]" ")"        : | "???"    exp:   `atom`-      : | `exp` `qualbinop` `exp`+      : | `exp` `qualsymbol` `exp`       : | `exp` `exp`       : | "!" `exp`       : | "-" `exp`@@ -464,8 +484,8 @@       : | `exp` [ ".." `exp` ] "..>" `exp`       : | "if" `exp` "then" `exp` "else" `exp`       : | "let" `size`* `pat` "=" `exp` "in" `exp`-      : | "let" `id` "[" `index` ("," `index`)* "]" "=" `exp` "in" `exp`-      : | "let" `id` `type_param`* `pat`+ [":" `type`] "=" `exp` "in" `exp`+      : | "let" `name` "[" `index` ("," `index`)* "]" "=" `exp` "in" `exp`+      : | "let" `name` `type_param`* `pat`+ [":" `type`] "=" `exp` "in" `exp`       : | "(" "\" `pat`+ [":" `type`] "->" `exp` ")"       : | "loop" `pat` ["=" `exp`] `loopform` "do" `exp`       : | "#[" `attr` "]" `exp`@@ -475,9 +495,9 @@       : | `exp` "with" `fieldid` ("." `fieldid`)* "=" `exp`       : | "match" `exp` ("case" `pat` "->" `exp`)+    field:   `fieldid` "=" `exp`-        : | `id`-   size : "[" `id` "]"-   pat:   `id`+        : | `name`+   size : "[" `name` "]"+   pat:   `name`       : | `pat_literal`       : | "_"       : | "(" ")"@@ -493,7 +513,7 @@               : | `charlit`               : | "true"               : | "false"-   loopform :   "for" `id` "<" `exp`+   loopform :   "for" `name` "<" `exp`             : | "for" `pat` "in" `exp`             : | "while" `exp`    index:   `exp` [":" [`exp`]] [":" [`exp`]]@@ -523,7 +543,7 @@ * A type ascription (``exp : type``) cannot appear as an array   index, as it conflicts with the syntax for slicing. -* In ``f [x]``, there is am ambiguity between indexing the array ``f``+* In ``f [x]``, there is an ambiguity between indexing the array ``f``   at position ``x``, or calling the function ``f`` with the singleton   array ``x``.  We resolve this the following way: @@ -536,17 +556,21 @@   enclosed in parentheses, rather than an operator section partially   applying the infix operator ``-``. -* Function and type application, and prefix operators, bind more-  tightly than any infix operator.  Note that the only prefix-  operators are the builtin ``!`` and ``-``, and more cannot be-  defined.  In particular, a user-defined operator beginning with-  ``!`` binds as ``!=``, as on the table below, not as the prefix+* Prefix operators bind more tighly than infix operators.  Note that+  the only prefix operators are the builtin ``!`` and ``-``, and more+  cannot be defined.  In particular, a user-defined operator beginning+  with ``!`` binds as ``!=``, as on the table below, not as the prefix   operator ``!`` +* Function and type application binds more tightly than infix+  operators.+ * ``#foo #bar`` is interpreted as a constructor with a ``#bar``   payload, not as applying ``#foo`` to ``#bar`` (the latter would be   semantically invalid anyway). +* `Attributes`_ bind less tightly than any other syntactic construct.+ * A type application ``pt [n]t`` is parsed as an application of the   type constructor ``pt`` to the size argument ``[n]`` and the type   ``t``.  To pass a single array-typed parameter, enclose it in@@ -564,7 +588,7 @@   =================  =============   left               ``,``   left               ``:``, ``:>``-  left               ```op```+  left               ```symbol```   left               ``||``   left               ``&&``   left               ``<=`` ``>=`` ``>`` ``<`` ``==`` ``!=`` ``!`` ``=``@@ -603,8 +627,8 @@  Evaluates to itself. -`qualid`-........+`qualname`+..........  A variable name; evaluates to its value in the current environment. @@ -812,9 +836,9 @@      Company any two values of numeric type for equality. -  ```op```+  ```symbol``` -    Use ``op``, which may be any non-operator function name, as an+    Use ``symbol``, which may be any non-operator function name, as an     infix operator.  ``x && y``@@ -1471,9 +1495,9 @@ -------  .. productionlist::-   mod_bind: "module" `id` `mod_param`* "=" [":" `mod_type_exp`] "=" `mod_exp`-   mod_param: "(" `id` ":" `mod_type_exp` ")"-   mod_type_bind: "module" "type" `id` "=" `mod_type_exp`+   mod_bind: "module" `name` `mod_param`* "=" [":" `mod_type_exp`] "=" `mod_exp`+   mod_param: "(" `name` ":" `mod_type_exp` ")"+   mod_type_bind: "module" "type" `name` "=" `mod_type_exp`  Futhark supports an ML-style higher-order module system.  *Modules* can contain types, functions, and other modules and module types.@@ -1515,7 +1539,7 @@ ~~~~~~~~~~~~~~~~~~  .. productionlist::-   mod_exp:   `qualid`+   mod_exp:   `qualname`           : | `mod_exp` ":" `mod_type_exp`           : | "\" "(" `mod_param`* ")" [":" `mod_type_exp`] "->" `mod_exp`           : | `mod_exp` `mod_exp`@@ -1527,8 +1551,8 @@ bindings produced by declarations (`dec`).  In particular, a module may contain other modules or module types. -``qualid``-..........+``qualname``+............  Evaluates to the module of the given name. @@ -1576,20 +1600,20 @@ ~~~~~~~~~~~~~~~~~~~~~~~  .. productionlist::-   mod_type_exp:   `qualid`+   mod_type_exp:   `qualname`              : | "{" `spec`* "}"-             : | `mod_type_exp` "with" `qualid` `type_param`* "=" `type`+             : | `mod_type_exp` "with" `qualname` `type_param`* "=" `type`              : | "(" `mod_type_exp` ")"-             : | "(" `id` ":" `mod_type_exp` ")" "->" `mod_type_exp`+             : | "(" `name` ":" `mod_type_exp` ")" "->" `mod_type_exp`              : | `mod_type_exp` "->" `mod_type_exp`   .. productionlist::-   spec:   "val" `id` `type_param`* ":" `type`-       : | "val" `binop` `type_param`* ":" `type`-       : | ("type" | "type^" | "type~") `id` `type_param`* "=" `type`-       : | ("type" | "type^" | "type~") `id` `type_param`*-       : | "module" `id` ":" `mod_type_exp`+   spec:   "val" `name` `type_param`* ":" `type`+       : | "val" `symbol` `type_param`* ":" `type`+       : | ("type" | "type^" | "type~") `name` `type_param`* "=" `type`+       : | ("type" | "type^" | "type~") `name` `type_param`*+       : | "module" `name` ":" `mod_type_exp`        : | "include" `mod_type_exp`        : | "#[" `attr` "]" `spec` @@ -1657,9 +1681,9 @@ ----------  .. productionlist::-   attr:   `id`+   attr:   `name`        : | `decimal`-       : | `id` "(" [`attr` ("," `attr`)*] ")"+       : | `name` "(" [`attr` ("," `attr`)*] ")"  An expression, declaration, pattern, or module type spec can be prefixed with an attribute, written as ``#[attr]``.  This may affect
futhark.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name:           futhark-version:        0.25.3+version:        0.25.4 synopsis:       An optimising compiler for a functional, array-oriented language.  description:    Futhark is a small programming language designed to be compiled to
src/Futhark/AD/Rev/Reduce.hs view
@@ -55,7 +55,7 @@       =<< eIf         first_elem         (resultBodyM $ scanNeutral scan)-        (eBody $ map (`eIndex` prev) res_incl)+        (eBody $ map (`eIndex` [prev]) res_incl)    letTupExp desc $ Op $ Screma w [iota] (mapSOAC lam) 
src/Futhark/AD/Rev/Scan.hs view
@@ -80,7 +80,7 @@         ( buildBody_ $ do             j <- letSubExp "j" =<< toExp (pe64 w - (le64 i + 1))             y_s <- forM ys_adj $ \y_ ->-              letSubExp (baseString y_ ++ "_j") =<< eIndex y_ (eSubExp j)+              letSubExp (baseString y_ ++ "_j") =<< eIndex y_ [eSubExp j]             let zso = orderArgs s y_s             let ido = orderArgs s $ case_jac k sc idmat             pure $ subExpsRes $ concat $ zipWith (++) zso $ fmap concat ido@@ -89,10 +89,10 @@             j <- letSubExp "j" =<< toExp (pe64 w - (le64 i + 1))             j1 <- letSubExp "j1" =<< toExp (pe64 w - le64 i)             y_s <- forM ys_adj $ \y_ ->-              letSubExp (baseString y_ ++ "_j") =<< eIndex y_ (eSubExp j)+              letSubExp (baseString y_ ++ "_j") =<< eIndex y_ [eSubExp j]              let args =-                  map (`eIndex` eSubExp j) ys ++ map (`eIndex` eSubExp j1) xs+                  map (`eIndex` [eSubExp j]) ys ++ map (`eIndex` [eSubExp j1]) xs             lam_rs <- traverse (`eLambda` args) lams              let yso = orderArgs s $ subExpsRes y_s@@ -171,7 +171,7 @@        dj <-         traverse-          (\dd -> letExp (baseString dd ++ "_dj") =<< eIndex dd (eSubExp j))+          (\dd -> letExp (baseString dd ++ "_dj") =<< eIndex dd [eSubExp j])           ds        fmap varsRes . letTupExp "scan_contribs"@@ -182,9 +182,8 @@               lam <- mkScanAdjointLam ops scan_lam WrtSecond $ fmap Var dj                im1 <- letSubExp "im1" =<< toExp (le64 i - 1)-              ys_im1 <- forM ys $ \y -> do-                y_t <- lookupType y-                letSubExp (baseString y ++ "_last") $ BasicOp $ Index y $ fullSlice y_t [DimFix im1]+              ys_im1 <- forM ys $ \y ->+                letSubExp (baseString y <> "_im1") =<< eIndex y [eSubExp im1]                let args = map eSubExp $ ys_im1 ++ map (Var . paramName) par_x               eLambda lam args@@ -341,5 +340,5 @@       mkLambda [par_i] $ do         a <-           letExp "ys_bar_rev"-            =<< eIndex arr (toExp (pe64 n - le64 (paramName par_i) - 1))+            =<< eIndex arr [toExp (pe64 n - le64 (paramName par_i) - 1)]         pure [varRes a]
src/Futhark/Analysis/SymbolTable.hs view
@@ -403,7 +403,7 @@   [LetBoundEntry rep] bindingEntries stm@(Let pat _ _) vtable = do   pat_elem <- patElems pat-  pure $ defBndEntry vtable pat_elem (Aliases.aliasesOf pat_elem) stm+  pure $ defBndEntry vtable pat_elem (expandAliases (Aliases.aliasesOf pat_elem) vtable) stm  adjustSeveral :: (Ord k) => (v -> v) -> [k] -> M.Map k v -> M.Map k v adjustSeveral f = flip $ foldl' $ flip $ M.adjust f@@ -449,35 +449,36 @@   SymbolTable rep insertStm stm vtable =   flip (foldl' $ flip consume) (namesToList stm_consumed) $-    flip (foldl' addRevAliases) (patElems $ stmPat stm) $-      insertEntries (zip names $ map LetBound $ bindingEntries stm vtable) vtable+    flip (foldl' addRevAliases) (zip names entries) $+      insertEntries (zip names $ map LetBound entries) vtable   where+    entries = bindingEntries stm vtable     names = patNames $ stmPat stm     stm_consumed = expandAliases (Aliases.consumedInStm stm) vtable-    addRevAliases vtable' pe =+    addRevAliases vtable' (name, LetBoundEntry {letBoundAliases = als}) =       vtable' {bindings = adjustSeveral update inedges $ bindings vtable'}       where-        inedges = namesToList $ expandAliases (Aliases.aliasesOf pe) vtable'+        inedges = namesToList $ expandAliases als vtable'         update e = e {entryType = update' $ entryType e}         update' (LetBound entry) =           LetBound             entry-              { letBoundAliases = oneName (patElemName pe) <> letBoundAliases entry+              { letBoundAliases = oneName name <> letBoundAliases entry               }         update' (FParam entry) =           FParam             entry-              { fparamAliases = oneName (patElemName pe) <> fparamAliases entry+              { fparamAliases = oneName name <> fparamAliases entry               }         update' (LParam entry) =           LParam             entry-              { lparamAliases = oneName (patElemName pe) <> lparamAliases entry+              { lparamAliases = oneName name <> lparamAliases entry               }         update' (FreeVar entry) =           FreeVar             entry-              { freeVarAliases = oneName (patElemName pe) <> freeVarAliases entry+              { freeVarAliases = oneName name <> freeVarAliases entry               }         update' e = e 
src/Futhark/Analysis/UsageTable.hs view
@@ -170,11 +170,7 @@  usageInExp :: (Aliased rep) => Exp rep -> UsageTable usageInExp (Apply _ args _ _) =-  mconcat-    [ mconcat $ map consumedUsage $ namesToList $ subExpAliases arg-      | (arg, d) <- args,-        d == Consume-    ]+  mconcat [consumedUsage v | (Var v, Consume) <- args] usageInExp e@Loop {} =   foldMap consumedUsage $ namesToList $ consumedInExp e usageInExp (Match _ cases defbody _) =
src/Futhark/CodeGen/Backends/GenericC.hs view
@@ -202,7 +202,7 @@     fprintf(ctx->log, "Allocating %lld bytes for %s in %s (currently allocated: %lld bytes).\n",             (long long) size,             desc, $string:spacedesc,-            ctx->$id:usagename);+            (long long) ctx->$id:usagename);   }    $items:alloc
src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs view
@@ -351,9 +351,9 @@          sIf (phys_tid .<. n) in_bounds out_of_bounds +    sOp $ Imp.ErrorSync Imp.FenceLocal     sComment "Transpose scan inputs" $ do       forM_ (zip transposedArrays privateArrays) $ \(trans, priv) -> do-        sOp localBarrier         sFor "i" m $ \i -> do           sharedIdx <-             dPrimVE "sharedIdx" $@@ -364,7 +364,7 @@         sFor "i" m $ \i -> do           sharedIdx <- dPrimV "sharedIdx" $ kernelLocalThreadId constants * m + i           copyDWIMFix priv [sExt64 i] (Var trans) [sExt64 $ tvExp sharedIdx]-    sOp $ Imp.ErrorSync Imp.FenceLocal+        sOp localBarrier      sComment "Per thread scan" $ do       -- We don't need to touch the first element, so only m-1
src/Futhark/Construct.hs view
@@ -417,12 +417,14 @@             BinOp LogOr less_than_zero greater_than_size   foldBinOp LogOr (constant False) =<< zipWithM checkDim ws is' --- | The array element at this index.-eIndex :: (MonadBuilder m) => VName -> m (Exp (Rep m)) -> m (Exp (Rep m))-eIndex arr i = do-  i' <- letSubExp "i" =<< i+-- | The array element at this index.  Returns array unmodified if+-- indexes are null (does not even need to be an array in that case).+eIndex :: (MonadBuilder m) => VName -> [m (Exp (Rep m))] -> m (Exp (Rep m))+eIndex arr [] = eSubExp $ Var arr+eIndex arr is = do+  is' <- mapM (letSubExp "i" =<<) is   arr_t <- lookupType arr-  pure $ BasicOp $ Index arr $ fullSlice arr_t [DimFix i']+  pure $ BasicOp $ Index arr $ fullSlice arr_t $ map DimFix is'  -- | The last element of the given array. eLast :: (MonadBuilder m) => VName -> m (Exp (Rep m))@@ -431,7 +433,7 @@   nm1 <-     letSubExp "nm1" . BasicOp $       BinOp (Sub Int64 OverflowUndef) n (intConst Int64 1)-  eIndex arr (eSubExp nm1)+  eIndex arr [eSubExp nm1]  -- | Construct an unspecified value of the given type. eBlank :: (MonadBuilder m) => Type -> m (Exp (Rep m))
src/Futhark/IR/Mem.hs view
@@ -594,7 +594,7 @@               TC.bad . TC.TypeError $                 "Array "                   <> prettyText v-                  <> " returned by function, but has nontrivial index function "+                  <> " returned by function, but has nontrivial index function:\n"                   <> prettyText ixfun  matchLoopResultMem ::
src/Futhark/IR/Mem/IxFun.hs view
@@ -234,7 +234,7 @@ expand ::   (Eq num, IntegralExp num) => num -> num -> IxFun num -> Maybe (IxFun num) expand o p (IxFun lmad base) =-  let onDim ld = ld {LMAD.ldStride = LMAD.ldStride ld * p}+  let onDim ld = ld {LMAD.ldStride = p * LMAD.ldStride ld}       lmad' =         LMAD           (o + p * LMAD.offset lmad)
src/Futhark/IR/Mem/LMAD.hs view
@@ -223,17 +223,14 @@  -- Then the general case. reshape lmad@(LMAD off dims) newshape = do-  let mid_dims = take (length dims) dims+  let base_stride = ldStride (last dims)+      no_zero_stride = all (\ld -> ldStride ld /= 0) dims+      strides_as_expected = lmad == iotaStrided off base_stride (shape lmad) -  guard $-    -- checking conditions (2)-    all (\(LMADDim s _) -> s /= 0) mid_dims-      && all-        (\(ld, se) -> ldStride ld == se)-        (zip dims (reverse $ scanl (*) 1 (reverse (tail (shape lmad)))))+  guard $ no_zero_stride && strides_as_expected -  let LMAD off' dims_sup = iota off newshape-  Just $ LMAD off' dims_sup+  Just $ iotaStrided off base_stride newshape+{-# NOINLINE reshape #-}  -- | Substitute a name with a PrimExp in an LMAD. substituteInLMAD ::@@ -255,6 +252,19 @@ rank :: LMAD num -> Int rank = length . shape +iotaStrided ::+  (IntegralExp num) =>+  -- | Offset+  num ->+  -- | Base Stride+  num ->+  -- | Shape+  [num] ->+  LMAD num+iotaStrided off s ns =+  let ss = tail $ reverse $ scanl (*) s $ reverse ns+   in LMAD off $ zipWith LMADDim ss ns+ -- | Generalised iota with user-specified offset. iota ::   (IntegralExp num) =>@@ -263,10 +273,8 @@   -- | Shape   [num] ->   LMAD num-iota off ns =-  let rk = length ns-      ss = reverse $ take rk $ scanl (*) 1 $ reverse ns-   in LMAD off $ zipWith LMADDim ss ns+iota off = iotaStrided off 1+{-# NOINLINE iota #-}  -- | Create an LMAD that is existential in everything. mkExistential :: Int -> Int -> LMAD (Ext a)@@ -517,6 +525,7 @@       ((.&&.) . uncurry dynamicEqualsLMADDim)       true       (zip (dims lmad1) (dims lmad2))+{-# NOINLINE dynamicEqualsLMAD #-}  -- | Returns true if two 'LMAD's are equivalent. --@@ -526,10 +535,9 @@   length (dims lmad1) == length (dims lmad2)     && offset lmad1 == offset lmad2     && map ldStride (dims lmad1) == map ldStride (dims lmad2)+{-# NOINLINE equivalent #-} --- | Is this is a row-major array?+-- | Is this is a row-major array with zero offset? isDirect :: (Eq num, IntegralExp num) => LMAD num -> Bool-isDirect (LMAD offset dims) =-  let strides_expected = reverse $ scanl (*) 1 $ reverse $ tail $ map ldShape dims-   in offset == 0-        && and (zipWith (==) (map ldStride dims) strides_expected)+isDirect lmad = lmad == iota 0 (map ldShape $ dims lmad)+{-# NOINLINE isDirect #-}
src/Futhark/IR/SOACS/Simplify.hs view
@@ -627,7 +627,7 @@       Simplify $ foldClosedForm (`ST.lookupExp` vtable) pat red_fun nes arrs simplifyClosedFormReduce _ _ _ _ = Skip --- For now we just remove singleton SOACs.+-- For now we just remove singleton SOACs and those with unroll attributes. simplifyKnownIterationSOAC ::   (Buildable rep, BuilderOps rep, HasSOAC rep) =>   TopDownRuleOp rep@@ -685,6 +685,19 @@        forM_ (zip (patNames pat) res) $ \(v, SubExpRes cs se) ->         certifying cs $ letBindNames [v] $ BasicOp $ SubExp se+--+simplifyKnownIterationSOAC _ pat aux op+  | Just (Screma (Constant (IntValue (Int64Value k))) arrs (ScremaForm [] [] map_lam)) <- asSOAC op,+    "unroll" `inAttrs` stmAuxAttrs aux = Simplify $ do+      arrs_elems <- fmap transpose . forM [0 .. k - 1] $ \i -> do+        map_lam' <- renameLambda map_lam+        eLambda map_lam' $ map (`eIndex` [eSubExp (constant i)]) arrs+      forM_ (zip3 (patNames pat) arrs_elems (lambdaReturnType map_lam)) $+        \(v, arr_elems, t) ->+          certifying (mconcat (map resCerts arr_elems)) $+            letBindNames [v] . BasicOp $+              ArrayLit (map resSubExp arr_elems) t+-- simplifyKnownIterationSOAC _ _ _ _ = Skip  data ArrayOp@@ -737,9 +750,11 @@   S.Set (Pat (LetDec rep), ArrayOp) arrayOps cs = mconcat . map onStm . stmsToList . bodyStms   where-    -- It is not safe to move everything out of branches (#1874);-    -- probably we need to put some more intelligence in here somehow.+    -- It is not safe to move everything out of branches (#1874) or+    -- loops (#2015); probably we need to put some more intelligence+    -- in here somehow.     onStm (Let _ _ Match {}) = mempty+    onStm (Let _ _ Loop {}) = mempty     onStm (Let pat aux e) =       case isArrayOp (cs <> stmAuxCerts aux) e of         Just op -> S.singleton (pat, op)
src/Futhark/IR/SegOp.hs view
@@ -1342,7 +1342,7 @@   Rule rep -- Some SegOp results can be moved outside the SegOp, which can -- simplify further analysis.-bottomUpSegOp (vtable, used) (Pat kpes) dec segop = Simplify $ do+bottomUpSegOp (vtable, _used) (Pat kpes) dec segop = Simplify $ do   -- Iterate through the bindings.  For each, we check whether it is   -- in kres and can be moved outside.  If so, we remove it from kres   -- and kpes and make it a binding outside.  We have to be careful@@ -1353,20 +1353,16 @@     localScope (scopeOfSegSpace space) $       foldM distribute (kpes, kts, kres, mempty) kstms -  when-    (kpes' == kpes)-    cannotSimplify+  when (kpes' == kpes) cannotSimplify    kbody' <--    localScope (scopeOfSegSpace space) $-      mkKernelBodyM kstms' kres'+    localScope (scopeOfSegSpace space) $ mkKernelBodyM kstms' kres'    addStm $ Let (Pat kpes') dec $ Op $ segOp $ mk_segop kts' kbody'   where-    (kts, kbody@(KernelBody _ kstms kres), num_nonmap_results, mk_segop) =+    (kts, KernelBody _ kstms kres, num_nonmap_results, mk_segop) =       segOpGuts segop     free_in_kstms = foldMap freeIn kstms-    consumed_in_segop = consumedInKernelBody kbody     space = segSpace segop      sliceWithGtidsFixed stm@@ -1395,13 +1391,9 @@                 letBindNames [patElemName kpe'] . BasicOp . Index arr $                   Slice $                     outer_slice <> remaining_slice-          if (patElemName kpe `UT.isConsumed` used)-            || (arr `nameIn` consumed_in_segop)-            then do-              precopy <- newVName $ baseString (patElemName kpe) <> "_precopy"-              index kpe {patElemName = precopy}-              letBindNames [patElemName kpe] $ BasicOp $ Replicate mempty $ Var precopy-            else index kpe+          precopy <- newVName $ baseString (patElemName kpe) <> "_precopy"+          index kpe {patElemName = precopy}+          letBindNames [patElemName kpe] $ BasicOp $ Replicate mempty $ Var precopy           pure             ( kpes'',               kts'',
src/Futhark/Internalise/Monomorphise.hs view
@@ -889,7 +889,8 @@         Just rexp -> onExps bound (unReplaced rexp) e         Nothing -> pure ()     onExps bound e (Var v _ _)-      | Just rexp <- lookup (qualLeaf v) named2 = onExps bound e (unReplaced rexp)+      | Just rexp <- lookup (qualLeaf v) named2 =+          onExps bound e (unReplaced rexp)     onExps bound e1 e2       | Just es <- similarExps e1 e2 =           mapM_ (uncurry $ onExps bound) es
src/Futhark/Optimise/TileLoops.hs view
@@ -473,7 +473,8 @@     lambdaReturnType map_lam == lambdaReturnType red_lam, -- No mapout arrays.     not $ null arrs,     all primType $ lambdaReturnType map_lam,-    all (primType . paramType) $ lambdaParams map_lam =+    all (primType . paramType) $ lambdaParams map_lam,+    not $ "unroll" `inAttrs` stmAuxAttrs (stmAux stm) =       Just (w, arrs, (red_comm, red_lam, red_nes, map_lam))   | otherwise =       Nothing
src/Futhark/Optimise/Unstream.hs view
@@ -137,11 +137,9 @@   pure [Let pat aux $ Op $ ParOp par_op' op'] onMCOp stage pat aux (MC.OtherOp soac)   | sequentialise stage soac = do-      stms <- runBuilder_ $ FOT.transformSOAC pat soac-      fmap concat $-        localScope (scopeOf stms) $-          mapM (optimiseStm (onMCOp stage)) $-            stmsToList stms+      stms <- runBuilder_ $ auxing aux $ FOT.transformSOAC pat soac+      fmap concat . localScope (scopeOf stms) $+        mapM (optimiseStm (onMCOp stage)) (stmsToList stms)   | otherwise =       -- Still sequentialise whatever's inside.       pure <$> (Let pat aux . Op . MC.OtherOp <$> mapSOACM optimise soac)@@ -159,11 +157,9 @@ onHostOp :: Stage -> OnOp GPU onHostOp stage pat aux (GPU.OtherOp soac)   | sequentialise stage soac = do-      stms <- runBuilder_ $ FOT.transformSOAC pat soac-      fmap concat $-        localScope (scopeOf stms) $-          mapM (optimiseStm (onHostOp stage)) $-            stmsToList stms+      stms <- runBuilder_ $ auxing aux $ FOT.transformSOAC pat soac+      fmap concat . localScope (scopeOf stms) $+        mapM (optimiseStm (onHostOp stage)) (stmsToList stms)   | otherwise =       -- Still sequentialise whatever's inside.       pure <$> (Let pat aux . Op . GPU.OtherOp <$> mapSOACM optimise soac)
src/Futhark/Pass/ExtractKernels/DistributeNests.hs view
@@ -566,23 +566,39 @@   scope <- asksScope scopeForSOACs   distributeMapBodyStms acc . fmap (certify cs) . snd     =<< runBuilderT (dissectScrema pat w form arrs) scope-maybeDistributeStm (Let pat aux (BasicOp (Replicate (Shape (d : ds)) v))) acc-  | [t] <- patTypes pat = do-      tmp <- newVName "tmp"-      let rowt = rowType t-          newstm = Let pat aux $ Op $ Screma d [] $ mapSOAC lam-          tmpstm =-            Let (Pat [PatElem tmp rowt]) aux $ BasicOp $ Replicate (Shape ds) v-          lam =-            Lambda-              { lambdaReturnType = [rowt],-                lambdaParams = [],-                lambdaBody = mkBody (oneStm tmpstm) [varRes tmp]-              }-      maybeDistributeStm newstm acc-maybeDistributeStm stm@(Let _ aux (BasicOp (Replicate (Shape []) (Var stm_arr)))) acc =-  distributeSingleUnaryStm acc stm stm_arr $ \_ outerpat arr ->-    pure $ oneStm $ Let outerpat aux $ BasicOp $ Replicate mempty $ Var arr+maybeDistributeStm stm@(Let _ aux (BasicOp (Replicate shape (Var stm_arr)))) acc = do+  distributeSingleUnaryStm acc stm stm_arr $ \nest outerpat arr ->+    if shape == mempty+      then pure $ oneStm $ Let outerpat aux $ BasicOp $ Replicate mempty $ Var arr+      else runBuilder_ $ auxing aux $ do+        arr_t <- lookupType arr+        let arr_r = arrayRank arr_t+            nest_r = length (snd nest) + 1+            res_r = arr_r + shapeRank shape+        -- Move the to-be-replicated dimensions outermost.+        arr_tr <-+          letExp (baseString arr <> "_tr") . BasicOp $+            Rearrange ([nest_r .. arr_r - 1] ++ [0 .. nest_r - 1]) arr+        -- Replicate the now-outermost dimensions appropriately.+        arr_tr_rep <-+          letExp (baseString arr <> "_tr_rep") . BasicOp $+            Replicate shape (Var arr_tr)+        -- Move the replicated dimensions back where they belong.+        letBind outerpat . BasicOp $+          Rearrange ([res_r - nest_r .. res_r - 1] ++ [0 .. res_r - nest_r - 1]) arr_tr_rep+maybeDistributeStm (Let (Pat [pe]) aux (BasicOp (Replicate (Shape (d : ds)) v))) acc = do+  tmp <- newVName "tmp"+  let rowt = rowType $ patElemType pe+      newstm = Let (Pat [pe]) aux $ Op $ Screma d [] $ mapSOAC lam+      tmpstm =+        Let (Pat [PatElem tmp rowt]) aux $ BasicOp $ Replicate (Shape ds) v+      lam =+        Lambda+          { lambdaReturnType = [rowt],+            lambdaParams = [],+            lambdaBody = mkBody (oneStm tmpstm) [varRes tmp]+          }+  maybeDistributeStm newstm acc -- Opaques are applied to the full array, because otherwise they can -- drastically inhibit parallelisation in some cases. maybeDistributeStm stm@(Let (Pat [pe]) aux (BasicOp (Opaque _ (Var stm_arr)))) acc@@ -648,10 +664,9 @@     Just (kernels, res, nest, acc')       | map resSubExp res == map Var (patNames $ stmPat stm),         (outer, _) <- nest,-        [(arr_p, arr)] <- loopNestingParamsAndArrs outer,-        boundInKernelNest nest-          `namesIntersection` freeIn stm-          == oneName (paramName arr_p),+        [(_, arr)] <- loopNestingParamsAndArrs outer,+        boundInKernelNest nest `namesIntersection` freeIn stm+          == oneName stm_arr,         perfectlyMapped arr nest -> do           addPostStms kernels           let outerpat = loopNestingPat $ fst nest@@ -842,12 +857,8 @@   ((res_t, res), kstms) <- runBuilder $ do     -- Compute indexes into full array.     v' <--      certifying cs $-        letSubExp "v" $-          BasicOp $-            Index v $-              Slice $-                map (DimFix . Var) slice_gtids+      certifying cs . letSubExp "v" . BasicOp . Index v $+        Slice (map (DimFix . Var) slice_gtids)     slice_is <-       traverse (toSubExp "index") $         fixSlice (fmap pe64 slice) $
src/Language/Futhark/Prop.hs view
@@ -199,7 +199,7 @@     go bound b (Scalar (Record fields)) =       Scalar . Record <$> traverse (go bound b) fields     go bound b (Scalar (TypeVar as tn targs)) =-      Scalar <$> (TypeVar as tn <$> traverse (onTypeArg bound b) targs)+      Scalar <$> (TypeVar as tn <$> traverse (onTypeArg tn bound b) targs)     go bound b (Scalar (Sum cs)) =       Scalar . Sum <$> traverse (traverse (go bound b)) cs     go _ _ (Scalar (Prim t)) =@@ -213,10 +213,15 @@               Named p' -> S.insert p' bound               Unnamed -> bound -    onTypeArg bound b (TypeArgDim d) =+    onTypeArg _ bound b (TypeArgDim d) =       TypeArgDim <$> f bound b d-    onTypeArg bound b (TypeArgType t) =-      TypeArgType <$> go bound b t+    onTypeArg tn bound b (TypeArgType t) =+      TypeArgType <$> go bound b' t+      where+        b' =+          if qualLeaf tn == fst intrinsicAcc+            then b+            else PosParam  -- | Return the uniqueness of a type. uniqueness :: TypeBase shape Uniqueness -> Uniqueness@@ -411,7 +416,8 @@               <$> zipWithM (matchTypeArg bound) targs1 targs2         _ -> pure t1 -    matchTypeArg _ ta@TypeArgType {} _ = pure ta+    matchTypeArg bound (TypeArgType t1) (TypeArgType t2) =+      TypeArgType <$> matchDims' bound t1 t2     matchTypeArg bound (TypeArgDim x) (TypeArgDim y) =       TypeArgDim <$> onDims bound x y     matchTypeArg _ a _ = pure a
src/Language/Futhark/TypeChecker/Terms.hs view
@@ -986,10 +986,15 @@ dimUses :: TypeBase Size u -> (Names, Names) dimUses = flip execState mempty . traverseDims f   where-    f bound _ (Var v _ _) | qualLeaf v `S.member` bound = pure ()-    f _ PosImmediate (Var v _ _) = modify ((S.singleton (qualLeaf v), mempty) <>)-    f _ PosParam (Var v _ _) = modify ((mempty, S.singleton (qualLeaf v)) <>)-    f _ _ _ = pure ()+    f bound pos e =+      case pos of+        PosImmediate ->+          modify ((fvVars fv, mempty) <>)+        PosParam ->+          modify ((mempty, fvVars fv) <>)+        PosReturn -> pure ()+      where+        fv = freeInExp e `freeWithout` bound  checkApply ::   SrcLoc ->@@ -1007,7 +1012,7 @@     argtype' <- normTypeFully argtype      -- Check whether this would produce an impossible return type.-    let (tp2_produced_dims, tp2_paramdims) = dimUses $ toStruct tp2'+    let (tp2_produced_dims, tp2_paramdims) = dimUses tp2'         problematic = S.fromList ext <> boundInsideType argtype'         problem = any (`S.member` problematic) (tp2_paramdims `S.difference` tp2_produced_dims)     when (not (S.null problematic) && problem) $ do
unittests/Futhark/IR/Mem/IxFunTests.hs view
@@ -120,6 +120,7 @@         test_reshape_permute_iota,         test_slice_reshape_iota2,         test_reshape_slice_iota3,+        test_flatten_strided,         test_complex1,         test_complex2,         test_expand1,@@ -198,6 +199,14 @@               DimSlice 0 n 1             ]      in reshape (slice (iota [n, n, n, n]) slc) newdims++-- Tests flattening something that is strided - this can occur after+-- memory expansion.+test_flatten_strided :: [TestTree]+test_flatten_strided =+  singleton . testCase "reshape . fix . iota 3d" . compareOps $+    let slc = Slice [DimSlice 0 n 1, DimSlice 0 2 1, DimFix 1]+     in reshape (slice (iota [n, 2, n * n]) slc) [2 * 10]  test_complex1 :: [TestTree] test_complex1 =