diff --git a/mlir/docs/Dialects/Affine.md b/mlir/docs/Dialects/Affine.md --- a/mlir/docs/Dialects/Affine.md +++ b/mlir/docs/Dialects/Affine.md @@ -67,7 +67,7 @@ latter), 3. a value that dominates the `AffineScope` op enclosing the value's use, 4. the result of a constant operation, 5. the result of an -[`affine.apply` operation](#affineapply-affineapplyop) that recursively takes as +[`affine.apply` operation](#affineapply-mliraffineapplyop) that recursively takes as arguments any valid symbolic identifiers, or 6. the result of a [`dim` operation](MemRef.md/#memrefdim-mlirmemrefdimop) on either a memref that is an argument to a `AffineScope` op or a memref where the corresponding @@ -78,9 +78,9 @@ Note that as a result of rule (3) above, symbol validity is sensitive to the location of the SSA use. Dimensions may be bound not only to anything that a symbol is bound to, but also to induction variables of enclosing -[`affine.for`](#affinefor-affineforop) and -[`affine.parallel`](#affineparallel-affineparallelop) operations, and the result -of an [`affine.apply` operation](#affineapply-affineapplyop) (which recursively +[`affine.for`](#affinefor-mliraffineforop) and +[`affine.parallel`](#affineparallel-mliraffineparallelop) operations, and the result +of an [`affine.apply` operation](#affineapply-mliraffineapplyop) (which recursively may use other dimensions and symbols). ### Affine Expressions @@ -155,9 +155,9 @@ combining the indices and symbols. Affine maps distinguish between [indices and symbols](#dimensions-and-symbols) because indices are inputs to the affine map when the map is called (through an operation such as -[affine.apply](#affineapply-affineapplyop)), whereas symbols are bound when the +[affine.apply](#affineapply-mliraffineapplyop)), whereas symbols are bound when the map is established (e.g. when a memref is formed, establishing a memory -[layout map](Builtin.md/#layout-map)). +[layout map](Builtin.md/#layout)). Affine maps are used for various core structures in MLIR. The restrictions we impose on their form allows powerful analysis and transformation, while keeping @@ -306,67 +306,7 @@ [include "Dialects/AffineOps.md"] -### 'affine.load' operation - -Syntax: - -``` -operation ::= ssa-id `=` `affine.load` ssa-use `[` multi-dim-affine-map-of-ssa-ids `]` `:` memref-type -``` - -The `affine.load` op reads an element from a memref, where the index for each -memref dimension is an affine expression of loop induction variables and -symbols. The output of 'affine.load' is a new value with the same type as the -elements of the memref. An affine expression of loop IVs and symbols must be -specified for each dimension of the memref. The keyword 'symbol' can be used to -indicate SSA identifiers which are symbolic. - -Example: - -```mlir - - Example 1: - - %1 = affine.load %0[%i0 + 3, %i1 + 7] : memref<100x100xf32> - - Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'. - - %1 = affine.load %0[%i0 + symbol(%n), %i1 + symbol(%m)] - : memref<100x100xf32> - -``` - -### 'affine.store' operation - -Syntax: - -``` -operation ::= ssa-id `=` `affine.store` ssa-use, ssa-use `[` multi-dim-affine-map-of-ssa-ids `]` `:` memref-type -``` - -The `affine.store` op writes an element to a memref, where the index for each -memref dimension is an affine expression of loop induction variables and -symbols. The 'affine.store' op stores a new value which is the same type as the -elements of the memref. An affine expression of loop IVs and symbols must be -specified for each dimension of the memref. The keyword 'symbol' can be used to -indicate SSA identifiers which are symbolic. - -Example: - -```mlir - - Example 1: - - affine.store %v0, %0[%i0 + 3, %i1 + 7] : memref<100x100xf32> - - Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'. - - affine.store %v0, %0[%i0 + symbol(%n), %i1 + symbol(%m)] - : memref<100x100xf32> - -``` - -### 'affine.dma_start' operation +### `affine.dma_start` (mlir::AffineDmaStartOp) Syntax: @@ -392,29 +332,34 @@ should be specified. The value of 'num_elements' must be a multiple of 'number_of_elements_per_stride'. -Example: +Example 1: + +For example, a `DmaStartOp` operation that transfers 256 elements of a memref +`%src` in memory space 0 at indices `[%i + 3, %j]` to memref `%dst` in memory +space 1 at indices `[%k + 7, %l]`, would be specified as follows: + + +```mlir +%num_elements = arith.constant 256 +%idx = arith.constant 0 : index +%tag = memref.alloc() : memref<1xi32, 4> +affine.dma_start %src[%i + 3, %j], %dst[%k + 7, %l], %tag[%idx], + %num_elements : + memref<40x128xf32, 0>, memref<2x1024xf32, 1>, memref<1xi32, 2> +``` + +Example 2: + +If `%stride` and `%num_elt_per_stride` are specified, the DMA is expected to +transfer `%num_elt_per_stride` elements every `%stride elements` apart from +memory space 0 until `%num_elements` are transferred. ```mlir -For example, a DmaStartOp operation that transfers 256 elements of a memref -'%src' in memory space 0 at indices [%i + 3, %j] to memref '%dst' in memory -space 1 at indices [%k + 7, %l], would be specified as follows: - - %num_elements = arith.constant 256 - %idx = arith.constant 0 : index - %tag = memref.alloc() : memref<1xi32, 4> - affine.dma_start %src[%i + 3, %j], %dst[%k + 7, %l], %tag[%idx], - %num_elements : - memref<40x128xf32, 0>, memref<2x1024xf32, 1>, memref<1xi32, 2> - - If %stride and %num_elt_per_stride are specified, the DMA is expected to - transfer %num_elt_per_stride elements every %stride elements apart from - memory space 0 until %num_elements are transferred. - - affine.dma_start %src[%i, %j], %dst[%k, %l], %tag[%idx], %num_elements, - %stride, %num_elt_per_stride : ... +affine.dma_start %src[%i, %j], %dst[%k, %l], %tag[%idx], %num_elements, + %stride, %num_elt_per_stride : ... ``` -### 'affine.dma_wait' operation +### `affine.dma_wait` (mlir::AffineDmaWaitOp) Syntax: @@ -423,11 +368,11 @@ ``` The `affine.dma_start` op blocks until the completion of a DMA operation -associated with the tag element '%tag[%index]'. %tag is a memref, and %index has +associated with the tag element `%tag[%index]`. `%tag` is a memref, and `%index` has to be an index with the same restrictions as any load/store index. In particular, index for each memref dimension must be an affine expression of loop -induction variables and symbols. %num_elements is the number of elements -associated with the DMA operation. For example: +induction variables and symbols. `%num_elements` is the number of elements +associated with the DMA operation. Example: diff --git a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td --- a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td +++ b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td @@ -38,7 +38,7 @@ def AffineApplyOp : Affine_Op<"apply", [Pure]> { let summary = "affine apply operation"; let description = [{ - The affine.apply operation applies an [affine mapping](#affine-expressions) + The `affine.apply` operation applies an [affine mapping](#affine-maps) to a list of SSA values, yielding a single SSA value. The number of dimension and symbol arguments to `affine.apply` must be equal to the respective number of dimensional and symbolic inputs to the affine mapping; @@ -127,7 +127,7 @@ The `affine.for` operation represents an affine loop nest. It has one region containing its body. This region must contain one block that terminates with - [`affine.yield`](#affineyield-affineyieldop). *Note:* when + [`affine.yield`](#affineyield-mliraffineyieldop). *Note:* when `affine.for` is printed in custom format, the terminator is omitted. The block has one argument of [`index`](Builtin.md/#indextype) type that represents the induction variable of the loop. @@ -506,12 +506,18 @@ def AffineLoadOp : AffineLoadOpBase<"load"> { let summary = "affine load operation"; let description = [{ - The "affine.load" op reads an element from a memref, where the index + Syntax: + + ``` + operation ::= ssa-id `=` `affine.load` ssa-use `[` multi-dim-affine-map-of-ssa-ids `]` `:` memref-type + ``` + + The `affine.load` op reads an element from a memref, where the index for each memref dimension is an affine expression of loop induction - variables and symbols. The output of 'affine.load' is a new value with the + variables and symbols. The output of `affine.load` is a new value with the same type as the elements of the memref. An affine expression of loop IVs and symbols must be specified for each dimension of the memref. The keyword - 'symbol' can be used to indicate SSA identifiers which are symbolic. + `symbol` can be used to indicate SSA identifiers which are symbolic. Example 1: @@ -519,7 +525,7 @@ %1 = affine.load %0[%i0 + 3, %i1 + 7] : memref<100x100xf32> ``` - Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'. + Example 2: Uses `symbol` keyword for symbols `%n` and `%m`. ```mlir %1 = affine.load %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32> @@ -604,7 +610,7 @@ def AffineMaxOp : AffineMinMaxOpBase<"max", [Pure]> { let summary = "max operation"; let description = [{ - The "max" operation computes the maximum value result from a multi-result + The `affine.max` operation computes the maximum value result from a multi-result affine map. Example: @@ -621,7 +627,7 @@ MemRefsNormalizable]> { let summary = "multi-index parallel band operation"; let description = [{ - The "affine.parallel" operation represents a hyper-rectangular affine + The `affine.parallel` operation represents a hyper-rectangular affine parallel band, defining zero or more SSA values for its induction variables. It has one region capturing the parallel band body. The induction variables are represented as arguments of this region. These SSA values always have @@ -629,7 +635,7 @@ by steps, are positive constant integers which defaults to "1" if not present. The lower and upper bounds specify a half-open range: the range includes the lower bound but does not include the upper bound. The body - region must contain exactly one block that terminates with "affine.yield". + region must contain exactly one block that terminates with `affine.yield`. The lower and upper bounds of a parallel operation are represented as an application of an affine mapping to a list of SSA values passed to the map. @@ -642,14 +648,14 @@ max(min) of these values obtained from these expressions. The loop band has as many loops as elements in the group bounds attributes. - Each value yielded by affine.yield will be accumulated/reduced via one of + Each value yielded by `affine.yield` will be accumulated/reduced via one of the reduction methods defined in the AtomicRMWKind enum. The order of reduction is unspecified, and lowering may produce any valid ordering. Loops with a 0 trip count will produce as a result the identity value associated with each reduction (i.e. 0.0 for addf, 1.0 for mulf). Assign reductions for loops with a trip count != 1 produces undefined results. - Note: Calling AffineParallelOp::build will create the required region and + Note: Calling `AffineParallelOp::build` will create the required region and block, and insert the required terminator if it is trivial (i.e. no values are yielded). Parsing will also create the required region, block, and terminator, even when they are missing from the textual representation. @@ -764,7 +770,7 @@ [DeclareOpInterfaceMethods]> { let summary = "affine prefetch operation"; let description = [{ - The "affine.prefetch" op prefetches data from a memref location described + The `affine.prefetch` op prefetches data from a memref location described with an affine subscript similar to affine.load, and has three attributes: a read/write specifier, a locality hint, and a cache type specifier as shown below: @@ -867,12 +873,18 @@ def AffineStoreOp : AffineStoreOpBase<"store"> { let summary = "affine store operation"; let description = [{ - The "affine.store" op writes an element to a memref, where the index + Syntax: + + ``` + operation ::= `affine.store` ssa-use, ssa-use `[` multi-dim-affine-map-of-ssa-ids `]` `:` memref-type + ``` + + The `affine.store` op writes an element to a memref, where the index for each memref dimension is an affine expression of loop induction - variables and symbols. The 'affine.store' op stores a new value which is the + variables and symbols. The `affine.store` op stores a new value which is the same type as the elements of the memref. An affine expression of loop IVs and symbols must be specified for each dimension of the memref. The keyword - 'symbol' can be used to indicate SSA identifiers which are symbolic. + `symbol` can be used to indicate SSA identifiers which are symbolic. Example 1: @@ -880,7 +892,7 @@ affine.store %v0, %0[%i0 + 3, %i1 + 7] : memref<100x100xf32> ``` - Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'. + Example 2: Uses `symbol` keyword for symbols `%n` and `%m`. ```mlir affine.store %v0, %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32> @@ -911,16 +923,15 @@ MemRefsNormalizable]> { let summary = "Yield values to parent operation"; let description = [{ - "affine.yield" yields zero or more SSA values from an affine op region and + The `affine.yield` yields zero or more SSA values from an affine op region and terminates the region. The semantics of how the values yielded are used is defined by the parent operation. - If "affine.yield" has any operands, the operands must match the parent + If `affine.yield` has any operands, the operands must match the parent operation's results. - If the parent operation defines no values, then the "affine.yield" may be + If the parent operation defines no values, then the `affine.yield` may be left out in the custom syntax and the builders will insert one implicitly. Otherwise, it has to be present in the syntax to indicate which values are yielded. - ``` }]; let arguments = (ins Variadic:$operands); @@ -936,8 +947,8 @@ def AffineVectorLoadOp : AffineLoadOpBase<"vector_load"> { let summary = "affine vector load operation"; let description = [{ - The "affine.vector_load" is the vector counterpart of - [affine.load](#affineload-affineloadop). It reads a slice from a + The `affine.vector_load` is the vector counterpart of + [affine.load](#affineload-mliraffineloadop). It reads a slice from a [MemRef](Builtin.md/#memreftype), supplied as its first operand, into a [vector](Builtin.md/#vectortype) of the same base elemental type. The index for each memref dimension is an affine expression of loop induction @@ -946,7 +957,7 @@ the slice read from the memref. This slice is contiguous along the respective dimensions of the shape. Strided vector loads will be supported in the future. An affine expression of loop IVs and symbols must be specified for each - dimension of the memref. The keyword 'symbol' can be used to indicate SSA + dimension of the memref. The keyword `symbol` can be used to indicate SSA identifiers which are symbolic. Example 1: 8-wide f32 vector load. @@ -955,7 +966,7 @@ %1 = affine.vector_load %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>, vector<8xf32> ``` - Example 2: 4-wide f32 vector load. Uses 'symbol' keyword for symbols '%n' and '%m'. + Example 2: 4-wide f32 vector load. Uses `symbol` keyword for symbols `%n` and `%m`. ```mlir %1 = affine.vector_load %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>, vector<4xf32> @@ -970,7 +981,7 @@ TODOs: * Add support for strided vector loads. * Consider adding a permutation map to permute the slice that is read from memory - (see [vector.transfer_read](../Vector/#vectortransfer_read-vectortransferreadop)). + (see [vector.transfer_read](../Vector/#vectortransfer_read-mlirvectortransferreadop)). }]; let results = (outs AnyVector:$result); @@ -1001,8 +1012,8 @@ def AffineVectorStoreOp : AffineStoreOpBase<"vector_store"> { let summary = "affine vector store operation"; let description = [{ - The "affine.vector_store" is the vector counterpart of - [affine.store](#affinestore-affinestoreop). It writes a + The `affine.vector_store` is the vector counterpart of + [affine.store](#affinestore-mliraffinestoreop). It writes a [vector](Builtin.md/#vectortype), supplied as its first operand, into a slice within a [MemRef](Builtin.md/#memreftype) of the same base elemental type, supplied as its second operand. @@ -1013,7 +1024,7 @@ respective dimensions of the shape. Strided vector stores will be supported in the future. An affine expression of loop IVs and symbols must be specified for each - dimension of the memref. The keyword 'symbol' can be used to indicate SSA + dimension of the memref. The keyword `symbol` can be used to indicate SSA identifiers which are symbolic. Example 1: 8-wide f32 vector store. @@ -1022,7 +1033,7 @@ affine.vector_store %v0, %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>, vector<8xf32> ``` - Example 2: 4-wide f32 vector store. Uses 'symbol' keyword for symbols '%n' and '%m'. + Example 2: 4-wide f32 vector store. Uses `symbol` keyword for symbols `%n` and `%m`. ```mlir affine.vector_store %v0, %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>, vector<4xf32> @@ -1037,7 +1048,7 @@ TODOs: * Add support for strided vector stores. * Consider adding a permutation map to permute the slice that is written to memory - (see [vector.transfer_write](../Vector/#vectortransfer_write-vectortransferwriteop)). + (see [vector.transfer_write](../Vector/#vectortransfer_write-mlirvectortransferwriteop)). }]; let arguments = (ins AnyVector:$value,