1//===- MemRefOps.td - MemRef op definitions ----------------*- tablegen -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef MEMREF_OPS
10#define MEMREF_OPS
11
12include "mlir/Dialect/Arithmetic/IR/ArithmeticBase.td"
13include "mlir/Dialect/MemRef/IR/MemRefBase.td"
14include "mlir/Interfaces/CastInterfaces.td"
15include "mlir/Interfaces/ControlFlowInterfaces.td"
16include "mlir/Interfaces/CopyOpInterface.td"
17include "mlir/Interfaces/SideEffectInterfaces.td"
18include "mlir/Interfaces/ViewLikeInterface.td"
19include "mlir/IR/SymbolInterfaces.td"
20
21/// A TypeAttr for memref types.
22def MemRefTypeAttr
23    : TypeAttrBase<"::mlir::MemRefType", "memref type attribute"> {
24  let constBuilderCall = "::mlir::TypeAttr::get($0)";
25}
26
27class MemRef_Op<string mnemonic, list<Trait> traits = []>
28    : Op<MemRef_Dialect, mnemonic, traits>;
29
30// Base class for ops with static/dynamic offset, sizes and strides
31// attributes/arguments.
32class MemRef_OpWithOffsetSizesAndStrides<string mnemonic,
33                                         list<Trait> traits = []>
34    : MemRef_Op<mnemonic, traits> {
35  code extraBaseClassDeclaration = [{
36    /// Returns the dynamic sizes for this subview operation if specified.
37    ::mlir::Operation::operand_range getDynamicSizes() { return getSizes(); }
38
39    /// Return the list of Range (i.e. offset, size, stride). Each
40    /// Range entry contains either the dynamic value or a ConstantIndexOp
41    /// constructed with `b` at location `loc`.
42    ::mlir::SmallVector<::mlir::Range, 8> getOrCreateRanges(
43        ::mlir::OpBuilder &b, ::mlir::Location loc) {
44      return ::mlir::getOrCreateRanges(*this, b, loc);
45    }
46  }];
47}
48
49//===----------------------------------------------------------------------===//
50// AllocLikeOp
51//===----------------------------------------------------------------------===//
52
53// Base class for memref allocating ops: alloca and alloc.
54//
55//   %0 = alloclike(%m)[%s] : memref<8x?xf32, affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>>
56//
57class AllocLikeOp<string mnemonic,
58                  Resource resource,
59                  list<Trait> traits = []> :
60    MemRef_Op<mnemonic,
61    !listconcat([
62      AttrSizedOperandSegments
63    ], traits)> {
64
65  let arguments = (ins Variadic<Index>:$dynamicSizes,
66                       // The symbolic operands (the ones in square brackets)
67                       // bind to the symbols of the memref's layout map.
68                       Variadic<Index>:$symbolOperands,
69                       Confined<OptionalAttr<I64Attr>,
70                                [IntMinValue<0>]>:$alignment);
71  let results = (outs Res<AnyMemRef, "", [MemAlloc<resource>]>:$memref);
72
73  let builders = [
74    OpBuilder<(ins "MemRefType":$memrefType,
75                  CArg<"IntegerAttr", "IntegerAttr()">:$alignment), [{
76      return build($_builder, $_state, memrefType, {}, alignment);
77    }]>,
78    OpBuilder<(ins "MemRefType":$memrefType, "ValueRange":$dynamicSizes,
79                  CArg<"IntegerAttr", "IntegerAttr()">:$alignment), [{
80      return build($_builder, $_state, memrefType, dynamicSizes, {}, alignment);
81    }]>,
82    OpBuilder<(ins "MemRefType":$memrefType, "ValueRange":$dynamicSizes,
83                  "ValueRange":$symbolOperands,
84                  CArg<"IntegerAttr", "{}">:$alignment), [{
85      $_state.types.push_back(memrefType);
86      $_state.addOperands(dynamicSizes);
87      $_state.addOperands(symbolOperands);
88      $_state.addAttribute(getOperandSegmentSizeAttr(),
89          $_builder.getI32VectorAttr({
90              static_cast<int32_t>(dynamicSizes.size()),
91              static_cast<int32_t>(symbolOperands.size())}));
92      if (alignment)
93        $_state.addAttribute(getAlignmentAttrStrName(), alignment);
94    }]>];
95
96  let extraClassDeclaration = [{
97    static StringRef getAlignmentAttrStrName() { return "alignment"; }
98
99    MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
100  }];
101
102  let assemblyFormat = [{
103    `(`$dynamicSizes`)` (`` `[` $symbolOperands^ `]`)? attr-dict `:` type($memref)
104  }];
105
106  let hasCanonicalizer = 1;
107  let hasVerifier = 1;
108}
109
110//===----------------------------------------------------------------------===//
111// AssumeAlignmentOp
112//===----------------------------------------------------------------------===//
113
114def AssumeAlignmentOp : MemRef_Op<"assume_alignment"> {
115  let summary =
116      "assertion that gives alignment information to the input memref";
117  let description = [{
118    The `assume_alignment` operation takes a memref and an integer of alignment
119    value, and internally annotates the buffer with the given alignment. If
120    the buffer isn't aligned to the given alignment, the behavior is undefined.
121
122    This operation doesn't affect the semantics of a correct program. It's for
123    optimization only, and the optimization is best-effort.
124  }];
125  let arguments = (ins AnyMemRef:$memref,
126                       Confined<I32Attr, [IntPositive]>:$alignment);
127  let results = (outs);
128
129  let assemblyFormat = "$memref `,` $alignment attr-dict `:` type($memref)";
130  let hasVerifier = 1;
131}
132
133//===----------------------------------------------------------------------===//
134// AllocOp
135//===----------------------------------------------------------------------===//
136
137def MemRef_AllocOp : AllocLikeOp<"alloc", DefaultResource, []> {
138  let summary = "memory allocation operation";
139  let description = [{
140    The `alloc` operation allocates a region of memory, as specified by its
141    memref type.
142
143    Example:
144
145    ```mlir
146    %0 = memref.alloc() : memref<8x64xf32, 1>
147    ```
148
149    The optional list of dimension operands are bound to the dynamic dimensions
150    specified in its memref type. In the example below, the ssa value '%d' is
151    bound to the second dimension of the memref (which is dynamic).
152
153    ```mlir
154    %0 = memref.alloc(%d) : memref<8x?xf32, 1>
155    ```
156
157    The optional list of symbol operands are bound to the symbols of the
158    memrefs affine map. In the example below, the ssa value '%s' is bound to
159    the symbol 's0' in the affine map specified in the allocs memref type.
160
161    ```mlir
162    %0 = memref.alloc()[%s] : memref<8x64xf32,
163                              affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>, 1>
164    ```
165
166    This operation returns a single ssa value of memref type, which can be used
167    by subsequent load and store operations.
168
169    The optional `alignment` attribute may be specified to ensure that the
170    region of memory that will be indexed is aligned at the specified byte
171    boundary.
172
173    ```mlir
174    %0 = memref.alloc()[%s] {alignment = 8} :
175      memref<8x64xf32, affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>, 1>
176    ```
177  }];
178  let hasVerifier = 1;
179}
180
181//===----------------------------------------------------------------------===//
182// AllocaOp
183//===----------------------------------------------------------------------===//
184
185def MemRef_AllocaOp : AllocLikeOp<"alloca", AutomaticAllocationScopeResource> {
186  let summary = "stack memory allocation operation";
187  let description = [{
188    The `alloca` operation allocates memory on the stack, to be automatically
189    released when control transfers back from the region of its closest
190    surrounding operation with an
191    [`AutomaticAllocationScope`](../Traits.md/#automaticallocationscope) trait.
192    The amount of memory allocated is specified by its memref and additional
193    operands. For example:
194
195    ```mlir
196    %0 = memref.alloca() : memref<8x64xf32>
197    ```
198
199    The optional list of dimension operands are bound to the dynamic dimensions
200    specified in its memref type. In the example below, the SSA value '%d' is
201    bound to the second dimension of the memref (which is dynamic).
202
203    ```mlir
204    %0 = memref.alloca(%d) : memref<8x?xf32>
205    ```
206
207    The optional list of symbol operands are bound to the symbols of the
208    memref's affine map. In the example below, the SSA value '%s' is bound to
209    the symbol 's0' in the affine map specified in the allocs memref type.
210
211    ```mlir
212    %0 = memref.alloca()[%s] : memref<8x64xf32,
213                               affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>>
214    ```
215
216    This operation returns a single SSA value of memref type, which can be used
217    by subsequent load and store operations. An optional alignment attribute, if
218    specified, guarantees alignment at least to that boundary. If not specified,
219    an alignment on any convenient boundary compatible with the type will be
220    chosen.
221  }];
222  let hasVerifier = 1;
223}
224
225//===----------------------------------------------------------------------===//
226// AllocaScopeOp
227//===----------------------------------------------------------------------===//
228
229def MemRef_AllocaScopeOp : MemRef_Op<"alloca_scope",
230      [AutomaticAllocationScope,
231       DeclareOpInterfaceMethods<RegionBranchOpInterface>,
232       SingleBlockImplicitTerminator<"AllocaScopeReturnOp">,
233       RecursiveSideEffects,
234       NoRegionArguments]> {
235  let summary = "explicitly delimited scope for stack allocation";
236  let description = [{
237    The `memref.alloca_scope` operation represents an explicitly-delimited
238    scope for the alloca allocations. Any `memref.alloca` operations that are
239    used within this scope are going to be cleaned up automatically once
240    the control-flow exits the nested region. For example:
241
242    ```mlir
243    memref.alloca_scope {
244      %myalloca = memref.alloca(): memref<4x3xf32>
245      ...
246    }
247    ```
248
249    Here, `%myalloca` memref is valid within the explicitly delimited scope
250    and is automatically deallocated at the end of the given region. Conceptually,
251    `memref.alloca_scope` is a passthrough operation with
252    `AutomaticAllocationScope` that spans the body of the region within the operation.
253
254    `memref.alloca_scope` may also return results that are defined in the nested
255    region. To return a value, one should use `memref.alloca_scope.return`
256    operation:
257
258    ```mlir
259    %result = memref.alloca_scope {
260      ...
261      memref.alloca_scope.return %value
262    }
263    ```
264
265    If `memref.alloca_scope` returns no value, the `memref.alloca_scope.return ` can
266    be left out, and will be inserted implicitly.
267  }];
268
269  let results = (outs Variadic<AnyType>:$results);
270  let regions = (region SizedRegion<1>:$bodyRegion);
271  let hasCustomAssemblyFormat = 1;
272  let hasCanonicalizer = 1;
273}
274
275//===----------------------------------------------------------------------===//
276// AllocaScopeReturnOp
277//===----------------------------------------------------------------------===//
278
279def MemRef_AllocaScopeReturnOp : MemRef_Op<"alloca_scope.return",
280      [HasParent<"AllocaScopeOp">,
281       NoSideEffect,
282       ReturnLike,
283       Terminator]> {
284  let summary = "terminator for alloca_scope operation";
285  let description = [{
286    `memref.alloca_scope.return` operation returns zero or more SSA values
287    from the region within `memref.alloca_scope`. If no values are returned,
288    the return operation may be omitted. Otherwise, it has to be present
289    to indicate which values are going to be returned. For example:
290
291    ```mlir
292    memref.alloca_scope.return %value
293    ```
294  }];
295
296  let arguments = (ins Variadic<AnyType>:$results);
297  let builders = [OpBuilder<(ins), [{ /*nothing to do */ }]>];
298
299  let assemblyFormat = "attr-dict ($results^ `:` type($results))?";
300}
301
302//===----------------------------------------------------------------------===//
303// CastOp
304//===----------------------------------------------------------------------===//
305
306def MemRef_CastOp : MemRef_Op<"cast", [
307      NoSideEffect, SameOperandsAndResultShape,
308      DeclareOpInterfaceMethods<CastOpInterface>,
309      ViewLikeOpInterface,
310      MemRefsNormalizable
311    ]> {
312  let summary = "memref cast operation";
313  let description = [{
314    Syntax:
315
316    ```
317    operation ::= ssa-id `=` `memref.cast` ssa-use `:` type `to` type
318    ```
319
320    The `memref.cast` operation converts a memref from one type to an equivalent
321    type with a compatible shape. The source and destination types are
322    compatible if:
323
324    a. Both are ranked memref types with the same element type, address space,
325    and rank and:
326      1. Both have the same layout or both have compatible strided layouts.
327      2. The individual sizes (resp. offset and strides in the case of strided
328         memrefs) may convert constant dimensions to dynamic dimensions and
329         vice-versa.
330
331    If the cast converts any dimensions from an unknown to a known size, then it
332    acts as an assertion that fails at runtime if the dynamic dimensions
333    disagree with resultant destination size.
334
335    Example:
336
337    ```mlir
338    // Assert that the input dynamic shape matches the destination static shape.
339    %2 = memref.cast %1 : memref<?x?xf32> to memref<4x4xf32>
340    // Erase static shape information, replacing it with dynamic information.
341    %3 = memref.cast %1 : memref<4xf32> to memref<?xf32>
342
343    // The same holds true for offsets and strides.
344
345    // Assert that the input dynamic shape matches the destination static stride.
346    %4 = memref.cast %1 : memref<12x4xf32, offset:?, strides: [?, ?]> to
347                          memref<12x4xf32, offset:5, strides: [4, 1]>
348    // Erase static offset and stride information, replacing it with
349    // dynamic information.
350    %5 = memref.cast %1 : memref<12x4xf32, offset:5, strides: [4, 1]> to
351                          memref<12x4xf32, offset:?, strides: [?, ?]>
352    ```
353
354    b. Either or both memref types are unranked with the same element type, and
355    address space.
356
357    Example:
358
359    ```mlir
360    Cast to concrete shape.
361        %4 = memref.cast %1 : memref<*xf32> to memref<4x?xf32>
362
363    Erase rank information.
364        %5 = memref.cast %1 : memref<4x?xf32> to memref<*xf32>
365    ```
366  }];
367
368  let arguments = (ins AnyRankedOrUnrankedMemRef:$source);
369  let results = (outs AnyRankedOrUnrankedMemRef:$dest);
370  let assemblyFormat = "$source attr-dict `:` type($source) `to` type($dest)";
371
372  let extraClassDeclaration = [{
373    /// Fold the given CastOp into consumer op.
374    static bool canFoldIntoConsumerOp(CastOp castOp);
375
376    Value getViewSource() { return getSource(); }
377  }];
378
379  let hasFolder = 1;
380}
381
382//===----------------------------------------------------------------------===//
383// CopyOp
384//===----------------------------------------------------------------------===//
385
386def CopyOp : MemRef_Op<"copy",
387    [CopyOpInterface, SameOperandsElementType, SameOperandsShape]> {
388
389  let description = [{
390    Copies the data from the source to the destination memref.
391
392    Usage:
393
394    ```mlir
395    memref.copy %arg0, %arg1 : memref<?xf32> to memref<?xf32>
396    ```
397
398    Source and destination are expected to have the same element type and shape.
399    Otherwise, the result is undefined. They may have different layouts.
400  }];
401
402  let arguments = (ins Arg<AnyRankedOrUnrankedMemRef, "the memref to copy from",
403                           [MemRead]>:$source,
404                       Arg<AnyRankedOrUnrankedMemRef, "the memref to copy to",
405                           [MemWrite]>:$target);
406
407  let assemblyFormat = [{
408    $source `,` $target attr-dict `:` type($source) `to` type($target)
409  }];
410
411  let hasCanonicalizer = 1;
412  let hasFolder = 1;
413}
414
415//===----------------------------------------------------------------------===//
416// DeallocOp
417//===----------------------------------------------------------------------===//
418
419def MemRef_DeallocOp : MemRef_Op<"dealloc", [MemRefsNormalizable]> {
420  let summary = "memory deallocation operation";
421  let description = [{
422    The `dealloc` operation frees the region of memory referenced by a memref
423    which was originally created by the `alloc` operation.
424    The `dealloc` operation should not be called on memrefs which alias an
425    alloc'd memref (e.g. memrefs returned by `view` operations).
426
427    Example:
428
429    ```mlir
430    %0 = memref.alloc() : memref<8x64xf32, affine_map<(d0, d1) -> (d0, d1), 1>>
431    memref.dealloc %0 : memref<8x64xf32,  affine_map<(d0, d1) -> (d0, d1), 1>>
432    ```
433  }];
434
435  let arguments = (ins Arg<AnyRankedOrUnrankedMemRef, "", [MemFree]>:$memref);
436
437  let hasFolder = 1;
438  let assemblyFormat = "$memref attr-dict `:` type($memref)";
439}
440
441//===----------------------------------------------------------------------===//
442// DimOp
443//===----------------------------------------------------------------------===//
444
445def MemRef_DimOp : MemRef_Op<"dim", [NoSideEffect, MemRefsNormalizable]> {
446  let summary = "dimension index operation";
447  let description = [{
448    The `dim` operation takes a memref and a dimension operand of type `index`.
449    It returns the size of the requested dimension of the given memref.
450    If the dimension index is out of bounds the behavior is undefined.
451
452    The specified memref type is that of the first operand.
453
454    Example:
455
456    ```mlir
457    // Always returns 4, can be constant folded:
458    %c0 = arith.constant 0 : index
459    %x = memref.dim %A, %c0 : memref<4 x ? x f32>
460
461    // Returns the dynamic dimension of %A.
462    %c1 = arith.constant 1 : index
463    %y = memref.dim %A, %c1 : memref<4 x ? x f32>
464
465    // Equivalent generic form:
466    %x = "memref.dim"(%A, %c0) : (memref<4 x ? x f32>, index) -> index
467    %y = "memref.dim"(%A, %c1) : (memref<4 x ? x f32>, index) -> index
468    ```
469  }];
470
471  let arguments = (ins AnyRankedOrUnrankedMemRef:$source,
472                       Index:$index);
473  let results = (outs Index:$result);
474
475  let assemblyFormat = [{
476    attr-dict $source `,` $index `:` type($source)
477  }];
478
479  let builders = [
480    OpBuilder<(ins "Value":$source, "int64_t":$index)>,
481    OpBuilder<(ins "Value":$source, "Value":$index)>
482  ];
483
484  let extraClassDeclaration = [{
485    /// Helper function to get the index as a simple integer if it is constant.
486    Optional<int64_t> getConstantIndex();
487  }];
488
489  let hasCanonicalizer = 1;
490  let hasFolder = 1;
491  let hasVerifier = 1;
492}
493
494//===----------------------------------------------------------------------===//
495// DmaStartOp
496//===----------------------------------------------------------------------===//
497
498def MemRef_DmaStartOp : MemRef_Op<"dma_start"> {
499  let summary = "non-blocking DMA operation that starts a transfer";
500  let description = [{
501    DmaStartOp starts a non-blocking DMA operation that transfers data from a
502    source memref to a destination memref. The source and destination memref
503    need not be of the same dimensionality, but need to have the same elemental
504    type. The operands include the source and destination memref's each followed
505    by its indices, size of the data transfer in terms of the number of elements
506    (of the elemental type of the memref), a tag memref with its indices, and
507    optionally at the end, a stride and a number_of_elements_per_stride
508    arguments. The tag location is used by a DmaWaitOp to check for completion.
509    The indices of the source memref, destination memref, and the tag memref
510    have the same restrictions as any load/store. The optional stride arguments
511    should be of 'index' type, and specify a stride for the slower memory space
512    (memory space with a lower memory space id), transferring chunks of
513    number_of_elements_per_stride every stride until %num_elements are
514    transferred. Either both or no stride arguments should be specified. If the
515    source and destination locations overlap the behavior of this operation is
516    not defined.
517
518    For example, a DmaStartOp operation that transfers 256 elements of a memref
519    '%src' in memory space 0 at indices [%i, %j] to memref '%dst' in memory
520    space 1 at indices [%k, %l], would be specified as follows:
521
522    ```mlir
523    %num_elements = arith.constant 256
524    %idx = arith.constant 0 : index
525    %tag = memref.alloc() : memref<1 x i32, affine_map<(d0) -> (d0)>, 4>
526    dma_start %src[%i, %j], %dst[%k, %l], %num_elements, %tag[%idx] :
527      memref<40 x 128 x f32>, affine_map<(d0) -> (d0)>, 0>,
528      memref<2 x 1024 x f32>, affine_map<(d0) -> (d0)>, 1>,
529      memref<1 x i32>, affine_map<(d0) -> (d0)>, 2>
530    ```
531
532    If %stride and %num_elt_per_stride are specified, the DMA is expected to
533    transfer %num_elt_per_stride elements every %stride elements apart from
534    memory space 0 until %num_elements are transferred.
535
536    ```mlir
537    dma_start %src[%i, %j], %dst[%k, %l], %num_elements, %tag[%idx], %stride,
538              %num_elt_per_stride :
539    ```
540
541    TODO: add additional operands to allow source and destination striding, and
542    multiple stride levels.
543    TODO: Consider replacing src/dst memref indices with view memrefs.
544  }];
545  let arguments = (ins Variadic<AnyType>:$operands);
546
547  let builders = [
548    OpBuilder<(ins "Value":$srcMemRef, "ValueRange":$srcIndices,
549                   "Value":$destMemRef, "ValueRange":$destIndices,
550                   "Value":$numElements, "Value":$tagMemRef,
551                   "ValueRange":$tagIndices, CArg<"Value", "{}">:$stride,
552                   CArg<"Value", "{}">:$elementsPerStride)>
553  ];
554
555  let extraClassDeclaration = [{
556    // Returns the source MemRefType for this DMA operation.
557    Value getSrcMemRef() { return getOperand(0); }
558    // Returns the rank (number of indices) of the source MemRefType.
559    unsigned getSrcMemRefRank() {
560      return getSrcMemRef().getType().cast<MemRefType>().getRank();
561    }
562    // Returns the source memref indices for this DMA operation.
563    operand_range getSrcIndices() {
564      return {(*this)->operand_begin() + 1,
565              (*this)->operand_begin() + 1 + getSrcMemRefRank()};
566    }
567
568    // Returns the destination MemRefType for this DMA operations.
569    Value getDstMemRef() { return getOperand(1 + getSrcMemRefRank()); }
570    // Returns the rank (number of indices) of the destination MemRefType.
571    unsigned getDstMemRefRank() {
572      return getDstMemRef().getType().cast<MemRefType>().getRank();
573    }
574    unsigned getSrcMemorySpace() {
575      return getSrcMemRef().getType().cast<MemRefType>().getMemorySpaceAsInt();
576    }
577    unsigned getDstMemorySpace() {
578      return getDstMemRef().getType().cast<MemRefType>().getMemorySpaceAsInt();
579    }
580
581    // Returns the destination memref indices for this DMA operation.
582    operand_range getDstIndices() {
583      return {(*this)->operand_begin() + 1 + getSrcMemRefRank() + 1,
584              (*this)->operand_begin() + 1 + getSrcMemRefRank() + 1 +
585                  getDstMemRefRank()};
586    }
587
588    // Returns the number of elements being transferred by this DMA operation.
589    Value getNumElements() {
590      return getOperand(1 + getSrcMemRefRank() + 1 + getDstMemRefRank());
591    }
592
593    // Returns the Tag MemRef for this DMA operation.
594    Value getTagMemRef() {
595      return getOperand(1 + getSrcMemRefRank() + 1 + getDstMemRefRank() + 1);
596    }
597
598    // Returns the rank (number of indices) of the tag MemRefType.
599    unsigned getTagMemRefRank() {
600      return getTagMemRef().getType().cast<MemRefType>().getRank();
601    }
602
603    // Returns the tag memref index for this DMA operation.
604    operand_range getTagIndices() {
605      unsigned tagIndexStartPos =
606          1 + getSrcMemRefRank() + 1 + getDstMemRefRank() + 1 + 1;
607      return {(*this)->operand_begin() + tagIndexStartPos,
608              (*this)->operand_begin() + tagIndexStartPos + getTagMemRefRank()};
609    }
610
611    /// Returns true if this is a DMA from a faster memory space to a slower
612    /// one.
613    bool isDestMemorySpaceFaster() {
614      return (getSrcMemorySpace() < getDstMemorySpace());
615    }
616
617    /// Returns true if this is a DMA from a slower memory space to a faster
618    /// one.
619    bool isSrcMemorySpaceFaster() {
620      // Assumes that a lower number is for a slower memory space.
621      return (getDstMemorySpace() < getSrcMemorySpace());
622    }
623
624    /// Given a DMA start operation, returns the operand position of either the
625    /// source or destination memref depending on the one that is at the higher
626    /// level of the memory hierarchy. Asserts failure if neither is true.
627    unsigned getFasterMemPos() {
628      assert(isSrcMemorySpaceFaster() || isDestMemorySpaceFaster());
629      return isSrcMemorySpaceFaster() ? 0 : getSrcMemRefRank() + 1;
630    }
631
632    bool isStrided() {
633      return getNumOperands() != 1 + getSrcMemRefRank() + 1 +
634                                 getDstMemRefRank() + 1 + 1 +
635                                 getTagMemRefRank();
636    }
637
638    Value getStride() {
639      if (!isStrided())
640        return nullptr;
641      return getOperand(getNumOperands() - 1 - 1);
642    }
643
644    Value getNumElementsPerStride() {
645      if (!isStrided())
646        return nullptr;
647      return getOperand(getNumOperands() - 1);
648    }
649  }];
650  let hasCustomAssemblyFormat = 1;
651  let hasFolder = 1;
652  let hasVerifier = 1;
653}
654
655//===----------------------------------------------------------------------===//
656// DmaWaitOp
657//===----------------------------------------------------------------------===//
658
659def MemRef_DmaWaitOp : MemRef_Op<"dma_wait"> {
660  let summary = "blocking DMA operation that waits for transfer completion";
661  let description = [{
662   DmaWaitOp blocks until the completion of a DMA operation associated with the
663   tag element '%tag[%index]'. %tag is a memref, and %index has to be an index
664   with the same restrictions as any load/store index. %num_elements is the
665   number of elements associated with the DMA operation.
666
667   Example:
668
669   ```mlir
670    dma_start %src[%i, %j], %dst[%k, %l], %num_elements, %tag[%index] :
671      memref<2048 x f32>, affine_map<(d0) -> (d0)>, 0>,
672      memref<256 x f32>, affine_map<(d0) -> (d0)>, 1>
673      memref<1 x i32>, affine_map<(d0) -> (d0)>, 2>
674    ...
675    ...
676    dma_wait %tag[%index], %num_elements : memref<1 x i32, affine_map<(d0) -> (d0)>, 2>
677    ```
678  }];
679  let arguments = (ins AnyMemRef:$tagMemRef,
680                       Variadic<Index>:$tagIndices,
681                       Index:$numElements);
682  let assemblyFormat = [{
683    $tagMemRef `[` $tagIndices `]` `,` $numElements attr-dict `:`
684    type($tagMemRef)
685  }];
686  let extraClassDeclaration = [{
687    /// Returns the rank (number of indices) of the tag memref.
688    unsigned getTagMemRefRank() {
689      return getTagMemRef().getType().cast<MemRefType>().getRank();
690    }
691  }];
692  let hasFolder = 1;
693  let hasVerifier = 1;
694}
695
696//===----------------------------------------------------------------------===//
697// GenericAtomicRMWOp
698//===----------------------------------------------------------------------===//
699
700def GenericAtomicRMWOp : MemRef_Op<"generic_atomic_rmw", [
701      SingleBlockImplicitTerminator<"AtomicYieldOp">,
702      TypesMatchWith<"result type matches element type of memref",
703                     "memref", "result",
704                     "$_self.cast<MemRefType>().getElementType()">
705    ]> {
706  let summary = "atomic read-modify-write operation with a region";
707  let description = [{
708    The `memref.generic_atomic_rmw` operation provides a way to perform a
709    read-modify-write sequence that is free from data races. The memref operand
710    represents the buffer that the read and write will be performed against, as
711    accessed by the specified indices. The arity of the indices is the rank of
712    the memref. The result represents the latest value that was stored. The
713    region contains the code for the modification itself. The entry block has
714    a single argument that represents the value stored in `memref[indices]`
715    before the write is performed. No side-effecting ops are allowed in the
716    body of `GenericAtomicRMWOp`.
717
718    Example:
719
720    ```mlir
721    %x = memref.generic_atomic_rmw %I[%i] : memref<10xf32> {
722      ^bb0(%current_value : f32):
723        %c1 = arith.constant 1.0 : f32
724        %inc = arith.addf %c1, %current_value : f32
725        memref.atomic_yield %inc : f32
726    }
727    ```
728  }];
729
730  let arguments = (ins
731      MemRefOf<[AnySignlessInteger, AnyFloat]>:$memref,
732      Variadic<Index>:$indices);
733
734  let results = (outs
735      AnyTypeOf<[AnySignlessInteger, AnyFloat]>:$result);
736
737  let regions = (region AnyRegion:$atomic_body);
738
739  let skipDefaultBuilders = 1;
740  let builders = [OpBuilder<(ins "Value":$memref, "ValueRange":$ivs)>];
741
742  let extraClassDeclaration = [{
743    // TODO: remove post migrating callers.
744    Region &body() { return getRegion(); }
745
746    // The value stored in memref[ivs].
747    Value getCurrentValue() {
748      return getRegion().getArgument(0);
749    }
750    MemRefType getMemRefType() {
751      return getMemref().getType().cast<MemRefType>();
752    }
753  }];
754  let hasCustomAssemblyFormat = 1;
755  let hasVerifier = 1;
756}
757
758def AtomicYieldOp : MemRef_Op<"atomic_yield", [
759      HasParent<"GenericAtomicRMWOp">,
760      NoSideEffect,
761      Terminator
762    ]> {
763  let summary = "yield operation for GenericAtomicRMWOp";
764  let description = [{
765    "memref.atomic_yield" yields an SSA value from a
766    GenericAtomicRMWOp region.
767  }];
768
769  let arguments = (ins AnyType:$result);
770  let assemblyFormat = "$result attr-dict `:` type($result)";
771  let hasVerifier = 1;
772}
773
774//===----------------------------------------------------------------------===//
775// GetGlobalOp
776//===----------------------------------------------------------------------===//
777
778def MemRef_GetGlobalOp : MemRef_Op<"get_global",
779    [NoSideEffect, DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
780  let summary = "get the memref pointing to a global variable";
781  let description = [{
782     The `memref.get_global` operation retrieves the memref pointing to a
783     named global variable. If the global variable is marked constant, writing
784     to the result memref (such as through a `memref.store` operation) is
785     undefined.
786
787     Example:
788
789     ```mlir
790     %x = memref.get_global @foo : memref<2xf32>
791     ```
792  }];
793
794  let arguments = (ins FlatSymbolRefAttr:$name);
795  let results = (outs AnyStaticShapeMemRef:$result);
796  let assemblyFormat = "$name `:` type($result) attr-dict";
797}
798
799//===----------------------------------------------------------------------===//
800// GlobalOp
801//===----------------------------------------------------------------------===//
802
803def MemRef_GlobalOp : MemRef_Op<"global", [Symbol]> {
804  let summary = "declare or define a global memref variable";
805  let description = [{
806    The `memref.global` operation declares or defines a named global memref
807    variable. The backing memory for the variable is allocated statically and is
808    described by the type of the variable (which should be a statically shaped
809    memref type). The operation is a declaration if no `initial_value` is
810    specified, else it is a definition. The `initial_value` can either be a unit
811    attribute to represent a definition of an uninitialized global variable, or
812    an elements attribute to represent the definition of a global variable with
813    an initial value. The global variable can also be marked constant using the
814    `constant` unit attribute. Writing to such constant global variables is
815    undefined.
816
817    The global variable can be accessed by using the `memref.get_global` to
818    retrieve the memref for the global variable. Note that the memref
819    for such global variable itself is immutable (i.e., memref.get_global for a
820    given global variable will always return the same memref descriptor).
821
822    Example:
823
824    ```mlir
825    // Private variable with an initial value.
826    memref.global "private" @x : memref<2xf32> = dense<0.0,2.0>
827
828    // Private variable with an initial value and an alignment (power of 2).
829    memref.global "private" @x : memref<2xf32> = dense<0.0,2.0> {alignment = 64}
830
831    // Declaration of an external variable.
832    memref.global "private" @y : memref<4xi32>
833
834    // Uninitialized externally visible variable.
835    memref.global @z : memref<3xf16> = uninitialized
836
837    // Externally visible constant variable.
838    memref.global constant @c : memref<2xi32> = dense<1, 4>
839    ```
840  }];
841
842  let arguments = (ins SymbolNameAttr:$sym_name,
843                       OptionalAttr<StrAttr>:$sym_visibility,
844                       MemRefTypeAttr:$type,
845                       OptionalAttr<AnyAttr>:$initial_value,
846                       UnitAttr:$constant,
847                       OptionalAttr<I64Attr>:$alignment);
848
849  let assemblyFormat = [{
850       ($sym_visibility^)?
851       (`constant` $constant^)?
852       $sym_name `:`
853       custom<GlobalMemrefOpTypeAndInitialValue>($type, $initial_value)
854       attr-dict
855  }];
856
857  let extraClassDeclaration = [{
858     bool isExternal() { return !getInitialValue(); }
859     bool isUninitialized() {
860       return !isExternal() && getInitialValue()->isa<UnitAttr>();
861     }
862     /// Returns the constant initial value if the memref.global is a constant,
863     /// or null otherwise.
864     ElementsAttr getConstantInitValue();
865  }];
866  let hasVerifier = 1;
867}
868
869//===----------------------------------------------------------------------===//
870// LoadOp
871//===----------------------------------------------------------------------===//
872
873def LoadOp : MemRef_Op<"load",
874     [TypesMatchWith<"result type matches element type of 'memref'",
875                     "memref", "result",
876                     "$_self.cast<MemRefType>().getElementType()">,
877                     MemRefsNormalizable]> {
878  let summary = "load operation";
879  let description = [{
880    The `load` op reads an element from a memref specified by an index list. The
881    output of load is a new value with the same type as the elements of the
882    memref. The arity of indices is the rank of the memref (i.e., if the memref
883    loaded from is of rank 3, then 3 indices are required for the load following
884    the memref identifier).
885
886    In an `affine.if` or `affine.for` body, the indices of a load are restricted
887    to SSA values bound to surrounding loop induction variables,
888    [symbols](Affine.md/#dimensions-and-symbols), results of a
889    constant operations, or the result of an
890    `affine.apply` operation that can in turn take as arguments all of the
891    aforementioned SSA values or the recursively result of such an
892    `affine.apply` operation.
893
894    Example:
895
896    ```mlir
897    %1 = affine.apply affine_map<(d0, d1) -> (3*d0)> (%i, %j)
898    %2 = affine.apply affine_map<(d0, d1) -> (d1+1)> (%i, %j)
899    %12 = memref.load %A[%1, %2] : memref<8x?xi32, #layout, memspace0>
900
901    // Example of an indirect load (treated as non-affine)
902    %3 = affine.apply affine_map<(d0) -> (2*d0 + 1)>(%12)
903    %13 = memref.load %A[%3, %2] : memref<4x?xi32, #layout, memspace0>
904    ```
905
906    **Context:** The `load` and `store` operations are specifically crafted to
907    fully resolve a reference to an element of a memref, and (in affine
908    `affine.if` and `affine.for` operations) the compiler can follow use-def
909    chains (e.g. through [`affine.apply`](Affine.md/#affineapply-affineapplyop)
910    operations) to precisely analyze references at compile-time using polyhedral
911    techniques. This is possible because of the
912    [restrictions on dimensions and symbols](Affine.md/#restrictions-on-dimensions-and-symbols)
913    in these contexts.
914  }];
915
916  let arguments = (ins Arg<AnyMemRef, "the reference to load from",
917                           [MemRead]>:$memref,
918                       Variadic<Index>:$indices);
919  let results = (outs AnyType:$result);
920
921  let builders = [
922    OpBuilder<(ins "Value":$memref, CArg<"ValueRange", "{}">:$indices), [{
923      auto memrefType = memref.getType().cast<MemRefType>();
924      $_state.addOperands(memref);
925      $_state.addOperands(indices);
926      $_state.types.push_back(memrefType.getElementType());
927    }]>];
928
929  let extraClassDeclaration = [{
930    Value getMemRef() { return getOperand(0); }
931    void setMemRef(Value value) { setOperand(0, value); }
932    MemRefType getMemRefType() {
933      return getMemRef().getType().cast<MemRefType>();
934    }
935  }];
936
937  let hasFolder = 1;
938  let hasVerifier = 1;
939
940  let assemblyFormat = "$memref `[` $indices `]` attr-dict `:` type($memref)";
941}
942
943//===----------------------------------------------------------------------===//
944// PrefetchOp
945//===----------------------------------------------------------------------===//
946
947def MemRef_PrefetchOp : MemRef_Op<"prefetch"> {
948  let summary = "prefetch operation";
949  let description = [{
950    The "prefetch" op prefetches data from a memref location described with
951    subscript indices similar to memref.load, and with three attributes: a
952    read/write specifier, a locality hint, and a cache type specifier as shown
953    below:
954
955    ```mlir
956    memref.prefetch %0[%i, %j], read, locality<3>, data : memref<400x400xi32>
957    ```
958
959    The read/write specifier is either 'read' or 'write', the locality hint
960    ranges from locality<0> (no locality) to locality<3> (extremely local keep
961    in cache). The cache type specifier is either 'data' or 'instr'
962    and specifies whether the prefetch is performed on data cache or on
963    instruction cache.
964  }];
965
966  let arguments = (ins AnyMemRef:$memref, Variadic<Index>:$indices,
967                       BoolAttr:$isWrite,
968                       Confined<I32Attr, [IntMinValue<0>,
969                                          IntMaxValue<3>]>:$localityHint,
970                       BoolAttr:$isDataCache);
971
972  let extraClassDeclaration = [{
973    MemRefType getMemRefType() {
974      return getMemref().getType().cast<MemRefType>();
975    }
976    static StringRef getLocalityHintAttrStrName() { return "localityHint"; }
977    static StringRef getIsWriteAttrStrName() { return "isWrite"; }
978    static StringRef getIsDataCacheAttrStrName() { return "isDataCache"; }
979  }];
980
981  let hasCustomAssemblyFormat = 1;
982  let hasFolder = 1;
983  let hasVerifier = 1;
984}
985
986//===----------------------------------------------------------------------===//
987// ReinterpretCastOp
988//===----------------------------------------------------------------------===//
989
990def MemRef_ReinterpretCastOp
991  : MemRef_OpWithOffsetSizesAndStrides<"reinterpret_cast", [
992      NoSideEffect, AttrSizedOperandSegments, ViewLikeOpInterface,
993      OffsetSizeAndStrideOpInterface, MemRefsNormalizable
994    ]> {
995  let summary = "memref reinterpret cast operation";
996  let description = [{
997    Modify offset, sizes and strides of an unranked/ranked memref.
998
999    Example:
1000    ```mlir
1001    memref.reinterpret_cast %ranked to
1002      offset: [0],
1003      sizes: [%size0, 10],
1004      strides: [1, %stride1]
1005    : memref<?x?xf32> to memref<?x10xf32, offset: 0, strides: [1, ?]>
1006
1007    memref.reinterpret_cast %unranked to
1008      offset: [%offset],
1009      sizes: [%size0, %size1],
1010      strides: [%stride0, %stride1]
1011    : memref<*xf32> to memref<?x?xf32, offset: ?, strides: [?, ?]>
1012    ```
1013  }];
1014
1015  let arguments = (ins Arg<AnyRankedOrUnrankedMemRef, "", []>:$source,
1016                       Variadic<Index>:$offsets,
1017                       Variadic<Index>:$sizes,
1018                       Variadic<Index>:$strides,
1019                       I64ArrayAttr:$static_offsets,
1020                       I64ArrayAttr:$static_sizes,
1021                       I64ArrayAttr:$static_strides);
1022  let results = (outs AnyMemRef:$result);
1023
1024  let assemblyFormat = [{
1025    $source `to` `offset` `` `:`
1026    custom<OperandsOrIntegersOffsetsOrStridesList>($offsets, $static_offsets)
1027    `` `,` `sizes` `` `:`
1028    custom<OperandsOrIntegersSizesList>($sizes, $static_sizes) `` `,` `strides`
1029    `` `:`
1030    custom<OperandsOrIntegersOffsetsOrStridesList>($strides, $static_strides)
1031    attr-dict `:` type($source) `to` type($result)
1032  }];
1033
1034  let hasVerifier = 1;
1035
1036  let builders = [
1037    // Build a ReinterpretCastOp with mixed static and dynamic entries.
1038    OpBuilder<(ins "MemRefType":$resultType, "Value":$source,
1039      "OpFoldResult":$offset, "ArrayRef<OpFoldResult>":$sizes,
1040      "ArrayRef<OpFoldResult>":$strides,
1041      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
1042    // Build a ReinterpretCastOp with static entries.
1043    OpBuilder<(ins "MemRefType":$resultType, "Value":$source,
1044      "int64_t":$offset, "ArrayRef<int64_t>":$sizes,
1045      "ArrayRef<int64_t>":$strides,
1046      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
1047    // Build a ReinterpretCastOp with dynamic entries.
1048    OpBuilder<(ins "MemRefType":$resultType, "Value":$source,
1049      "Value":$offset, "ValueRange":$sizes,
1050      "ValueRange":$strides,
1051      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
1052  ];
1053
1054  let extraClassDeclaration = extraBaseClassDeclaration # [{
1055    // The result of the op is always a ranked memref.
1056    MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
1057    Value getViewSource() { return getSource(); }
1058
1059    /// Return the rank of the source ShapedType.
1060    unsigned getResultRank() {
1061      return getResult().getType().cast<ShapedType>().getRank();
1062    }
1063
1064    /// Return the expected rank of each of the`static_offsets`, `static_sizes`
1065    /// and `static_strides` attributes.
1066    std::array<unsigned, 3> getArrayAttrMaxRanks() {
1067      unsigned resultRank = getResult().getType().cast<ShapedType>().getRank();
1068      return {1, resultRank, resultRank};
1069    }
1070
1071    /// Return the number of leading operands before the `offsets`, `sizes` and
1072    /// and `strides` operands.
1073    static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 1; }
1074  }];
1075
1076  let hasFolder = 1;
1077}
1078
1079//===----------------------------------------------------------------------===//
1080// RankOp
1081//===----------------------------------------------------------------------===//
1082
1083def MemRef_RankOp : MemRef_Op<"rank", [NoSideEffect]> {
1084  let summary = "rank operation";
1085  let description = [{
1086    The `memref.rank` operation takes a memref operand and returns its rank.
1087
1088    Example:
1089
1090    ```mlir
1091    %0 = memref.rank %arg0 : memref<*xf32>
1092    %1 = memref.rank %arg1 : memref<?x?xf32>
1093    ```
1094  }];
1095
1096  let arguments = (ins AnyRankedOrUnrankedMemRef:$memref);
1097  let results = (outs Index);
1098
1099  let hasFolder = 1;
1100  let assemblyFormat = "$memref attr-dict `:` type($memref)";
1101}
1102
1103//===----------------------------------------------------------------------===//
1104// ReshapeOp
1105//===----------------------------------------------------------------------===//
1106
1107def MemRef_ReshapeOp: MemRef_Op<"reshape", [
1108    ViewLikeOpInterface, NoSideEffect]>  {
1109  let summary = "memref reshape operation";
1110  let description = [{
1111    The `reshape` operation converts a memref from one type to an
1112    equivalent type with a provided shape. The data is never copied or
1113    modified. The source and destination types are compatible if both have the
1114    same element type, same number of elements, address space and identity
1115    layout map. The following combinations are possible:
1116
1117    a. Source type is ranked or unranked. Shape argument has static size.
1118    Result type is ranked.
1119
1120    ```mlir
1121    // Reshape statically-shaped memref.
1122    %dst = memref.reshape %src(%shape)
1123             : (memref<4x1xf32>, memref<1xi32>) to memref<4xf32>
1124    %dst0 = memref.reshape %src(%shape0)
1125             : (memref<4x1xf32>, memref<2xi32>) to memref<2x2xf32>
1126    // Flatten unranked memref.
1127    %dst = memref.reshape %src(%shape)
1128             : (memref<*xf32>, memref<1xi32>) to memref<?xf32>
1129    ```
1130
1131    b. Source type is ranked or unranked. Shape argument has dynamic size.
1132    Result type is unranked.
1133
1134    ```mlir
1135    // Reshape dynamically-shaped 1D memref.
1136    %dst = memref.reshape %src(%shape)
1137             : (memref<?xf32>, memref<?xi32>) to memref<*xf32>
1138    // Reshape unranked memref.
1139    %dst = memref.reshape %src(%shape)
1140             : (memref<*xf32>, memref<?xi32>) to memref<*xf32>
1141    ```
1142  }];
1143
1144  let arguments = (ins AnyRankedOrUnrankedMemRef:$source,
1145                       MemRefRankOf<[AnySignlessInteger, Index], [1]>:$shape);
1146  let results = (outs AnyRankedOrUnrankedMemRef:$result);
1147
1148  let builders = [OpBuilder<
1149     (ins "MemRefType":$resultType, "Value":$operand, "Value":$shape), [{
1150       $_state.addOperands(operand);
1151       $_state.addOperands(shape);
1152       $_state.addTypes(resultType);
1153     }]>];
1154
1155  let extraClassDeclaration = [{
1156    MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
1157    Value getViewSource() { return getSource(); }
1158  }];
1159
1160  let assemblyFormat = [{
1161    $source `(` $shape `)` attr-dict `:` functional-type(operands, results)
1162  }];
1163  let hasVerifier = 1;
1164}
1165
1166//===----------------------------------------------------------------------===//
1167// ExpandShapeOp / CollapseShapeOp
1168//===----------------------------------------------------------------------===//
1169
1170class MemRef_ReassociativeReshapeOp<string mnemonic, list<Trait> traits = []> :
1171    MemRef_Op<mnemonic, !listconcat(traits,
1172      [NoSideEffect, ViewLikeOpInterface])>,
1173    Arguments<(ins AnyStridedMemRef:$src, IndexListArrayAttr:$reassociation)>,
1174    Results<(outs AnyStridedMemRef:$result)>{
1175
1176  code commonExtraClassDeclaration = [{
1177    SmallVector<AffineMap, 4> getReassociationMaps();
1178
1179    SmallVector<ReassociationExprs, 4> getReassociationExprs();
1180
1181    SmallVector<ReassociationIndices, 4> getReassociationIndices() {
1182      SmallVector<ReassociationIndices, 4> reassociationIndices;
1183      for (auto attr : getReassociation())
1184        reassociationIndices.push_back(llvm::to_vector<2>(
1185            llvm::map_range(attr.cast<ArrayAttr>(), [&](Attribute indexAttr) {
1186              return indexAttr.cast<IntegerAttr>().getInt();
1187            })));
1188      return reassociationIndices;
1189    };
1190
1191    MemRefType getSrcType() { return getSrc().getType().cast<MemRefType>(); }
1192
1193    MemRefType getResultType() { return getResult().getType().cast<MemRefType>(); }
1194
1195    Value getViewSource() { return getSrc(); }
1196  }];
1197
1198  let assemblyFormat = [{
1199    $src $reassociation attr-dict `:` type($src) `into` type($result)
1200  }];
1201
1202  let hasFolder = 1;
1203  let hasCanonicalizer = 1;
1204  let hasVerifier = 1;
1205}
1206
1207def MemRef_ExpandShapeOp : MemRef_ReassociativeReshapeOp<"expand_shape"> {
1208  let summary = "operation to produce a memref with a higher rank.";
1209  let description = [{
1210    The `memref.expand_shape` op produces a new view with a higher rank whose
1211    sizes are a reassociation of the original `view`. The operation is limited
1212    to such reassociations, where a dimension is expanded into one or multiple
1213    contiguous dimensions. Such reassociations never require additional allocs
1214    or copies.
1215
1216    A reassociation is defined as a grouping of dimensions and is represented
1217    with an array of I64ArrayAttr attributes.
1218
1219    Example:
1220
1221    ```mlir
1222    %r = memref.expand_shape %0 [[0, 1], [2]]
1223        : memref<?x?xf32> into memref<?x5x?xf32>
1224    ```
1225
1226    At most one dimension of a reassociation group (e.g., [0, 1] above) may be
1227    dynamic in the result type. Otherwise, the op would be ambiguous, as it
1228    would not be clear how the source dimension is extended.
1229
1230    If an op can be statically proven to be invalid (e.g, an expansion from
1231    `memref<10xf32>` to `memref<2x6xf32>`), it is rejected by the verifier. If
1232    it cannot statically be proven invalid (e.g., the full example above; it is
1233    unclear whether the first source dimension is divisible by 5), the op is
1234    accepted by the verifier. However, if the op is in fact invalid at runtime,
1235    the behavior is undefined.
1236
1237    The source memref can be zero-ranked. In that case, the reassociation
1238    indices must be empty and the result shape may only consist of unit
1239    dimensions.
1240
1241    For simplicity, this op may not be used to cast dynamicity of dimension
1242    sizes and/or strides. I.e., if and only if a source dimension is dynamic,
1243    there must be a dynamic result dimension in the corresponding reassociation
1244    group. Same for strides.
1245
1246    Note: This op currently assumes that the inner strides are of the
1247    source/result layout map are the faster-varying ones.
1248  }];
1249
1250  let builders = [
1251    // Builders using ReassociationIndices.
1252    OpBuilder<(ins "Type":$resultType, "Value":$src,
1253      "ArrayRef<ReassociationIndices>":$reassociation,
1254      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
1255    [{
1256      build($_builder, $_state, resultType, src, attrs);
1257      $_state.addAttribute("reassociation",
1258                          getReassociationIndicesAttribute($_builder, reassociation));
1259    }]>,
1260
1261    // Builder using ReassociationExprs.
1262    OpBuilder<(ins "Type":$resultType, "Value":$src,
1263      "ArrayRef<ReassociationExprs>":$reassociation,
1264      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
1265    [{
1266      auto reassociationMaps =
1267          convertReassociationMapsToIndices($_builder, reassociation);
1268      build($_builder, $_state, resultType, src, reassociationMaps, attrs);
1269    }]>,
1270
1271    // Builder that infers the result layout map. The result shape must be
1272    // specified. Otherwise, the op may be ambiguous.
1273    OpBuilder<(ins "ArrayRef<int64_t>":$resultShape, "Value":$src,
1274               "ArrayRef<ReassociationIndices>":$reassociation)>
1275  ];
1276  let extraClassDeclaration = commonExtraClassDeclaration;
1277  let hasVerifier = 1;
1278}
1279
1280def MemRef_CollapseShapeOp : MemRef_ReassociativeReshapeOp<"collapse_shape"> {
1281  let summary = "operation to produce a memref with a smaller rank.";
1282  let description = [{
1283    The `memref.collapse_shape` op produces a new view with a smaller rank
1284    whose sizes are a reassociation of the original `view`. The operation is
1285    limited to such reassociations, where subsequent, contiguous dimensions are
1286    collapsed into a single dimension. Such reassociations never require
1287    additional allocs or copies.
1288
1289    Collapsing non-contiguous dimensions is undefined behavior. When a group of
1290    dimensions can be statically proven to be non-contiguous, collapses of such
1291    groups are rejected in the verifier on a best-effort basis. In the general
1292    case, collapses of dynamically-sized dims with dynamic strides cannot be
1293    proven to be contiguous or non-contiguous due to limitations in the memref
1294    type.
1295
1296    A reassociation is defined as a continuous grouping of dimensions and is
1297    represented with an array of I64ArrayAttr attribute.
1298
1299    Note: Only the dimensions within a reassociation group must be contiguous.
1300    The remaining dimensions may be non-contiguous.
1301
1302    The result memref type can be zero-ranked if the source memref type is
1303    statically shaped with all dimensions being unit extent. In such a case, the
1304    reassociation indices must be empty.
1305
1306    Examples:
1307
1308    ```mlir
1309    // Dimension collapse (i, j) -> i' and k -> k'
1310    %1 = memref.collapse_shape %0 [[0, 1], [2]] :
1311        memref<?x?x?xf32, stride_spec> into memref<?x?xf32, stride_spec_2>
1312    ```
1313
1314    For simplicity, this op may not be used to cast dynamicity of dimension
1315    sizes and/or strides. I.e., a result dimension must be dynamic if and only
1316    if at least one dimension in the corresponding reassociation group is
1317    dynamic. Similarly, the stride of a result dimension must be dynamic if and
1318    only if the corresponding start dimension in the source type is dynamic.
1319
1320    Note: This op currently assumes that the inner strides are of the
1321    source/result layout map are the faster-varying ones.
1322  }];
1323  let builders = [
1324    // Builders for a contracting reshape whose result type is computed from
1325    // `src` and `reassociation`.
1326    OpBuilder<(ins "Value":$src,
1327      "ArrayRef<ReassociationIndices>":$reassociation,
1328      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
1329    OpBuilder<(ins "Value":$src,
1330      "ArrayRef<ReassociationExprs>":$reassociation,
1331      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
1332    [{
1333      auto reassociationMaps =
1334          convertReassociationMapsToIndices($_builder, reassociation);
1335      build($_builder, $_state, src, reassociationMaps, attrs);
1336    }]>,
1337
1338    // Builders for a reshape whose result type is passed explicitly.
1339    OpBuilder<(ins "Type":$resultType, "Value":$src,
1340      "ArrayRef<ReassociationIndices>":$reassociation,
1341      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
1342    [{
1343      build($_builder, $_state, resultType, src, attrs);
1344      $_state.addAttribute("reassociation",
1345                          getReassociationIndicesAttribute($_builder, reassociation));
1346    }]>,
1347    OpBuilder<(ins "Type":$resultType, "Value":$src,
1348      "ArrayRef<ReassociationExprs>":$reassociation,
1349      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
1350    [{
1351      auto reassociationMaps =
1352          convertReassociationMapsToIndices($_builder, reassociation);
1353      build($_builder, $_state, resultType, src, reassociationMaps, attrs);
1354    }]>
1355  ];
1356  let extraClassDeclaration = commonExtraClassDeclaration # [{
1357    /// Return `true` if this source MemRef type is guaranteed to be collapsible
1358    /// according to the given reassociation indices. In the presence of dynamic
1359    /// strides this is usually not the case.
1360    static bool isGuaranteedCollapsible(
1361        MemRefType srcType, ArrayRef<ReassociationIndices> reassociation);
1362  }];
1363
1364  let hasVerifier = 1;
1365}
1366
1367//===----------------------------------------------------------------------===//
1368// StoreOp
1369//===----------------------------------------------------------------------===//
1370
1371def MemRef_StoreOp : MemRef_Op<"store",
1372     [TypesMatchWith<"type of 'value' matches element type of 'memref'",
1373                     "memref", "value",
1374                     "$_self.cast<MemRefType>().getElementType()">,
1375                     MemRefsNormalizable]> {
1376  let summary = "store operation";
1377  let description = [{
1378    Store a value to a memref location given by indices. The value stored should
1379    have the same type as the elemental type of the memref. The number of
1380    arguments provided within brackets need to match the rank of the memref.
1381
1382    In an affine context, the indices of a store are restricted to SSA values
1383    bound to surrounding loop induction variables,
1384    [symbols](Affine.md/#restrictions-on-dimensions-and-symbols), results of a
1385    `constant` operation, or the result of an
1386    [`affine.apply`](Affine.md/#affineapply-affineapplyop) operation that can in
1387    turn take as arguments all of the aforementioned SSA values or the
1388    recursively result of such an `affine.apply` operation.
1389
1390    Example:
1391
1392    ```mlir
1393    memref.store %100, %A[%1, 1023] : memref<4x?xf32, #layout, memspace0>
1394    ```
1395
1396    **Context:** The `load` and `store` operations are specifically crafted to
1397    fully resolve a reference to an element of a memref, and (in polyhedral
1398    `affine.if` and `affine.for` operations) the compiler can follow use-def
1399    chains (e.g. through [`affine.apply`](Affine.md/#affineapply-affineapplyop)
1400    operations) to precisely analyze references at compile-time using polyhedral
1401    techniques. This is possible because of the
1402    [restrictions on dimensions and symbols](Affine.md/#restrictions-on-dimensions-and-symbols)
1403    in these contexts.
1404  }];
1405
1406  let arguments = (ins AnyType:$value,
1407                       Arg<AnyMemRef, "the reference to store to",
1408                           [MemWrite]>:$memref,
1409                       Variadic<Index>:$indices);
1410
1411  let builders = [
1412    OpBuilder<(ins "Value":$valueToStore, "Value":$memref), [{
1413      $_state.addOperands(valueToStore);
1414      $_state.addOperands(memref);
1415    }]>];
1416
1417  let extraClassDeclaration = [{
1418      Value getValueToStore() { return getOperand(0); }
1419
1420      Value getMemRef() { return getOperand(1); }
1421      void setMemRef(Value value) { setOperand(1, value); }
1422      MemRefType getMemRefType() {
1423        return getMemRef().getType().cast<MemRefType>();
1424      }
1425  }];
1426
1427  let hasFolder = 1;
1428  let hasVerifier = 1;
1429
1430  let assemblyFormat = [{
1431    $value `,` $memref `[` $indices `]` attr-dict `:` type($memref)
1432  }];
1433}
1434
1435//===----------------------------------------------------------------------===//
1436// SubViewOp
1437//===----------------------------------------------------------------------===//
1438
1439def SubViewOp : MemRef_OpWithOffsetSizesAndStrides<"subview", [
1440    DeclareOpInterfaceMethods<ViewLikeOpInterface>, NoSideEffect,
1441    AttrSizedOperandSegments, OffsetSizeAndStrideOpInterface
1442  ]> {
1443  let summary = "memref subview operation";
1444  let description = [{
1445    The "subview" operation converts a memref type to another memref type
1446    which represents a reduced-size view of the original memref as specified by
1447    the operation's offsets, sizes and strides arguments.
1448
1449    The SubView operation supports the following arguments:
1450
1451    * source: the "base" memref on which to create a "view" memref.
1452    * offsets: memref-rank number of offsets into the "base" memref at which to
1453               create the "view" memref.
1454    * sizes: memref-rank number of sizes which specify the sizes of the result
1455             "view" memref type.
1456    * strides: memref-rank number of strides that compose multiplicatively with
1457               the base memref strides in each dimension.
1458
1459    The representation based on offsets, sizes and strides support a
1460    partially-static specification via attributes specified through the
1461    `static_offsets`, `static_sizes` and `static_strides` arguments. A special
1462    sentinel value ShapedType::kDynamicSize and
1463    ShapedType::kDynamicStrideOrOffset encodes that the corresponding entry has
1464    a dynamic value.
1465
1466    A subview operation may additionally reduce the rank of the resulting view
1467    by removing dimensions that are statically known to be of size 1.
1468
1469    Example 1:
1470
1471    ```mlir
1472    %0 = memref.alloc() : memref<64x4xf32, affine_map<(d0, d1) -> (d0 * 4 + d1)>>
1473
1474    // Create a sub-view of "base" memref '%0' with offset arguments '%c0',
1475    // dynamic sizes for each dimension, and stride arguments '%c1'.
1476    %1 = memref.subview %0[%c0, %c0][%size0, %size1][%c1, %c1]
1477      : memref<64x4xf32, affine_map<(d0, d1) -> (d0 * 4 + d1)>> to
1478        memref<?x?xf32, affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + d1 + s0)>>
1479    ```
1480
1481    Example 2:
1482
1483    ```mlir
1484    %0 = memref.alloc() : memref<8x16x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>>
1485
1486    // Create a sub-view of "base" memref '%0' with dynamic offsets, sizes,
1487    // and strides.
1488    // Note that dynamic offsets are represented by the linearized dynamic
1489    // offset symbol 's0' in the subview memref layout map, and that the
1490    // dynamic strides operands, after being applied to the base memref
1491    // strides in each dimension, are represented in the view memref layout
1492    // map as symbols 's1', 's2' and 's3'.
1493    %1 = memref.subview %0[%i, %j, %k][%size0, %size1, %size2][%x, %y, %z]
1494      : memref<8x16x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>> to
1495        memref<?x?x?xf32,
1496          affine_map<(d0, d1, d2)[s0, s1, s2, s3] -> (d0 * s1 + d1 * s2 + d2 * s3 + s0)>>
1497    ```
1498
1499    Example 3:
1500
1501    ```mlir
1502    %0 = memref.alloc() : memref<8x16x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>>
1503
1504    // Subview with constant offsets, sizes and strides.
1505    %1 = memref.subview %0[0, 2, 0][4, 4, 4][1, 1, 1]
1506      : memref<8x16x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>> to
1507        memref<4x4x4xf32, affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2 + 8)>>
1508    ```
1509
1510    Example 4:
1511
1512    ```mlir
1513    %0 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>
1514
1515    // Subview with constant size, but dynamic offsets and
1516    // strides. The resulting memref has a static shape, but if the
1517    // base memref has an affine map to describe the layout, the result
1518    // memref also uses an affine map to describe the layout. The
1519    // strides of the result memref is computed as follows:
1520    //
1521    // Let #map1 represents the layout of the base memref, and #map2
1522    // represents the layout of the result memref. A #mapsubview can be
1523    // constructed to map an index from the result memref to the base
1524    // memref (note that the description below uses more convenient
1525    // naming for symbols, while in affine maps, symbols are
1526    // represented as unsigned numbers that identify that symbol in the
1527    // given affine map.
1528    //
1529    // #mapsubview = (d0, d1)[o0, o1, t0, t1] -> (d0 * t0 + o0, d1 * t1 + o1)
1530    //
1531    // where, o0, o1, ... are offsets, and t0, t1, ... are strides. Then,
1532    //
1533    // #map2 = #map1.compose(#mapsubview)
1534    //
1535    // If the layout map is represented as
1536    //
1537    // #map1 = (d0, d1)[s0, s1, s2] -> (d0 * s1 + d1 * s2 + s0)
1538    //
1539    // then,
1540    //
1541    // #map2 = (d0, d1)[s0, s1, s2, o0, o1, t0, t1] ->
1542    //              (d0 * s1 * t0 + d1 * s2 * t1 + o0 * s1 + o1 * s2 + s0)
1543    //
1544    // Representing this canonically
1545    //
1546    // #map2 = (d0, d1)[r0, r1, r2] -> (d0 * r1 + d1 * r2 + r0)
1547    //
1548    // where, r0 = o0 * s1 + o1 * s2 + s0, r1 = s1 * t0, r2 = s2 * t1.
1549    %1 = memref.subview %0[%i, %j][4, 4][%x, %y] :
1550      : memref<?x?xf32, affine_map<(d0, d1)[s0, s1, s2] -> (d0 * s1 + d1 * s2 + s0)>> to
1551        memref<4x4xf32, affine_map<(d0, d1)[r0, r1, r2] -> (d0 * r1 + d1 * r2 + r0)>>
1552
1553    // Note that the subview op does not guarantee that the result
1554    // memref is "inbounds" w.r.t to base memref. It is upto the client
1555    // to ensure that the subview is accessed in a manner that is
1556    // in-bounds.
1557    ```
1558
1559    Example 5:
1560
1561    ```mlir
1562    // Rank-reducing subview.
1563    %1 = memref.subview %0[0, 0, 0][1, 16, 4][1, 1, 1] :
1564      memref<8x16x4xf32> to memref<16x4xf32>
1565
1566    // Original layout:
1567    // (d0, d1, d2) -> (64 * d0 + 16 * d1 + d2)
1568    // Subviewed layout:
1569    // (d0, d1, d2) -> (64 * (d0 + 3) + 4 * (d1 + 4) + d2 + 2) = (64 * d0 + 4 * d1 + d2 + 210)
1570    // After rank reducing:
1571    // (d0, d1) -> (4 * d0 + d1 + 210)
1572    %3 = memref.subview %2[3, 4, 2][1, 6, 3][1, 1, 1] :
1573      memref<8x16x4xf32> to memref<6x3xf32, offset: 210, strides: [4, 1]>
1574    ```
1575    }
1576  }];
1577
1578  let arguments = (ins AnyMemRef:$source,
1579                       Variadic<Index>:$offsets,
1580                       Variadic<Index>:$sizes,
1581                       Variadic<Index>:$strides,
1582                       I64ArrayAttr:$static_offsets,
1583                       I64ArrayAttr:$static_sizes,
1584                       I64ArrayAttr:$static_strides);
1585  let results = (outs AnyMemRef:$result);
1586
1587  let assemblyFormat = [{
1588    $source ``
1589    custom<OperandsOrIntegersOffsetsOrStridesList>($offsets, $static_offsets)
1590    custom<OperandsOrIntegersSizesList>($sizes, $static_sizes)
1591    custom<OperandsOrIntegersOffsetsOrStridesList>($strides, $static_strides)
1592    attr-dict `:` type($source) `to` type($result)
1593  }];
1594
1595  let builders = [
1596    // Build a SubViewOp with mixed static and dynamic entries and custom
1597    // result type. If the type passed is nullptr, it is inferred.
1598    OpBuilder<(ins "Value":$source, "ArrayRef<OpFoldResult>":$offsets,
1599      "ArrayRef<OpFoldResult>":$sizes, "ArrayRef<OpFoldResult>":$strides,
1600      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
1601    // Build a SubViewOp with mixed static and dynamic entries and inferred
1602    // result type.
1603    OpBuilder<(ins "MemRefType":$resultType, "Value":$source,
1604      "ArrayRef<OpFoldResult>":$offsets, "ArrayRef<OpFoldResult>":$sizes,
1605      "ArrayRef<OpFoldResult>":$strides,
1606      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
1607    // Build a SubViewOp with static entries and custom result type. If the
1608    // type passed is nullptr, it is inferred.
1609    OpBuilder<(ins "Value":$source, "ArrayRef<int64_t>":$offsets,
1610      "ArrayRef<int64_t>":$sizes, "ArrayRef<int64_t>":$strides,
1611      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
1612    // Build a SubViewOp with static entries and inferred result type.
1613    OpBuilder<(ins "MemRefType":$resultType, "Value":$source,
1614      "ArrayRef<int64_t>":$offsets, "ArrayRef<int64_t>":$sizes,
1615      "ArrayRef<int64_t>":$strides,
1616      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
1617    // Build a SubViewOp with dynamic entries and custom result type. If the
1618    // type passed is nullptr, it is inferred.
1619    OpBuilder<(ins "Value":$source, "ValueRange":$offsets,
1620      "ValueRange":$sizes, "ValueRange":$strides,
1621      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
1622    // Build a SubViewOp with dynamic entries and inferred result type.
1623    OpBuilder<(ins "MemRefType":$resultType, "Value":$source,
1624      "ValueRange":$offsets, "ValueRange":$sizes, "ValueRange":$strides,
1625      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
1626  ];
1627
1628  let extraClassDeclaration = extraBaseClassDeclaration # [{
1629    /// Returns the type of the base memref operand.
1630    MemRefType getSourceType() {
1631      return getSource().getType().cast<MemRefType>();
1632    }
1633
1634    /// The result of a subview is always a memref.
1635    MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
1636
1637    /// A subview result type can be fully inferred from the source type and the
1638    /// static representation of offsets, sizes and strides. Special sentinels
1639    /// encode the dynamic case.
1640    static Type inferResultType(MemRefType sourceMemRefType,
1641                                ArrayRef<int64_t> staticOffsets,
1642                                ArrayRef<int64_t> staticSizes,
1643                                ArrayRef<int64_t> staticStrides);
1644    static Type inferResultType(MemRefType sourceMemRefType,
1645                                ArrayRef<OpFoldResult> staticOffsets,
1646                                ArrayRef<OpFoldResult> staticSizes,
1647                                ArrayRef<OpFoldResult> staticStrides);
1648
1649    /// A rank-reducing result type can be inferred from the desired result
1650    /// shape. Only the layout map is inferred.
1651    ///
1652    /// Note: The result shape cannot be inferred with just the result rank and
1653    /// and the desired sizes. In case there are more "ones" among the sizes
1654    /// than the difference in source/result rank, it is not clear which dims of
1655    /// size one should be dropped.
1656    static Type inferRankReducedResultType(ArrayRef<int64_t> resultShape,
1657                                           MemRefType sourceMemRefType,
1658                                           ArrayRef<int64_t> staticOffsets,
1659                                           ArrayRef<int64_t> staticSizes,
1660                                           ArrayRef<int64_t> staticStrides);
1661    static Type inferRankReducedResultType(ArrayRef<int64_t> resultShape,
1662                                           MemRefType sourceMemRefType,
1663                                           ArrayRef<OpFoldResult> staticOffsets,
1664                                           ArrayRef<OpFoldResult> staticSizes,
1665                                           ArrayRef<OpFoldResult> staticStrides);
1666
1667    /// Return the expected rank of each of the`static_offsets`, `static_sizes`
1668    /// and `static_strides` attributes.
1669    std::array<unsigned, 3> getArrayAttrMaxRanks() {
1670      unsigned rank = getSourceType().getRank();
1671      return {rank, rank, rank};
1672    }
1673
1674    /// Return the number of leading operands before the `offsets`, `sizes` and
1675    /// and `strides` operands.
1676    static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 1; }
1677
1678    /// Return the dimensions of the source type that are dropped when
1679    /// the result is rank-reduced.
1680    llvm::SmallBitVector getDroppedDims();
1681  }];
1682
1683  let hasCanonicalizer = 1;
1684  let hasFolder = 1;
1685  let hasVerifier = 1;
1686}
1687
1688//===----------------------------------------------------------------------===//
1689// TensorStoreOp
1690//===----------------------------------------------------------------------===//
1691
1692def TensorStoreOp : MemRef_Op<"tensor_store",
1693    [SameOperandsShape, SameOperandsElementType,
1694     TypesMatchWith<"type of 'value' matches tensor equivalent of 'memref'",
1695                    "memref", "tensor",
1696                    "getTensorTypeFromMemRefType($_self)">]> {
1697  let summary = "tensor store operation";
1698  let description = [{
1699    Stores the contents of a tensor into a memref. The first operand is a value
1700    of tensor type, the second operand is a value of memref type. The shapes and
1701    element types of these must match, and are specified by the memref type.
1702
1703    Example:
1704
1705    ```mlir
1706    %9 = dim %8, 1 : tensor<4x?xf32>
1707    %10 = memref.alloc(%9) : memref<4x?xf32, #layout, memspace0>
1708    memref.tensor_store %8, %10 : memref<4x?xf32, #layout, memspace0>
1709    ```
1710  }];
1711
1712  let arguments = (ins AnyTensor:$tensor, Arg<AnyRankedOrUnrankedMemRef,
1713                       "the reference to store to", [MemWrite]>:$memref);
1714
1715  let assemblyFormat = "$tensor `,` $memref attr-dict `:` type($memref)";
1716}
1717
1718//===----------------------------------------------------------------------===//
1719// TransposeOp
1720//===----------------------------------------------------------------------===//
1721
1722def MemRef_TransposeOp : MemRef_Op<"transpose", [NoSideEffect]>,
1723    Arguments<(ins AnyStridedMemRef:$in, AffineMapAttr:$permutation)>,
1724    Results<(outs AnyStridedMemRef)> {
1725  let summary = "`transpose` produces a new strided memref (metadata-only)";
1726  let description = [{
1727    The `transpose` op produces a strided memref whose sizes and strides
1728    are a permutation of the original `in` memref. This is purely a metadata
1729    transformation.
1730
1731    Example:
1732
1733    ```mlir
1734    %1 = memref.transpose %0 (i, j) -> (j, i) : memref<?x?xf32> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d1 * s0 + d0)>>
1735    ```
1736  }];
1737
1738  let builders = [
1739    OpBuilder<(ins "Value":$in, "AffineMapAttr":$permutation,
1740      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>];
1741
1742  let extraClassDeclaration = [{
1743    static StringRef getPermutationAttrStrName() { return "permutation"; }
1744    ShapedType getShapedType() { return getIn().getType().cast<ShapedType>(); }
1745  }];
1746
1747  let hasCustomAssemblyFormat = 1;
1748  let hasFolder = 1;
1749  let hasVerifier = 1;
1750}
1751
1752//===----------------------------------------------------------------------===//
1753// ViewOp
1754//===----------------------------------------------------------------------===//
1755
1756def MemRef_ViewOp : MemRef_Op<"view", [
1757    DeclareOpInterfaceMethods<ViewLikeOpInterface>, NoSideEffect]> {
1758  let summary = "memref view operation";
1759  let description = [{
1760    The "view" operation extracts an N-D contiguous memref with empty layout map
1761    with arbitrary element type from a 1-D contiguous memref with empty layout
1762    map of i8 element  type. The ViewOp supports the following arguments:
1763
1764    * A single dynamic byte-shift operand must be specified which represents a
1765      a shift of the base 1-D memref pointer from which to create the resulting
1766      contiguous memref view with identity layout.
1767    * A dynamic size operand that must be specified for each dynamic dimension
1768      in the resulting view memref type.
1769
1770    The "view" operation gives a structured indexing form to a flat 1-D buffer.
1771    Unlike "subview" it can perform a type change. The type change behavior
1772    requires the op to have special semantics because, e.g. a byte shift of 3
1773    cannot be represented as an offset on f64.
1774    For now, a "view" op:
1775
1776    1. Only takes a contiguous source memref with 0 offset and empty layout.
1777    2. Must specify a byte_shift operand (in the future, a special integer
1778       attribute may be added to support the folded case).
1779    3. Returns a contiguous memref with 0 offset and empty layout.
1780
1781    Example:
1782
1783    ```mlir
1784    // Allocate a flat 1D/i8 memref.
1785    %0 = memref.alloc() : memref<2048xi8>
1786
1787    // ViewOp with dynamic offset and static sizes.
1788    %1 = memref.view %0[%offset_1024][] : memref<2048xi8> to memref<64x4xf32>
1789
1790    // ViewOp with dynamic offset and two dynamic size.
1791    %2 = memref.view %0[%offset_1024][%size0, %size1] :
1792      memref<2048xi8> to memref<?x4x?xf32>
1793    ```
1794  }];
1795
1796  let arguments = (ins MemRefRankOf<[I8], [1]>:$source,
1797                       Index:$byte_shift,
1798                       Variadic<Index>:$sizes);
1799  let results = (outs AnyMemRef);
1800
1801  let extraClassDeclaration = [{
1802    /// The result of a view is always a memref.
1803    MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
1804
1805    /// Returns the dynamic sizes for this view operation. This is redundant
1806    /// with `sizes` but needed in template implementations. More specifically:
1807    /// ```
1808    /// template <typename AnyMemRefDefOp>
1809    /// bool isMemRefSizeValidSymbol(AnyMemRefDefOp memrefDefOp, unsigned index,
1810    ///                              Region *region)
1811    /// ```
1812    operand_range getDynamicSizes() {
1813      return {getSizes().begin(), getSizes().end()};
1814    }
1815  }];
1816
1817  let assemblyFormat = [{
1818    $source `[` $byte_shift `]` `` `[` $sizes `]` attr-dict
1819    `:` type($source) `to` type(results)
1820  }];
1821
1822  let hasCanonicalizer = 1;
1823  let hasVerifier = 1;
1824}
1825
1826//===----------------------------------------------------------------------===//
1827// AtomicRMWOp
1828//===----------------------------------------------------------------------===//
1829
1830def AtomicRMWOp : MemRef_Op<"atomic_rmw", [
1831      AllTypesMatch<["value", "result"]>,
1832      TypesMatchWith<"value type matches element type of memref",
1833                     "memref", "value",
1834                     "$_self.cast<MemRefType>().getElementType()">
1835    ]> {
1836  let summary = "atomic read-modify-write operation";
1837  let description = [{
1838    The `memref.atomic_rmw` operation provides a way to perform a read-modify-write
1839    sequence that is free from data races. The kind enumeration specifies the
1840    modification to perform. The value operand represents the new value to be
1841    applied during the modification. The memref operand represents the buffer
1842    that the read and write will be performed against, as accessed by the
1843    specified indices. The arity of the indices is the rank of the memref. The
1844    result represents the latest value that was stored.
1845
1846    Example:
1847
1848    ```mlir
1849    %x = memref.atomic_rmw "addf" %value, %I[%i] : (f32, memref<10xf32>) -> f32
1850    ```
1851  }];
1852
1853  let arguments = (ins
1854      AtomicRMWKindAttr:$kind,
1855      AnyTypeOf<[AnySignlessInteger, AnyFloat]>:$value,
1856      MemRefOf<[AnySignlessInteger, AnyFloat]>:$memref,
1857      Variadic<Index>:$indices);
1858  let results = (outs AnyTypeOf<[AnySignlessInteger, AnyFloat]>:$result);
1859
1860  let assemblyFormat = [{
1861    $kind $value `,` $memref `[` $indices `]` attr-dict `:` `(` type($value) `,`
1862    type($memref) `)` `->` type($result)
1863  }];
1864
1865  let extraClassDeclaration = [{
1866    MemRefType getMemRefType() {
1867      return getMemref().getType().cast<MemRefType>();
1868    }
1869  }];
1870  let hasFolder = 1;
1871  let hasVerifier = 1;
1872}
1873
1874#endif // MEMREF_OPS
1875