1//===- ViewLikeInterface.td - ViewLike interface -----------*- 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// Defines the interface for view-like operations.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_INTERFACES_VIEWLIKEINTERFACE
14#define MLIR_INTERFACES_VIEWLIKEINTERFACE
15
16include "mlir/IR/OpBase.td"
17
18def ViewLikeOpInterface : OpInterface<"ViewLikeOpInterface"> {
19  let description = [{
20    A view-like operation "views" a buffer in a potentially different way. It
21    takes in a (view of) buffer (and potentially some other operands) and returns
22    another view of buffer.
23  }];
24  let cppNamespace = "::mlir";
25
26  let methods = [
27    InterfaceMethod<
28      "Returns the source buffer from which the view is created.",
29      "::mlir::Value", "getViewSource">
30  ];
31}
32
33def OffsetSizeAndStrideOpInterface : OpInterface<"OffsetSizeAndStrideOpInterface"> {
34  let description = [{
35    Common interface for ops that allow specifying mixed dynamic and static
36    offsets, sizes and strides variadic operands.
37    Ops that implement this interface need to expose the following methods:
38      1. `getArrayAttrMaxRanks` to specify the length of static integer
39          attributes.
40      2. `offsets`, `sizes` and `strides` variadic operands.
41      3. `static_offsets`, resp. `static_sizes` and `static_strides` integer
42          array attributes.
43      4. `getOffsetSizeAndStrideStartOperandIndex` method that specifies the
44         starting index of the OffsetSizeAndStrideOpInterface operands
45
46    The invariants of this interface are:
47      1. `static_offsets`, `static_sizes` and `static_strides` have length
48          exactly `getArrayAttrMaxRanks()`[0] (resp. [1], [2]).
49      2. `offsets`, `sizes` and `strides` have each length at most
50         `getArrayAttrMaxRanks()`[0] (resp. [1], [2]).
51      3. if an entry of `static_offsets` (resp. `static_sizes`,
52         `static_strides`) is equal to a special sentinel value, namely
53         `ShapedType::kDynamicStrideOrOffset` (resp. `ShapedType::kDynamicSize`,
54         `ShapedType::kDynamicStrideOrOffset`), then the corresponding entry is
55         a dynamic offset (resp. size, stride).
56      4. a variadic `offset` (resp. `sizes`, `strides`) operand  must be present
57         for each dynamic offset (resp. size, stride).
58      5. `offsets`, `sizes` and `strides` operands are specified in this order
59         at operand index starting at `getOffsetSizeAndStrideStartOperandIndex`.
60
61    This interface is useful to factor out common behavior and provide support
62    for carrying or injecting static behavior through the use of the static
63    attributes.
64  }];
65
66  let cppNamespace = "::mlir";
67
68  let methods = [
69    StaticInterfaceMethod<
70      /*desc=*/[{
71        Return the number of leading operands before the `offsets`, `sizes` and
72        and `strides` operands.
73      }],
74      /*retTy=*/"unsigned",
75      /*methodName=*/"getOffsetSizeAndStrideStartOperandIndex",
76      /*args=*/(ins)
77    >,
78    InterfaceMethod<
79      /*desc=*/[{
80        Return the expected rank of each of the`static_offsets`, `static_sizes`
81        and `static_strides` attributes.
82      }],
83      /*retTy=*/"std::array<unsigned, 3>",
84      /*methodName=*/"getArrayAttrMaxRanks",
85      /*args=*/(ins)
86    >,
87    InterfaceMethod<
88      /*desc=*/[{
89        Return the dynamic offset operands.
90      }],
91      /*retTy=*/"::mlir::OperandRange",
92      /*methodName=*/"offsets",
93      /*args=*/(ins),
94      /*methodBody=*/"",
95      /*defaultImplementation=*/[{
96        return $_op.offsets();
97      }]
98    >,
99    InterfaceMethod<
100      /*desc=*/[{
101        Return the dynamic size operands.
102      }],
103      /*retTy=*/"::mlir::OperandRange",
104      /*methodName=*/"sizes",
105      /*args=*/(ins),
106      /*methodBody=*/"",
107      /*defaultImplementation=*/[{
108        return $_op.sizes();
109      }]
110    >,
111    InterfaceMethod<
112      /*desc=*/[{
113        Return the dynamic stride operands.
114      }],
115      /*retTy=*/"::mlir::OperandRange",
116      /*methodName=*/"strides",
117      /*args=*/(ins),
118      /*methodBody=*/"",
119      /*defaultImplementation=*/[{
120        return $_op.strides();
121      }]
122    >,
123    InterfaceMethod<
124      /*desc=*/[{
125        Return the static offset attributes.
126      }],
127      /*retTy=*/"::mlir::ArrayAttr",
128      /*methodName=*/"static_offsets",
129      /*args=*/(ins),
130      /*methodBody=*/"",
131      /*defaultImplementation=*/[{
132        return $_op.static_offsets();
133      }]
134    >,
135    InterfaceMethod<
136      /*desc=*/[{
137        Return the static size attributes.
138      }],
139      /*retTy=*/"::mlir::ArrayAttr",
140      /*methodName=*/"static_sizes",
141      /*args=*/(ins),
142      /*methodBody=*/"",
143      /*defaultImplementation=*/[{
144        return $_op.static_sizes();
145      }]
146    >,
147    InterfaceMethod<
148      /*desc=*/[{
149        Return the dynamic stride attributes.
150      }],
151      /*retTy=*/"::mlir::ArrayAttr",
152      /*methodName=*/"static_strides",
153      /*args=*/(ins),
154      /*methodBody=*/"",
155      /*defaultImplementation=*/[{
156        return $_op.static_strides();
157      }]
158    >,
159    InterfaceMethod<
160      /*desc=*/[{
161        Return a vector of all the static or dynamic sizes of the op.
162      }],
163      /*retTy=*/"::llvm::SmallVector<::mlir::OpFoldResult, 4>",
164      /*methodName=*/"getMixedOffsets",
165      /*args=*/(ins),
166      /*methodBody=*/"",
167      /*defaultImplementation=*/[{
168        return ::mlir::getMixedOffsets($_op, $_op.static_offsets(),
169                                       $_op.offsets());
170      }]
171    >,
172    InterfaceMethod<
173      /*desc=*/[{
174        Return a vector of all the static or dynamic sizes of the op.
175      }],
176      /*retTy=*/"::llvm::SmallVector<::mlir::OpFoldResult, 4>",
177      /*methodName=*/"getMixedSizes",
178      /*args=*/(ins),
179      /*methodBody=*/"",
180      /*defaultImplementation=*/[{
181        return ::mlir::getMixedSizes($_op, $_op.static_sizes(), $_op.sizes());
182      }]
183    >,
184    InterfaceMethod<
185      /*desc=*/[{
186        Return a vector of all the static or dynamic strides of the op.
187      }],
188      /*retTy=*/"::llvm::SmallVector<::mlir::OpFoldResult, 4>",
189      /*methodName=*/"getMixedStrides",
190      /*args=*/(ins),
191      /*methodBody=*/"",
192      /*defaultImplementation=*/[{
193        return ::mlir::getMixedStrides($_op, $_op.static_strides(),
194                                       $_op.strides());
195      }]
196    >,
197
198    InterfaceMethod<
199      /*desc=*/[{
200        Return true if the offset `idx` is dynamic.
201      }],
202      /*retTy=*/"bool",
203      /*methodName=*/"isDynamicOffset",
204      /*args=*/(ins "unsigned":$idx),
205      /*methodBody=*/"",
206      /*defaultImplementation=*/[{
207        ::llvm::APInt v = *(static_offsets()
208          .template getAsValueRange<::mlir::IntegerAttr>().begin() + idx);
209        return ::mlir::ShapedType::isDynamicStrideOrOffset(v.getSExtValue());
210      }]
211    >,
212    InterfaceMethod<
213      /*desc=*/[{
214        Return true if the size `idx` is dynamic.
215      }],
216      /*retTy=*/"bool",
217      /*methodName=*/"isDynamicSize",
218      /*args=*/(ins "unsigned":$idx),
219      /*methodBody=*/"",
220      /*defaultImplementation=*/[{
221        ::llvm::APInt v = *(static_sizes()
222          .template getAsValueRange<::mlir::IntegerAttr>().begin() + idx);
223        return ::mlir::ShapedType::isDynamic(v.getSExtValue());
224      }]
225    >,
226    InterfaceMethod<
227      /*desc=*/[{
228       Return true if the stride `idx` is dynamic.
229      }],
230      /*retTy=*/"bool",
231      /*methodName=*/"isDynamicStride",
232      /*args=*/(ins "unsigned":$idx),
233      /*methodBody=*/"",
234      /*defaultImplementation=*/[{
235        ::llvm::APInt v = *(static_strides()
236          .template getAsValueRange<::mlir::IntegerAttr>().begin() + idx);
237        return ::mlir::ShapedType::isDynamicStrideOrOffset(v.getSExtValue());
238      }]
239    >,
240
241    InterfaceMethod<
242      /*desc=*/[{
243        Assert the offset `idx` is a static constant and return its value.
244      }],
245      /*retTy=*/"int64_t",
246      /*methodName=*/"getStaticOffset",
247      /*args=*/(ins "unsigned":$idx),
248      /*methodBody=*/"",
249      /*defaultImplementation=*/[{
250        assert(!$_op.isDynamicOffset(idx) && "expected static offset");
251        ::llvm::APInt v = *(static_offsets().
252          template getAsValueRange<::mlir::IntegerAttr>().begin() + idx);
253        return v.getSExtValue();
254      }]
255    >,
256    InterfaceMethod<
257      /*desc=*/[{
258        Assert the size `idx` is a static constant and return its value.
259      }],
260      /*retTy=*/"int64_t",
261      /*methodName=*/"getStaticSize",
262      /*args=*/(ins "unsigned":$idx),
263      /*methodBody=*/"",
264      /*defaultImplementation=*/[{
265        assert(!$_op.isDynamicSize(idx) && "expected static size");
266        ::llvm::APInt v = *(static_sizes().
267          template getAsValueRange<::mlir::IntegerAttr>().begin() + idx);
268        return v.getSExtValue();
269      }]
270    >,
271    InterfaceMethod<
272      /*desc=*/[{
273        Assert the stride `idx` is a static constant and return its value.
274      }],
275      /*retTy=*/"int64_t",
276      /*methodName=*/"getStaticStride",
277      /*args=*/(ins "unsigned":$idx),
278      /*methodBody=*/"",
279      /*defaultImplementation=*/[{
280        assert(!$_op.isDynamicStride(idx) && "expected static stride");
281        ::llvm::APInt v = *(static_strides().
282          template getAsValueRange<::mlir::IntegerAttr>().begin() + idx);
283        return v.getSExtValue();
284      }]
285    >,
286
287    InterfaceMethod<
288      /*desc=*/[{
289        Assert the offset `idx` is dynamic and return the position of the
290        corresponding operand.
291      }],
292      /*retTy=*/"unsigned",
293      /*methodName=*/"getIndexOfDynamicOffset",
294      /*args=*/(ins "unsigned":$idx),
295      /*methodBody=*/"",
296      /*defaultImplementation=*/[{
297        assert($_op.isDynamicOffset(idx) && "expected dynamic offset");
298        auto numDynamic = getNumDynamicEntriesUpToIdx(
299          static_offsets().template cast<::mlir::ArrayAttr>(),
300          ::mlir::ShapedType::isDynamicStrideOrOffset,
301          idx);
302        return $_op.getOffsetSizeAndStrideStartOperandIndex() + numDynamic;
303      }]
304    >,
305    InterfaceMethod<
306      /*desc=*/[{
307        Assert the size `idx` is dynamic and return the position of the
308        corresponding operand.
309      }],
310      /*retTy=*/"unsigned",
311      /*methodName=*/"getIndexOfDynamicSize",
312      /*args=*/(ins "unsigned":$idx),
313      /*methodBody=*/"",
314      /*defaultImplementation=*/[{
315        assert($_op.isDynamicSize(idx) && "expected dynamic size");
316        auto numDynamic = getNumDynamicEntriesUpToIdx(
317          static_sizes().template cast<::mlir::ArrayAttr>(), ::mlir::ShapedType::isDynamic, idx);
318        return $_op.getOffsetSizeAndStrideStartOperandIndex() +
319          offsets().size() + numDynamic;
320      }]
321    >,
322    InterfaceMethod<
323      /*desc=*/[{
324        Assert the stride `idx` is dynamic and return the position of the
325        corresponding operand.
326      }],
327      /*retTy=*/"unsigned",
328      /*methodName=*/"getIndexOfDynamicStride",
329      /*args=*/(ins "unsigned":$idx),
330      /*methodBody=*/"",
331      /*defaultImplementation=*/[{
332        assert($_op.isDynamicStride(idx) && "expected dynamic stride");
333        auto numDynamic = getNumDynamicEntriesUpToIdx(
334          static_strides().template cast<::mlir::ArrayAttr>(),
335          ::mlir::ShapedType::isDynamicStrideOrOffset,
336          idx);
337        return $_op.getOffsetSizeAndStrideStartOperandIndex() +
338          offsets().size() + sizes().size() + numDynamic;
339      }]
340    >,
341    InterfaceMethod<
342      /*desc=*/[{
343        Helper method to compute the number of dynamic entries of `attr`, up to
344        `idx` using `isDynamic` to determine whether an entry is dynamic.
345      }],
346      /*retTy=*/"unsigned",
347      /*methodName=*/"getNumDynamicEntriesUpToIdx",
348      /*args=*/(ins "::mlir::ArrayAttr":$attr,
349                    "::llvm::function_ref<bool(int64_t)>":$isDynamic,
350                    "unsigned":$idx),
351      /*methodBody=*/"",
352      /*defaultImplementation=*/[{
353        return std::count_if(
354          attr.getValue().begin(), attr.getValue().begin() + idx,
355          [&](::mlir::Attribute attr) {
356            return isDynamic(attr.cast<::mlir::IntegerAttr>().getInt());
357          });
358      }]
359    >,
360
361    InterfaceMethod<
362      /*desc=*/[{
363        Assert the offset `idx` is dynamic and return its value.
364      }],
365      /*retTy=*/"::mlir::Value",
366      /*methodName=*/"getDynamicOffset",
367      /*args=*/(ins "unsigned":$idx),
368      /*methodBody=*/"",
369      /*defaultImplementation=*/[{
370        return $_op.getOperand(getIndexOfDynamicOffset(idx));
371      }]
372    >,
373    InterfaceMethod<
374      /*desc=*/[{
375        Assert the size `idx` is dynamic and return its value.
376      }],
377      /*retTy=*/"::mlir::Value",
378      /*methodName=*/"getDynamicSize",
379      /*args=*/(ins "unsigned":$idx),
380      /*methodBody=*/"",
381      /*defaultImplementation=*/[{
382        return $_op.getOperand(getIndexOfDynamicSize(idx));
383      }]
384    >,
385    InterfaceMethod<
386      /*desc=*/[{
387        Assert the stride `idx` is dynamic and return its value.
388      }],
389      /*retTy=*/"::mlir::Value",
390      /*methodName=*/"getDynamicStride",
391      /*args=*/(ins "unsigned":$idx),
392      /*methodBody=*/"",
393      /*defaultImplementation=*/[{
394        return $_op.getOperand(getIndexOfDynamicStride(idx));
395      }]
396    >,
397    InterfaceMethod<
398      /*desc=*/[{
399        Return true if all `other`'s offsets, sizes and strides are the same.
400        Takes a custom `cmp` comparison function on OpFoldResult to avoid taking
401        a dialect dependence.
402      }],
403      /*retTy=*/"bool",
404      /*methodName=*/"isSameAs",
405      /*args=*/(ins "::mlir::OffsetSizeAndStrideOpInterface":$other,
406                   "::llvm::function_ref<bool(::mlir::OpFoldResult, ::mlir::OpFoldResult)>":$cmp),
407      /*methodBody=*/"",
408      /*defaultImplementation=*/[{
409        return ::mlir::detail::sameOffsetsSizesAndStrides(
410          ::mlir::cast<::mlir::OffsetSizeAndStrideOpInterface>(
411            $_op.getOperation()), other, cmp);
412      }]
413    >,
414    InterfaceMethod<
415      /*desc=*/[{ Return true if all strides are guaranteed to be 1. }],
416      /*retTy=*/"bool",
417      /*methodName=*/"hasUnitStride",
418      /*args=*/(ins),
419      /*methodBody=*/"",
420      /*defaultImplementation=*/[{
421        return ::llvm::all_of(getMixedStrides(), [](::mlir::OpFoldResult ofr) {
422          return ::mlir::getConstantIntValue(ofr) == static_cast<int64_t>(1);
423        });
424      }]
425    >,
426    InterfaceMethod<
427      /*desc=*/[{ Return true if all offsets are guaranteed to be 0. }],
428      /*retTy=*/"bool",
429      /*methodName=*/"hasZeroOffset",
430      /*args=*/(ins),
431      /*methodBody=*/"",
432      /*defaultImplementation=*/[{
433        return ::llvm::all_of(getMixedOffsets(), [](::mlir::OpFoldResult ofr) {
434          return ::mlir::getConstantIntValue(ofr) == static_cast<int64_t>(0);
435        });
436      }]
437    >,
438  ];
439
440  let extraClassDeclaration = [{
441    static unsigned getOffsetOperandGroupPosition() { return 0; }
442    static unsigned getSizeOperandGroupPosition() { return 1; }
443    static unsigned getStrideOperandGroupPosition() { return 2; }
444    static ::llvm::StringRef getStaticOffsetsAttrName() {
445      return "static_offsets";
446    }
447    static ::llvm::StringRef getStaticSizesAttrName() {
448      return "static_sizes";
449    }
450    static ::llvm::StringRef getStaticStridesAttrName() {
451      return "static_strides";
452    }
453    static ::llvm::ArrayRef<::llvm::StringRef> getSpecialAttrNames() {
454      static ::llvm::SmallVector<::llvm::StringRef, 4> names{
455        ::mlir::OffsetSizeAndStrideOpInterface::getStaticOffsetsAttrName(),
456        ::mlir::OffsetSizeAndStrideOpInterface::getStaticSizesAttrName(),
457        ::mlir::OffsetSizeAndStrideOpInterface::getStaticStridesAttrName(),
458        ::mlir::OpTrait::AttrSizedOperandSegments<void>::getOperandSegmentSizeAttr()};
459      return names;
460    }
461  }];
462
463  let verify = [{
464    return ::mlir::detail::verifyOffsetSizeAndStrideOp(
465        ::mlir::cast<::mlir::OffsetSizeAndStrideOpInterface>($_op));
466  }];
467}
468
469#endif // MLIR_INTERFACES_VIEWLIKEINTERFACE
470