Skip to content

Commit a9e3edf

Browse files
committed
[mlir] Add a contiguous<perm, offset> layout, use as identity layout
This PR introduces a new ContiguousLayoutAttr, which holds a permutation of the dimensions of the memref and an optional offset, and replaces the default memref layout (which was previously the N-D identity map) with contiguous<N>. In general, the syntax for this attribute is `contiguous<[I0, I1, .. IN], offset: O>` where `I0` through `IN` are integers in 0..=N and O is either a static offset or ? for a dynamic one. If the offset is 0, the offset isn't printed, while if the permutation is `[0, 1, ... N]`, we print it as N+1. That is, the 2-D identity/row-major layout is `contiguous<2>` and not `(d0, d1) -> (d0, d1)` like it used to be. \# Motivation In summary, the contiguous<> layout both fills in the "layout hierarchy" (all contiguous layouts are strided, and all strided layouts are affine maps, but you can't go back down) with a primitive that enables useful optimizations and makes it easier to have relocatable/mergable allocations in MLIR code. Consider `memref<?0 x ?1 x ?2 x T>` - a memref with three dynamic dimensions. This memref has a row-major identity layout. Suppose I want to make this memref "relocatable" - declare that it has an unonwn offset so that I can, for example, have a pass that merges allocations into larger contiguous buffers. With the current layouts in MLIR, I can either use: - `strided<[?, ?, 1], offset: ?>`, which loses the fact that this is a row-major memref. We don't know the relationship of those two `?`s to each other. - `(d0, d1, d2)[s0] -> (d0, d1, d2 + s0)`, which isn't a "strided" layout by existing definitions and encounters the fact that meany memref operations don't handle non-strided or arbitrary affine layouts. Being able to use `contiguous<3, offset: ?>` (or, in its long form, contiguous<[0, 1, 2], offset: ?>`) resolves this isue. That is now a strided layout that directly encodes the fact that this is a 3-D row-major memref with some dynamic offset. As seen in my changes to some passes like `gpu-decompose-memrefs` or the vector transfer op flattener, knowing that a layout is contiguous - if not necessarily row-major, allows us to use operations like `affine.linearize_index` for index computations, which fold well with operations like `affine.delinearize_index`, allowing for eliminating unnecessariy "divide an ID into parts and multiply them together again" computations that often come up in tiling-based code generation that the affine map simplifier has difficulty with or generates inefficiently. This layout also allows describing permuted layouts, like column-major layouts, without needing code to handle the general complexity of an affine map layout. For exmample, memref.expand_shape %arg [[0, 1], [2]] : memref<?x?xi32, contiguous<[1, 0]> into memref<?x?x?xi32, contiguous<[1, 2, 0]> accurately describes the effects of expand_shape'ing a column-major memref. \## Why change the default layout? Since the built-in layout attributes form a hierarchy of specificy (all contiguous layouts are strided ...), there are multiple ways to represent the identity row-major layout. The contiguous layout is the most specific of these, so it makes sense to declare it the canonical form of the identity layout. That is, `strided<[?, ?, 1]>` is less specific of a layout for `memref<?x?x?xi32>`. The identity affine_map also has non-canonical forms and is less spcefici: code that can handle te identity AffineMapAttr may not know what to do with other affine maps because of how general they are, but it will be easier to go from the identity ContiguousLayoutAttr to permuted and/or offset attributes. Therefore, making the contiguous layout the default form of MemRefLayoutAttrInterface makes writing memref-handling code easier going forward. \# Concrete impacts of the change 1. `memref<...xT, affine_map<(d0, d1, ..., dN) -> (d0, d1, ... dN)>` no longer prints as `memref<...xT>`. 2. Similarly, the default memref layout is no longer an AffineMapAttr. This didn't break any code in-tree, since almost everything had moved to MemRefLayoutAttrInterface::getAffineMap(), but it's worth calling out. 3. `memref.subview`, `memref.reinterperet_cast`, and so on do not alwasy produce a `strided` layout: if code needed to create `strided<[], offset: O>`, it'll now create `contiguous<0, offset: O>` and similarly for `strided<[1], offset: O>`, which is a 1-D contiguous layout. This is facilitated by the new `StridedLayout::getCanonical` method, which doesn't always return a strided layout 4. Some passes have been updated to use `affine.linearize_index disjoint` when they were flatting a contiguous (subset of) a memref, allowing for more efficient code generatino compared to an `affine.apply` over the strides. 4. `getStridesAndOfffset()` has learned a new trick for affine maps: any "offset permutation" (that is, a permutation where the last result can be dX + E for any E) is now considered strided. This means that you can now `getStridesAndOffset` a `memref<MxNxf32, affine_map<(i, j) -> (j, i)>`, which would previously fail. 5. `MemRefType::canonicalizeLayout` has been updated to canonicalize strided layouts to their `contiguous` equivalent for static-shaped memrefs. 6. `bufferization.buffer_layout` can be any `MemRefLayoutAttrInterface`, and any identity maps present in such attributes are transparently migrated to their contiguous<> equivalents. 7. Certain reshape folders will now work with any row-major layout, even if it has an offset. While this is a breaking change, we expect that it will allow long-term improvments to how MLIR represents memrefs in common situations.
1 parent f3a1421 commit a9e3edf

File tree

56 files changed

+1565
-484
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1565
-484
lines changed

mlir/include/mlir-c/BuiltinAttributes.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,13 @@ MLIR_CAPI_EXPORTED MlirAttribute
697697
mlirStridedLayoutAttrGet(MlirContext ctx, int64_t offset, intptr_t numStrides,
698698
const int64_t *strides);
699699

700+
// Creates a strided layout attribute from given strides and offset,
701+
// canonicalizing the 0D and 1D unit stride to contiguous layout attributes. The
702+
// returned value may not be a StridedLayoutAttr.
703+
MLIR_CAPI_EXPORTED MlirAttribute
704+
mlirStridedLayoutAttrGetCanonical(MlirContext ctx, int64_t offset,
705+
intptr_t numStrides, const int64_t *strides);
706+
700707
// Returns the offset in the given strided layout layout attribute.
701708
MLIR_CAPI_EXPORTED int64_t mlirStridedLayoutAttrGetOffset(MlirAttribute attr);
702709

@@ -711,6 +718,38 @@ MLIR_CAPI_EXPORTED int64_t mlirStridedLayoutAttrGetStride(MlirAttribute attr,
711718
/// Returns the typeID of a StridedLayout attribute.
712719
MLIR_CAPI_EXPORTED MlirTypeID mlirStridedLayoutAttrGetTypeID(void);
713720

721+
//===----------------------------------------------------------------------===//
722+
// Contiguous layout attribute.
723+
//===----------------------------------------------------------------------===//
724+
725+
// Checks wheather the given attribute is a contiguous layout attribute.
726+
MLIR_CAPI_EXPORTED bool mlirAttributeIsAContiguousLayout(MlirAttribute attr);
727+
728+
// Creates a contiguous layout attribute from given permutation and offset.
729+
// There must be `rank` values in `permutation`.
730+
MLIR_CAPI_EXPORTED MlirAttribute mlirContiguousLayoutAttrGet(
731+
MlirContext ctx, int64_t offset, intptr_t rank, const int64_t *permutation);
732+
733+
// Creates a row-major contiguous layout attribute from given offset and rank.
734+
MLIR_CAPI_EXPORTED MlirAttribute mlirContiguousLayoutAttrGetRowMajor(
735+
MlirContext ctx, int64_t offset, int64_t rank);
736+
737+
// Returns the offset in the given contiguous layout attribute.
738+
MLIR_CAPI_EXPORTED int64_t
739+
mlirContiguousLayoutAttrGetOffset(MlirAttribute attr);
740+
741+
// Returns the number of permutation entries in the given contiguous layout
742+
// attribute.
743+
MLIR_CAPI_EXPORTED intptr_t mlirContiguousLayoutAttrGetRank(MlirAttribute attr);
744+
745+
// Returns the pos-th permutation entry stored in the given contiguous layout
746+
// attribute.
747+
MLIR_CAPI_EXPORTED int64_t
748+
mlirContiguousLayoutAttrGetPermutationEntry(MlirAttribute attr, intptr_t pos);
749+
750+
/// Returns the typeID of a ContiguousLayout attribute.
751+
MLIR_CAPI_EXPORTED MlirTypeID mlirContiguousLayoutAttrGetTypeID(void);
752+
714753
#ifdef __cplusplus
715754
}
716755
#endif

mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ def MemRefTypeAttr
3232
class MemRef_Op<string mnemonic, list<Trait> traits = []>
3333
: Op<MemRef_Dialect, mnemonic, traits>;
3434

35-
// Base class for ops with static/dynamic offset, sizes and strides
36-
// attributes/arguments.
35+
// Base class for ops with static/dynamic offset, sizes and optional strides
36+
// attributes/arguments. When the strides are not specified, this implies a
37+
// contiguous layout.
3738
class MemRef_OpWithOffsetSizesAndStrides<string mnemonic,
3839
list<Trait> traits = []>
3940
: MemRef_Op<mnemonic, traits> {

mlir/include/mlir/Dialect/Utils/ReshapeOpsUtils.h

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,10 @@ LogicalResult reshapeLikeShapesAreCompatible(
178178
ArrayRef<int64_t> collapsedShape, ArrayRef<int64_t> expandedShape,
179179
ArrayRef<ReassociationIndices> reassociationMaps, bool isExpandingReshape);
180180

181-
/// Returns true iff the type is a MemRefType and has a non-identity layout.
182-
bool hasNonIdentityLayout(Type type);
181+
/// Returns true iff the type is a MemRefType and has a layout that is not
182+
/// row-major contiguous - that is, the identity layout with an optional
183+
/// offset.
184+
bool hasNonRowMajorContiguousLayout(Type type);
183185

184186
enum class ReshapeOpKind { kExpand, kCollapse };
185187

@@ -197,9 +199,9 @@ struct ComposeReassociativeReshapeOps : public OpRewritePattern<ReshapeOpTy> {
197199

198200
ShapedType resultType = reshapeOp.getResultType();
199201

200-
if (hasNonIdentityLayout(srcReshapeOp.getSrc().getType()) ||
201-
hasNonIdentityLayout(reshapeOp.getSrc().getType()) ||
202-
hasNonIdentityLayout(reshapeOp.getResult().getType()))
202+
if (hasNonRowMajorContiguousLayout(srcReshapeOp.getSrc().getType()) ||
203+
hasNonRowMajorContiguousLayout(reshapeOp.getSrc().getType()) ||
204+
hasNonRowMajorContiguousLayout(reshapeOp.getResult().getType()))
203205
return failure();
204206

205207
std::optional<SmallVector<ReassociationIndices>> reassociationIndices =
@@ -265,9 +267,9 @@ struct ComposeCollapseOfExpandOp : public OpRewritePattern<CollapseOpTy> {
265267
ShapedType srcType = expandOp.getSrcType();
266268
ShapedType resultType = collapseOp.getResultType();
267269

268-
if (hasNonIdentityLayout(collapseOp.getSrc().getType()) ||
269-
hasNonIdentityLayout(expandOp.getSrc().getType()) ||
270-
hasNonIdentityLayout(expandOp.getResult().getType()))
270+
if (hasNonRowMajorContiguousLayout(collapseOp.getSrc().getType()) ||
271+
hasNonRowMajorContiguousLayout(expandOp.getSrc().getType()) ||
272+
hasNonRowMajorContiguousLayout(expandOp.getResult().getType()))
271273
return failure();
272274

273275
int64_t srcRank = srcType.getRank();
@@ -331,9 +333,9 @@ struct ComposeExpandOfCollapseOp : public OpRewritePattern<ExpandOpTy> {
331333
ShapedType srcType = collapseOp.getSrcType();
332334
ShapedType resultType = expandOp.getResultType();
333335

334-
if (hasNonIdentityLayout(expandOp.getSrc().getType()) ||
335-
hasNonIdentityLayout(collapseOp.getSrc().getType()) ||
336-
hasNonIdentityLayout(collapseOp.getResult().getType()))
336+
if (hasNonRowMajorContiguousLayout(expandOp.getSrc().getType()) ||
337+
hasNonRowMajorContiguousLayout(collapseOp.getSrc().getType()) ||
338+
hasNonRowMajorContiguousLayout(collapseOp.getResult().getType()))
337339
return failure();
338340

339341
int64_t srcRank = srcType.getRank();
@@ -451,7 +453,7 @@ getLinearizedDimensions(ArrayRef<ReassociationIndices> reassociationIndices);
451453
/// %4 = tensor.extract_slice %0 [%3#0, %3#1, %3#2, 0] [1, 1, 1, 10] [1, 1, 1, 1] :
452454
/// tensor<3x7x11x10xf32> to tensor<1x1x1x10xf32>
453455
///
454-
/// %5 = tensor.collapse_shape %4 [[0, 1, 2], [3]] :
456+
/// %5 = tensor.collapse_shape %4 [[0, 1, 2], [3]] :
455457
/// tensor<1x1x1x10xf32> into tensor<1x10xf32>
456458
/// %6 = tensor.insert_slice %5 into %arg0 [%iv, 0] [1, 10] [1, 1] :
457459
/// tensor<1x10xf32> into tensor<10x10xf32>

mlir/include/mlir/IR/BuiltinAttributes.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,28 @@ inline bool operator!=(StringRef lhs, StringAttr rhs) { return !(lhs == rhs); }
10811081

10821082
namespace mlir {
10831083

1084+
/// Given an N-dimensional permutation and an offset (which can use
1085+
/// ShapedType::kDynamic) to represent a dynamic value), return the
1086+
/// N-dimensional map that is permuted according to said permutation and adds
1087+
/// the offset to the final output. If the permutation has no outputs (it's a
1088+
/// 0-D map), add one result to hold the offset.
1089+
///
1090+
/// Examples:
1091+
/// =========
1092+
///
1093+
/// offset = 0, permutation = [0, 1, 2] gives
1094+
/// [](d0, d1, d2) -> (d0, d1, d2)
1095+
/// while offset = 5 gives [](d0, d1, d2) -> (d0, d1, d2 + 5)
1096+
/// and offset = ? gives [s0](d0, d1, d2) -> (d0, d1, d2 + s0).
1097+
///
1098+
/// offset = ?, permutation = [2, 1, 0] gives
1099+
/// [s0](d0, d1, d2) -> (d2, d1, d0 + s0)
1100+
///
1101+
/// Finally, offset = 0, permutation = [], gives []() -> (0), while
1102+
/// offset = ?, permutation = [] gives [s0]() -> (s0).
1103+
AffineMap makePermutedMapWithOffset(ArrayRef<int64_t> permutation,
1104+
int64_t offset, MLIRContext *context);
1105+
10841106
/// Given a list of strides (in which ShapedType::kDynamic
10851107
/// represents a dynamic value), return the single result AffineMap which
10861108
/// represents the linearized strided layout map. Dimensions correspond to the

mlir/include/mlir/IR/BuiltinAttributes.td

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def Builtin_DenseArrayRawDataParameter : ArrayRefParameter<
164164
}];
165165
}
166166

167-
def Builtin_DenseArray : Builtin_Attr<"DenseArray", "dense_array",
167+
def Builtin_DenseArray : Builtin_Attr<"DenseArray", "dense_array",
168168
[BlobAttrInterface]> {
169169
let summary = "A dense array of integer or floating point elements.";
170170
let description = [{
@@ -494,7 +494,7 @@ def Builtin_DenseResourceElementsAttr : Builtin_Attr<"DenseResourceElements",
494494
/// when building the attribute. The provided `blobName` is used as a hint
495495
/// for the key of the new handle for the `blob` resource, but may be
496496
/// changed if necessary to ensure uniqueness during insertion.
497-
/// This base class builder does no element type specific size or alignment
497+
/// This base class builder does no element type specific size or alignment
498498
/// checking. Use the typed subclasses for more safety unless if performing
499499
/// generic operations.
500500
AttrBuilderWithInferredContext<(ins
@@ -1051,9 +1051,96 @@ def StridedLayoutAttr : Builtin_Attr<"StridedLayout", "strided_layout",
10511051
/// Returns true if this layout is static, i.e. the strides and offset all
10521052
/// have a known value > 0.
10531053
bool hasStaticLayout() const;
1054+
1055+
/// Get a "canonical" strided layout for the given strides.
1056+
/// This constructs a strided layout with the given `offset` and `strides`,
1057+
/// except that if either the strides are empty or equal to [1], it returns
1058+
/// the corresponding ContiguousLayoutAttr in order to guard against multiple
1059+
/// representations of the identity layout.
1060+
static ::mlir::MemRefLayoutAttrInterface getCanonical(MLIRContext *context,
1061+
int64_t offset, ::llvm::ArrayRef<int64_t> strides);
10541062
}];
10551063
}
10561064

1065+
//===----------------------------------------------------------------------===//
1066+
// ContiguousLayoutAttr
1067+
//===----------------------------------------------------------------------===//
1068+
1069+
def ContiguousLayoutAttr : Builtin_Attr<"ContiguousLayout", "contiguous_layout",
1070+
[DeclareAttrInterfaceMethods<MemRefLayoutAttrInterface,
1071+
["isIdentity", "verifyLayout"]>]> {
1072+
let summary = "An Attribute representing a contiguous layout of a shaped type";
1073+
let description = [{
1074+
Syntax:
1075+
1076+
```
1077+
contiguous-layout-attribute ::= `contiguous` `<` maybe-permutation
1078+
(`,` `offset` `:` dimension)? `>`
1079+
maybe-permutation ::= decimal-literal | `[` permutation `]`
1080+
permutation ::= decimal-literal (`,` decimal-literal)*
1081+
dimension ::= decimal-literal | `?`
1082+
```
1083+
1084+
A contiguous layout is a layout that represents a sequence of dimensions
1085+
laid out in linear memory in its canonical form. Specifically, it indicates
1086+
that if one permutes the dimensions of a memref according to `permutaton`,
1087+
they will be in a row-major contiguos form: that is, the stride (in the
1088+
sense of the strided layout) of dimension `permutation[i]` is equal
1089+
to the products of the sizes of all dimensions appearing later in the permutation.
1090+
1091+
For example, a MxN memref with a `contiguous<[1, 0]>` layout is colmn-major:
1092+
advancing in the M dimension requires moving by 1 element in linear memory,
1093+
while the N dimension requires moving by M elements. Conversely,
1094+
if the layout is `contiguous<[0, 1]>` (which can be written `contiguous<2>`
1095+
for brevity and will be omitted from printing without an offset), the stride
1096+
of the N dimension will be 1 element while the stride of the M dimension will be
1097+
N elements.
1098+
1099+
As a more complex example, `memref<AxBxCxT, contigous<[2, 0, 1], offset: D>>`
1100+
, where A, B, C, and D are potentially dynamic values, means that
1101+
the value at index `[%i, %j, %k]` is located `%k * A * B + %i * B + %j + D`
1102+
elements from the beginning of the memory underlying that memref.
1103+
1104+
The permutation must contain the integers between 0 and the rank of the memref - 1,
1105+
and must have one distinct entry for each memref dimension. The value
1106+
`[0, 1, ..., N-1]`, specifying a row-major format, may be printed as `N`
1107+
for clarity.
1108+
1109+
If an offset is specified, it is a number of elements to move within
1110+
the underlying linear memory after the permutation is applied. This offset
1111+
may be _dynamic_, meaning that it may not be known at compile time.
1112+
A dynamic offset is represented as a `?` in the assembly syntax and as
1113+
`ShapedType::kDynamic` in the code. The offset must be non-negative.
1114+
1115+
See [Dialects/Builtin.md#memreftype](MemRef type) for more information.
1116+
}];
1117+
1118+
let parameters = (ins
1119+
"int64_t":$offset,
1120+
ArrayRefParameter<
1121+
"int64_t",
1122+
"permutation (64-bit integer)"
1123+
>:$permutation
1124+
);
1125+
1126+
let builders = [
1127+
// Builder for row-major contiguous attribute.
1128+
AttrBuilder<(ins "int64_t":$offset, "int64_t":$rank)>
1129+
];
1130+
let genVerifyDecl = 1;
1131+
1132+
let extraClassDeclaration = [{
1133+
/// Print the attribute to the given output stream.
1134+
void print(raw_ostream &os) const;
1135+
1136+
/// Returns true if this layout is static, i.e. the offset has a static value.
1137+
bool hasStaticLayout() const;
1138+
1139+
/// Return true if this layout has a row-major permutation - that is, the
1140+
/// dimensions of the shape are not permuted.
1141+
bool isRowMajor() const;
1142+
}];
1143+
}
10571144

10581145
//===----------------------------------------------------------------------===//
10591146
// StringAttr

mlir/include/mlir/IR/BuiltinTypes.td

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -585,20 +585,27 @@ def Builtin_MemRef : Builtin_Type<"MemRef", "memref", [
585585
layout must avoid internal aliasing, i.e., two distinct tuples of
586586
_in-bounds_ indices must be pointing to different elements in memory. The
587587
layout is an attribute that implements `MemRefLayoutAttrInterface`. The
588-
bulitin dialect offers two kinds of layouts: strided and affine map, each
589-
of which is available as an attribute. Other attributes may be used to
590-
represent the layout as long as they can be converted to a
588+
bulitin dialect offers three kinds of layouts: contiguous, strided and
589+
affine map, each of which is available as an attribute. Other attributes may be
590+
used to represent the layout as long as they can be converted to a
591591
[semi-affine map](Affine.md/#semi-affine-maps) and implement the required
592592
interface. Users of memref are expected to fallback to the affine
593593
representation when handling unknown memref layouts. Multi-dimensional
594594
affine forms are interpreted in _row-major_ fashion.
595595

596596
In absence of an explicit layout, a memref is considered to have a
597-
multi-dimensional identity affine map layout. Identity layout maps do not
598-
contribute to the MemRef type identification and are discarded on
599-
construction. That is, a type with an explicit identity map is
597+
row-major contiguous layout with an offset of 0, which is equivalent
598+
to a multi-dimensional identity map. For backwards compatibility,
599+
identity layout maps do not contribute to the MemRef type identification and
600+
are discarded on construction. That is, a type with an explicit identity map is
600601
`memref<?x?xf32, (i,j)->(i,j)>` is strictly the same as the one without a
601-
layout, `memref<?x?xf32>`.
602+
layout, `memref<?x?xf32>`, which, written explicitly, has the layout
603+
`memref<?x?xf32, contiguous<2>>`.
604+
605+
The built-in layouts form a hierarchy: all contiguous layuts are strided layouts,
606+
and all strided layouts are affine map layouts, but the reverse is not true.
607+
Using a more specific layout may permit a greater degree of optimization in
608+
the generated code.
602609

603610
##### Affine Map Layout
604611

@@ -656,6 +663,37 @@ def Builtin_MemRef : Builtin_Type<"MemRef", "memref", [
656663
Therefore, it is never subject to the implicit row-major layout
657664
interpretation.
658665

666+
### Contiguous layout
667+
668+
The most restricted of the built-in layouts is the _contiguous_ layout, which
669+
expresses the fact that the in-memory layout of the memref would be row-major
670+
without padding after the associated permutation is applied. Equivalently,
671+
a contigous layout is a strided layout where the strides are implicitly computed
672+
from the (permuted) sizes of the memref.
673+
674+
This layout is necessary to allow optimizations during lowering passes in the
675+
presence of dynamic sizes, since
676+
`memref<?x?x?xf32, strided<[?, ?, 1], offset: ?>>` doesn't specify if it's
677+
dimensions have padding in between tem or not - the two non-1 strides are
678+
dynamic. By contrast, `contiguous<3, offset: ?>` indiates a row-major layout
679+
with an offset, while `contiguous<[2, 1, 0], offset: ?>` indicates a
680+
column-major layout. While this scheme could be expressed with an affine map,
681+
some operations expect memrefs to be in a form compatible with the `strided`
682+
layout, which can be difficult to detect from analyzing an affine expression.
683+
684+
In general, the layout `contiguous<[p0, p1, ..., pN], offset: V>`
685+
corresponds to the affine map
686+
687+
```mlir
688+
affine_map<(d0, ..., dN) -> (d[p0], d[p1], ... + d[pN] + V)>
689+
```
690+
691+
where `V` is either `s0` if it is dynamic or some constant value.
692+
693+
For convenience, the layout `contigous<[0, 1, ..., N], offset: V>` is printed
694+
as `contigous<N+1, offset: V>`, and the `, offset: V` segment is omitted if `V`
695+
is `0`.
696+
659697
##### Codegen of Unranked Memref
660698

661699
Using unranked memref in codegen besides the case mentioned above is highly
@@ -815,6 +853,10 @@ def Builtin_MemRef : Builtin_Type<"MemRef", "memref", [
815853
/// considering both _all_ and _only_ the trailing 3 dims,
816854
/// - memref<5x4x3x2xi8, strided<[48, 6, 2, 1]> is _only_ contiguous when
817855
/// considering the trailing 3 dims.
856+
/// - memref<?x?x?xi8, contiguous<3, offset: ?>> is contiguous when
857+
/// considering all dimensions.
858+
/// - memref<?x?x?x?xi32, contiguous<[1, 0, 2, 3], offset: ?>> is
859+
/// _only_ contiguous when considering the trailing 2 dimensions.
818860
///
819861
bool areTrailingDimsContiguous(int64_t n);
820862

@@ -830,8 +872,8 @@ def Builtin_MemRef : Builtin_Type<"MemRef", "memref", [
830872

831873
/// Returns the strides of the MemRef if the layout map is in strided form.
832874
/// MemRefs with a layout map in strided form include:
833-
/// 1. empty or identity layout map, in which case the stride information
834-
/// is the canonical form computed from sizes;
875+
/// 1. the empty layout, the identity layout affine map, and any ContigousLayoutAttr,
876+
/// in which case the stride information is the canonical form computed from sizes;
835877
/// 2. a StridedLayoutAttr layout;
836878
/// 3. any other layout that be converted into a single affine map layout
837879
/// of the form `K + k0 * d0 + ... kn * dn`, where K and ki's are

0 commit comments

Comments
 (0)