MLIR  16.0.0git
BuiltinTypes.cpp
Go to the documentation of this file.
1 //===- BuiltinTypes.cpp - MLIR Builtin Type Classes -----------------------===//
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 #include "mlir/IR/BuiltinTypes.h"
10 #include "TypeDetail.h"
11 #include "mlir/IR/AffineExpr.h"
12 #include "mlir/IR/AffineMap.h"
14 #include "mlir/IR/BuiltinDialect.h"
15 #include "mlir/IR/Diagnostics.h"
16 #include "mlir/IR/Dialect.h"
19 #include "mlir/IR/TensorEncoding.h"
20 #include "llvm/ADT/APFloat.h"
21 #include "llvm/ADT/BitVector.h"
22 #include "llvm/ADT/Sequence.h"
23 #include "llvm/ADT/Twine.h"
24 #include "llvm/ADT/TypeSwitch.h"
25 
26 using namespace mlir;
27 using namespace mlir::detail;
28 
29 //===----------------------------------------------------------------------===//
30 /// Tablegen Type Definitions
31 //===----------------------------------------------------------------------===//
32 
33 #define GET_TYPEDEF_CLASSES
34 #include "mlir/IR/BuiltinTypes.cpp.inc"
35 
36 //===----------------------------------------------------------------------===//
37 // BuiltinDialect
38 //===----------------------------------------------------------------------===//
39 
40 void BuiltinDialect::registerTypes() {
41  addTypes<
42 #define GET_TYPEDEF_LIST
43 #include "mlir/IR/BuiltinTypes.cpp.inc"
44  >();
45 }
46 
47 //===----------------------------------------------------------------------===//
48 /// ComplexType
49 //===----------------------------------------------------------------------===//
50 
51 /// Verify the construction of an integer type.
53  Type elementType) {
54  if (!elementType.isIntOrFloat())
55  return emitError() << "invalid element type for complex";
56  return success();
57 }
58 
59 //===----------------------------------------------------------------------===//
60 // Integer Type
61 //===----------------------------------------------------------------------===//
62 
63 /// Verify the construction of an integer type.
65  unsigned width,
66  SignednessSemantics signedness) {
67  if (width > IntegerType::kMaxWidth) {
68  return emitError() << "integer bitwidth is limited to "
69  << IntegerType::kMaxWidth << " bits";
70  }
71  return success();
72 }
73 
74 unsigned IntegerType::getWidth() const { return getImpl()->width; }
75 
76 IntegerType::SignednessSemantics IntegerType::getSignedness() const {
77  return getImpl()->signedness;
78 }
79 
80 IntegerType IntegerType::scaleElementBitwidth(unsigned scale) {
81  if (!scale)
82  return IntegerType();
83  return IntegerType::get(getContext(), scale * getWidth(), getSignedness());
84 }
85 
86 //===----------------------------------------------------------------------===//
87 // Float Type
88 //===----------------------------------------------------------------------===//
89 
90 unsigned FloatType::getWidth() {
91  if (isa<Float16Type, BFloat16Type>())
92  return 16;
93  if (isa<Float32Type>())
94  return 32;
95  if (isa<Float64Type>())
96  return 64;
97  if (isa<Float80Type>())
98  return 80;
99  if (isa<Float128Type>())
100  return 128;
101  llvm_unreachable("unexpected float type");
102 }
103 
104 /// Returns the floating semantics for the given type.
105 const llvm::fltSemantics &FloatType::getFloatSemantics() {
106  if (isa<BFloat16Type>())
107  return APFloat::BFloat();
108  if (isa<Float16Type>())
109  return APFloat::IEEEhalf();
110  if (isa<Float32Type>())
111  return APFloat::IEEEsingle();
112  if (isa<Float64Type>())
113  return APFloat::IEEEdouble();
114  if (isa<Float80Type>())
115  return APFloat::x87DoubleExtended();
116  if (isa<Float128Type>())
117  return APFloat::IEEEquad();
118  llvm_unreachable("non-floating point type used");
119 }
120 
122  if (!scale)
123  return FloatType();
124  MLIRContext *ctx = getContext();
125  if (isF16() || isBF16()) {
126  if (scale == 2)
127  return FloatType::getF32(ctx);
128  if (scale == 4)
129  return FloatType::getF64(ctx);
130  }
131  if (isF32())
132  if (scale == 2)
133  return FloatType::getF64(ctx);
134  return FloatType();
135 }
136 
138  return APFloat::semanticsPrecision(getFloatSemantics());
139 }
140 
141 //===----------------------------------------------------------------------===//
142 // FunctionType
143 //===----------------------------------------------------------------------===//
144 
145 unsigned FunctionType::getNumInputs() const { return getImpl()->numInputs; }
146 
147 ArrayRef<Type> FunctionType::getInputs() const {
148  return getImpl()->getInputs();
149 }
150 
151 unsigned FunctionType::getNumResults() const { return getImpl()->numResults; }
152 
153 ArrayRef<Type> FunctionType::getResults() const {
154  return getImpl()->getResults();
155 }
156 
157 FunctionType FunctionType::clone(TypeRange inputs, TypeRange results) const {
158  return get(getContext(), inputs, results);
159 }
160 
161 /// Returns a new function type with the specified arguments and results
162 /// inserted.
163 FunctionType FunctionType::getWithArgsAndResults(
164  ArrayRef<unsigned> argIndices, TypeRange argTypes,
165  ArrayRef<unsigned> resultIndices, TypeRange resultTypes) {
166  SmallVector<Type> argStorage, resultStorage;
168  getInputs(), argIndices, argTypes, argStorage);
170  getResults(), resultIndices, resultTypes, resultStorage);
171  return clone(newArgTypes, newResultTypes);
172 }
173 
174 /// Returns a new function type without the specified arguments and results.
175 FunctionType
176 FunctionType::getWithoutArgsAndResults(const BitVector &argIndices,
177  const BitVector &resultIndices) {
178  SmallVector<Type> argStorage, resultStorage;
180  getInputs(), argIndices, argStorage);
182  getResults(), resultIndices, resultStorage);
183  return clone(newArgTypes, newResultTypes);
184 }
185 
186 void FunctionType::walkImmediateSubElements(
187  function_ref<void(Attribute)> walkAttrsFn,
188  function_ref<void(Type)> walkTypesFn) const {
189  for (Type type : llvm::concat<const Type>(getInputs(), getResults()))
190  walkTypesFn(type);
191 }
192 
193 Type FunctionType::replaceImmediateSubElements(ArrayRef<Attribute> replAttrs,
194  ArrayRef<Type> replTypes) const {
195  unsigned numInputs = getNumInputs();
196  return get(getContext(), replTypes.take_front(numInputs),
197  replTypes.drop_front(numInputs));
198 }
199 
200 //===----------------------------------------------------------------------===//
201 // OpaqueType
202 //===----------------------------------------------------------------------===//
203 
204 /// Verify the construction of an opaque type.
206  StringAttr dialect, StringRef typeData) {
207  if (!Dialect::isValidNamespace(dialect.strref()))
208  return emitError() << "invalid dialect namespace '" << dialect << "'";
209 
210  // Check that the dialect is actually registered.
211  MLIRContext *context = dialect.getContext();
212  if (!context->allowsUnregisteredDialects() &&
213  !context->getLoadedDialect(dialect.strref())) {
214  return emitError()
215  << "`!" << dialect << "<\"" << typeData << "\">"
216  << "` type created with unregistered dialect. If this is "
217  "intended, please call allowUnregisteredDialects() on the "
218  "MLIRContext, or use -allow-unregistered-dialect with "
219  "the MLIR opt tool used";
220  }
221 
222  return success();
223 }
224 
225 //===----------------------------------------------------------------------===//
226 // VectorType
227 //===----------------------------------------------------------------------===//
228 
230  ArrayRef<int64_t> shape, Type elementType,
231  unsigned numScalableDims) {
232  if (!isValidElementType(elementType))
233  return emitError()
234  << "vector elements must be int/index/float type but got "
235  << elementType;
236 
237  if (any_of(shape, [](int64_t i) { return i <= 0; }))
238  return emitError()
239  << "vector types must have positive constant sizes but got "
240  << shape;
241 
242  return success();
243 }
244 
245 VectorType VectorType::scaleElementBitwidth(unsigned scale) {
246  if (!scale)
247  return VectorType();
248  if (auto et = getElementType().dyn_cast<IntegerType>())
249  if (auto scaledEt = et.scaleElementBitwidth(scale))
250  return VectorType::get(getShape(), scaledEt, getNumScalableDims());
251  if (auto et = getElementType().dyn_cast<FloatType>())
252  if (auto scaledEt = et.scaleElementBitwidth(scale))
253  return VectorType::get(getShape(), scaledEt, getNumScalableDims());
254  return VectorType();
255 }
256 
257 void VectorType::walkImmediateSubElements(
258  function_ref<void(Attribute)> walkAttrsFn,
259  function_ref<void(Type)> walkTypesFn) const {
260  walkTypesFn(getElementType());
261 }
262 
263 Type VectorType::replaceImmediateSubElements(ArrayRef<Attribute> replAttrs,
264  ArrayRef<Type> replTypes) const {
265  return get(getShape(), replTypes.front(), getNumScalableDims());
266 }
267 
268 VectorType VectorType::cloneWith(Optional<ArrayRef<int64_t>> shape,
269  Type elementType) const {
270  return VectorType::get(shape.value_or(getShape()), elementType,
271  getNumScalableDims());
272 }
273 
274 //===----------------------------------------------------------------------===//
275 // TensorType
276 //===----------------------------------------------------------------------===//
277 
280  .Case<RankedTensorType, UnrankedTensorType>(
281  [](auto type) { return type.getElementType(); });
282 }
283 
284 bool TensorType::hasRank() const { return !isa<UnrankedTensorType>(); }
285 
287  return cast<RankedTensorType>().getShape();
288 }
289 
291  Type elementType) const {
292  if (auto unrankedTy = dyn_cast<UnrankedTensorType>()) {
293  if (shape)
294  return RankedTensorType::get(*shape, elementType);
295  return UnrankedTensorType::get(elementType);
296  }
297 
298  auto rankedTy = cast<RankedTensorType>();
299  if (!shape)
300  return RankedTensorType::get(rankedTy.getShape(), elementType,
301  rankedTy.getEncoding());
302  return RankedTensorType::get(shape.value_or(rankedTy.getShape()), elementType,
303  rankedTy.getEncoding());
304 }
305 
306 // Check if "elementType" can be an element type of a tensor.
307 static LogicalResult
309  Type elementType) {
310  if (!TensorType::isValidElementType(elementType))
311  return emitError() << "invalid tensor element type: " << elementType;
312  return success();
313 }
314 
315 /// Return true if the specified element type is ok in a tensor.
317  // Note: Non standard/builtin types are allowed to exist within tensor
318  // types. Dialects are expected to verify that tensor types have a valid
319  // element type within that dialect.
320  return type.isa<ComplexType, FloatType, IntegerType, OpaqueType, VectorType,
321  IndexType>() ||
322  !llvm::isa<BuiltinDialect>(type.getDialect());
323 }
324 
325 //===----------------------------------------------------------------------===//
326 // RankedTensorType
327 //===----------------------------------------------------------------------===//
328 
331  ArrayRef<int64_t> shape, Type elementType,
332  Attribute encoding) {
333  for (int64_t s : shape)
334  if (s < -1)
335  return emitError() << "invalid tensor dimension size";
336  if (auto v = encoding.dyn_cast_or_null<VerifiableTensorEncoding>())
337  if (failed(v.verifyEncoding(shape, elementType, emitError)))
338  return failure();
339  return checkTensorElementType(emitError, elementType);
340 }
341 
342 void RankedTensorType::walkImmediateSubElements(
343  function_ref<void(Attribute)> walkAttrsFn,
344  function_ref<void(Type)> walkTypesFn) const {
345  walkTypesFn(getElementType());
346  if (Attribute encoding = getEncoding())
347  walkAttrsFn(encoding);
348 }
349 
350 Type RankedTensorType::replaceImmediateSubElements(
351  ArrayRef<Attribute> replAttrs, ArrayRef<Type> replTypes) const {
352  return get(getShape(), replTypes.front(),
353  replAttrs.empty() ? Attribute() : replAttrs.back());
354 }
355 
356 //===----------------------------------------------------------------------===//
357 // UnrankedTensorType
358 //===----------------------------------------------------------------------===//
359 
362  Type elementType) {
363  return checkTensorElementType(emitError, elementType);
364 }
365 
366 void UnrankedTensorType::walkImmediateSubElements(
367  function_ref<void(Attribute)> walkAttrsFn,
368  function_ref<void(Type)> walkTypesFn) const {
369  walkTypesFn(getElementType());
370 }
371 
372 Type UnrankedTensorType::replaceImmediateSubElements(
373  ArrayRef<Attribute> replAttrs, ArrayRef<Type> replTypes) const {
374  return get(replTypes.front());
375 }
376 
377 //===----------------------------------------------------------------------===//
378 // BaseMemRefType
379 //===----------------------------------------------------------------------===//
380 
383  .Case<MemRefType, UnrankedMemRefType>(
384  [](auto type) { return type.getElementType(); });
385 }
386 
387 bool BaseMemRefType::hasRank() const { return !isa<UnrankedMemRefType>(); }
388 
390  return cast<MemRefType>().getShape();
391 }
392 
394  Type elementType) const {
395  if (auto unrankedTy = dyn_cast<UnrankedMemRefType>()) {
396  if (!shape)
397  return UnrankedMemRefType::get(elementType, getMemorySpace());
398  MemRefType::Builder builder(*shape, elementType);
399  builder.setMemorySpace(getMemorySpace());
400  return builder;
401  }
402 
403  MemRefType::Builder builder(cast<MemRefType>());
404  if (shape)
405  builder.setShape(*shape);
406  builder.setElementType(elementType);
407  return builder;
408 }
409 
411  if (auto rankedMemRefTy = dyn_cast<MemRefType>())
412  return rankedMemRefTy.getMemorySpace();
413  return cast<UnrankedMemRefType>().getMemorySpace();
414 }
415 
417  if (auto rankedMemRefTy = dyn_cast<MemRefType>())
418  return rankedMemRefTy.getMemorySpaceAsInt();
419  return cast<UnrankedMemRefType>().getMemorySpaceAsInt();
420 }
421 
422 //===----------------------------------------------------------------------===//
423 // MemRefType
424 //===----------------------------------------------------------------------===//
425 
426 /// Given an `originalShape` and a `reducedShape` assumed to be a subset of
427 /// `originalShape` with some `1` entries erased, return the set of indices
428 /// that specifies which of the entries of `originalShape` are dropped to obtain
429 /// `reducedShape`. The returned mask can be applied as a projection to
430 /// `originalShape` to obtain the `reducedShape`. This mask is useful to track
431 /// which dimensions must be kept when e.g. compute MemRef strides under
432 /// rank-reducing operations. Return None if reducedShape cannot be obtained
433 /// by dropping only `1` entries in `originalShape`.
436  ArrayRef<int64_t> reducedShape) {
437  size_t originalRank = originalShape.size(), reducedRank = reducedShape.size();
438  llvm::SmallDenseSet<unsigned> unusedDims;
439  unsigned reducedIdx = 0;
440  for (unsigned originalIdx = 0; originalIdx < originalRank; ++originalIdx) {
441  // Greedily insert `originalIdx` if match.
442  if (reducedIdx < reducedRank &&
443  originalShape[originalIdx] == reducedShape[reducedIdx]) {
444  reducedIdx++;
445  continue;
446  }
447 
448  unusedDims.insert(originalIdx);
449  // If no match on `originalIdx`, the `originalShape` at this dimension
450  // must be 1, otherwise we bail.
451  if (originalShape[originalIdx] != 1)
452  return llvm::None;
453  }
454  // The whole reducedShape must be scanned, otherwise we bail.
455  if (reducedIdx != reducedRank)
456  return llvm::None;
457  return unusedDims;
458 }
459 
461 mlir::isRankReducedType(ShapedType originalType,
462  ShapedType candidateReducedType) {
463  if (originalType == candidateReducedType)
465 
466  ShapedType originalShapedType = originalType.cast<ShapedType>();
467  ShapedType candidateReducedShapedType =
468  candidateReducedType.cast<ShapedType>();
469 
470  // Rank and size logic is valid for all ShapedTypes.
471  ArrayRef<int64_t> originalShape = originalShapedType.getShape();
472  ArrayRef<int64_t> candidateReducedShape =
473  candidateReducedShapedType.getShape();
474  unsigned originalRank = originalShape.size(),
475  candidateReducedRank = candidateReducedShape.size();
476  if (candidateReducedRank > originalRank)
478 
479  auto optionalUnusedDimsMask =
480  computeRankReductionMask(originalShape, candidateReducedShape);
481 
482  // Sizes cannot be matched in case empty vector is returned.
483  if (!optionalUnusedDimsMask)
485 
486  if (originalShapedType.getElementType() !=
487  candidateReducedShapedType.getElementType())
489 
491 }
492 
494  // Empty attribute is allowed as default memory space.
495  if (!memorySpace)
496  return true;
497 
498  // Supported built-in attributes.
499  if (memorySpace.isa<IntegerAttr, StringAttr, DictionaryAttr>())
500  return true;
501 
502  // Allow custom dialect attributes.
503  if (!isa<BuiltinDialect>(memorySpace.getDialect()))
504  return true;
505 
506  return false;
507 }
508 
510  MLIRContext *ctx) {
511  if (memorySpace == 0)
512  return nullptr;
513 
514  return IntegerAttr::get(IntegerType::get(ctx, 64), memorySpace);
515 }
516 
518  IntegerAttr intMemorySpace = memorySpace.dyn_cast_or_null<IntegerAttr>();
519  if (intMemorySpace && intMemorySpace.getValue() == 0)
520  return nullptr;
521 
522  return memorySpace;
523 }
524 
526  if (!memorySpace)
527  return 0;
528 
529  assert(memorySpace.isa<IntegerAttr>() &&
530  "Using `getMemorySpaceInteger` with non-Integer attribute");
531 
532  return static_cast<unsigned>(memorySpace.cast<IntegerAttr>().getInt());
533 }
534 
536 MemRefType::Builder::setMemorySpace(unsigned newMemorySpace) {
537  memorySpace =
538  wrapIntegerMemorySpace(newMemorySpace, elementType.getContext());
539  return *this;
540 }
541 
542 unsigned MemRefType::getMemorySpaceAsInt() const {
543  return detail::getMemorySpaceAsInt(getMemorySpace());
544 }
545 
546 MemRefType MemRefType::get(ArrayRef<int64_t> shape, Type elementType,
547  MemRefLayoutAttrInterface layout,
548  Attribute memorySpace) {
549  // Use default layout for empty attribute.
550  if (!layout)
551  layout = AffineMapAttr::get(AffineMap::getMultiDimIdentityMap(
552  shape.size(), elementType.getContext()));
553 
554  // Drop default memory space value and replace it with empty attribute.
555  memorySpace = skipDefaultMemorySpace(memorySpace);
556 
557  return Base::get(elementType.getContext(), shape, elementType, layout,
558  memorySpace);
559 }
560 
561 MemRefType MemRefType::getChecked(
562  function_ref<InFlightDiagnostic()> emitErrorFn, ArrayRef<int64_t> shape,
563  Type elementType, MemRefLayoutAttrInterface layout, Attribute memorySpace) {
564 
565  // Use default layout for empty attribute.
566  if (!layout)
567  layout = AffineMapAttr::get(AffineMap::getMultiDimIdentityMap(
568  shape.size(), elementType.getContext()));
569 
570  // Drop default memory space value and replace it with empty attribute.
571  memorySpace = skipDefaultMemorySpace(memorySpace);
572 
573  return Base::getChecked(emitErrorFn, elementType.getContext(), shape,
574  elementType, layout, memorySpace);
575 }
576 
577 MemRefType MemRefType::get(ArrayRef<int64_t> shape, Type elementType,
578  AffineMap map, Attribute memorySpace) {
579 
580  // Use default layout for empty map.
581  if (!map)
582  map = AffineMap::getMultiDimIdentityMap(shape.size(),
583  elementType.getContext());
584 
585  // Wrap AffineMap into Attribute.
586  Attribute layout = AffineMapAttr::get(map);
587 
588  // Drop default memory space value and replace it with empty attribute.
589  memorySpace = skipDefaultMemorySpace(memorySpace);
590 
591  return Base::get(elementType.getContext(), shape, elementType, layout,
592  memorySpace);
593 }
594 
595 MemRefType
596 MemRefType::getChecked(function_ref<InFlightDiagnostic()> emitErrorFn,
597  ArrayRef<int64_t> shape, Type elementType, AffineMap map,
598  Attribute memorySpace) {
599 
600  // Use default layout for empty map.
601  if (!map)
602  map = AffineMap::getMultiDimIdentityMap(shape.size(),
603  elementType.getContext());
604 
605  // Wrap AffineMap into Attribute.
606  Attribute layout = AffineMapAttr::get(map);
607 
608  // Drop default memory space value and replace it with empty attribute.
609  memorySpace = skipDefaultMemorySpace(memorySpace);
610 
611  return Base::getChecked(emitErrorFn, elementType.getContext(), shape,
612  elementType, layout, memorySpace);
613 }
614 
615 MemRefType MemRefType::get(ArrayRef<int64_t> shape, Type elementType,
616  AffineMap map, unsigned memorySpaceInd) {
617 
618  // Use default layout for empty map.
619  if (!map)
620  map = AffineMap::getMultiDimIdentityMap(shape.size(),
621  elementType.getContext());
622 
623  // Wrap AffineMap into Attribute.
624  Attribute layout = AffineMapAttr::get(map);
625 
626  // Convert deprecated integer-like memory space to Attribute.
627  Attribute memorySpace =
628  wrapIntegerMemorySpace(memorySpaceInd, elementType.getContext());
629 
630  return Base::get(elementType.getContext(), shape, elementType, layout,
631  memorySpace);
632 }
633 
634 MemRefType
635 MemRefType::getChecked(function_ref<InFlightDiagnostic()> emitErrorFn,
636  ArrayRef<int64_t> shape, Type elementType, AffineMap map,
637  unsigned memorySpaceInd) {
638 
639  // Use default layout for empty map.
640  if (!map)
641  map = AffineMap::getMultiDimIdentityMap(shape.size(),
642  elementType.getContext());
643 
644  // Wrap AffineMap into Attribute.
645  Attribute layout = AffineMapAttr::get(map);
646 
647  // Convert deprecated integer-like memory space to Attribute.
648  Attribute memorySpace =
649  wrapIntegerMemorySpace(memorySpaceInd, elementType.getContext());
650 
651  return Base::getChecked(emitErrorFn, elementType.getContext(), shape,
652  elementType, layout, memorySpace);
653 }
654 
656  ArrayRef<int64_t> shape, Type elementType,
657  MemRefLayoutAttrInterface layout,
658  Attribute memorySpace) {
659  if (!BaseMemRefType::isValidElementType(elementType))
660  return emitError() << "invalid memref element type";
661 
662  // Negative sizes are not allowed except for `-1` that means dynamic size.
663  for (int64_t s : shape)
664  if (s < -1)
665  return emitError() << "invalid memref size";
666 
667  assert(layout && "missing layout specification");
668  if (failed(layout.verifyLayout(shape, emitError)))
669  return failure();
670 
671  if (!isSupportedMemorySpace(memorySpace))
672  return emitError() << "unsupported memory space Attribute";
673 
674  return success();
675 }
676 
677 void MemRefType::walkImmediateSubElements(
678  function_ref<void(Attribute)> walkAttrsFn,
679  function_ref<void(Type)> walkTypesFn) const {
680  walkTypesFn(getElementType());
681  if (!getLayout().isIdentity())
682  walkAttrsFn(getLayout());
683  walkAttrsFn(getMemorySpace());
684 }
685 
686 Type MemRefType::replaceImmediateSubElements(ArrayRef<Attribute> replAttrs,
687  ArrayRef<Type> replTypes) const {
688  bool hasLayout = replAttrs.size() > 1;
689  return get(getShape(), replTypes[0],
690  hasLayout ? replAttrs[0].dyn_cast<MemRefLayoutAttrInterface>()
691  : MemRefLayoutAttrInterface(),
692  hasLayout ? replAttrs[1] : replAttrs[0]);
693 }
694 
695 //===----------------------------------------------------------------------===//
696 // UnrankedMemRefType
697 //===----------------------------------------------------------------------===//
698 
700  return detail::getMemorySpaceAsInt(getMemorySpace());
701 }
702 
705  Type elementType, Attribute memorySpace) {
706  if (!BaseMemRefType::isValidElementType(elementType))
707  return emitError() << "invalid memref element type";
708 
709  if (!isSupportedMemorySpace(memorySpace))
710  return emitError() << "unsupported memory space Attribute";
711 
712  return success();
713 }
714 
715 // Fallback cases for terminal dim/sym/cst that are not part of a binary op (
716 // i.e. single term). Accumulate the AffineExpr into the existing one.
718  AffineExpr multiplicativeFactor,
720  AffineExpr &offset) {
721  if (auto dim = e.dyn_cast<AffineDimExpr>())
722  strides[dim.getPosition()] =
723  strides[dim.getPosition()] + multiplicativeFactor;
724  else
725  offset = offset + e * multiplicativeFactor;
726 }
727 
728 /// Takes a single AffineExpr `e` and populates the `strides` array with the
729 /// strides expressions for each dim position.
730 /// The convention is that the strides for dimensions d0, .. dn appear in
731 /// order to make indexing intuitive into the result.
733  AffineExpr multiplicativeFactor,
735  AffineExpr &offset) {
736  auto bin = e.dyn_cast<AffineBinaryOpExpr>();
737  if (!bin) {
738  extractStridesFromTerm(e, multiplicativeFactor, strides, offset);
739  return success();
740  }
741 
742  if (bin.getKind() == AffineExprKind::CeilDiv ||
743  bin.getKind() == AffineExprKind::FloorDiv ||
744  bin.getKind() == AffineExprKind::Mod)
745  return failure();
746 
747  if (bin.getKind() == AffineExprKind::Mul) {
748  auto dim = bin.getLHS().dyn_cast<AffineDimExpr>();
749  if (dim) {
750  strides[dim.getPosition()] =
751  strides[dim.getPosition()] + bin.getRHS() * multiplicativeFactor;
752  return success();
753  }
754  // LHS and RHS may both contain complex expressions of dims. Try one path
755  // and if it fails try the other. This is guaranteed to succeed because
756  // only one path may have a `dim`, otherwise this is not an AffineExpr in
757  // the first place.
758  if (bin.getLHS().isSymbolicOrConstant())
759  return extractStrides(bin.getRHS(), multiplicativeFactor * bin.getLHS(),
760  strides, offset);
761  return extractStrides(bin.getLHS(), multiplicativeFactor * bin.getRHS(),
762  strides, offset);
763  }
764 
765  if (bin.getKind() == AffineExprKind::Add) {
766  auto res1 =
767  extractStrides(bin.getLHS(), multiplicativeFactor, strides, offset);
768  auto res2 =
769  extractStrides(bin.getRHS(), multiplicativeFactor, strides, offset);
770  return success(succeeded(res1) && succeeded(res2));
771  }
772 
773  llvm_unreachable("unexpected binary operation");
774 }
775 
778  AffineExpr &offset) {
779  AffineMap m = t.getLayout().getAffineMap();
780 
781  if (m.getNumResults() != 1 && !m.isIdentity())
782  return failure();
783 
784  auto zero = getAffineConstantExpr(0, t.getContext());
785  auto one = getAffineConstantExpr(1, t.getContext());
786  offset = zero;
787  strides.assign(t.getRank(), zero);
788 
789  // Canonical case for empty map.
790  if (m.isIdentity()) {
791  // 0-D corner case, offset is already 0.
792  if (t.getRank() == 0)
793  return success();
794  auto stridedExpr =
795  makeCanonicalStridedLayoutExpr(t.getShape(), t.getContext());
796  if (succeeded(extractStrides(stridedExpr, one, strides, offset)))
797  return success();
798  assert(false && "unexpected failure: extract strides in canonical layout");
799  }
800 
801  // Non-canonical case requires more work.
802  auto stridedExpr =
804  if (failed(extractStrides(stridedExpr, one, strides, offset))) {
805  offset = AffineExpr();
806  strides.clear();
807  return failure();
808  }
809 
810  // Simplify results to allow folding to constants and simple checks.
811  unsigned numDims = m.getNumDims();
812  unsigned numSymbols = m.getNumSymbols();
813  offset = simplifyAffineExpr(offset, numDims, numSymbols);
814  for (auto &stride : strides)
815  stride = simplifyAffineExpr(stride, numDims, numSymbols);
816 
817  /// In practice, a strided memref must be internally non-aliasing. Test
818  /// against 0 as a proxy.
819  /// TODO: static cases can have more advanced checks.
820  /// TODO: dynamic cases would require a way to compare symbolic
821  /// expressions and would probably need an affine set context propagated
822  /// everywhere.
823  if (llvm::any_of(strides, [](AffineExpr e) {
824  return e == getAffineConstantExpr(0, e.getContext());
825  })) {
826  offset = AffineExpr();
827  strides.clear();
828  return failure();
829  }
830 
831  return success();
832 }
833 
835  SmallVectorImpl<int64_t> &strides,
836  int64_t &offset) {
837  AffineExpr offsetExpr;
838  SmallVector<AffineExpr, 4> strideExprs;
839  if (failed(::getStridesAndOffset(t, strideExprs, offsetExpr)))
840  return failure();
841  if (auto cst = offsetExpr.dyn_cast<AffineConstantExpr>())
842  offset = cst.getValue();
843  else
844  offset = ShapedType::kDynamicStrideOrOffset;
845  for (auto e : strideExprs) {
846  if (auto c = e.dyn_cast<AffineConstantExpr>())
847  strides.push_back(c.getValue());
848  else
849  strides.push_back(ShapedType::kDynamicStrideOrOffset);
850  }
851  return success();
852 }
853 
854 void UnrankedMemRefType::walkImmediateSubElements(
855  function_ref<void(Attribute)> walkAttrsFn,
856  function_ref<void(Type)> walkTypesFn) const {
857  walkTypesFn(getElementType());
858  walkAttrsFn(getMemorySpace());
859 }
860 
861 Type UnrankedMemRefType::replaceImmediateSubElements(
862  ArrayRef<Attribute> replAttrs, ArrayRef<Type> replTypes) const {
863  return get(replTypes.front(), replAttrs.front());
864 }
865 
866 //===----------------------------------------------------------------------===//
867 /// TupleType
868 //===----------------------------------------------------------------------===//
869 
870 /// Return the elements types for this tuple.
871 ArrayRef<Type> TupleType::getTypes() const { return getImpl()->getTypes(); }
872 
873 /// Accumulate the types contained in this tuple and tuples nested within it.
874 /// Note that this only flattens nested tuples, not any other container type,
875 /// e.g. a tuple<i32, tensor<i32>, tuple<f32, tuple<i64>>> is flattened to
876 /// (i32, tensor<i32>, f32, i64)
878  for (Type type : getTypes()) {
879  if (auto nestedTuple = type.dyn_cast<TupleType>())
880  nestedTuple.getFlattenedTypes(types);
881  else
882  types.push_back(type);
883  }
884 }
885 
886 /// Return the number of element types.
887 size_t TupleType::size() const { return getImpl()->size(); }
888 
889 void TupleType::walkImmediateSubElements(
890  function_ref<void(Attribute)> walkAttrsFn,
891  function_ref<void(Type)> walkTypesFn) const {
892  for (Type type : getTypes())
893  walkTypesFn(type);
894 }
895 
896 Type TupleType::replaceImmediateSubElements(ArrayRef<Attribute> replAttrs,
897  ArrayRef<Type> replTypes) const {
898  return get(getContext(), replTypes);
899 }
900 
901 //===----------------------------------------------------------------------===//
902 // Type Utilities
903 //===----------------------------------------------------------------------===//
904 
906  int64_t offset,
907  MLIRContext *context) {
908  AffineExpr expr;
909  unsigned nSymbols = 0;
910 
911  // AffineExpr for offset.
912  // Static case.
913  if (offset != MemRefType::getDynamicStrideOrOffset()) {
914  auto cst = getAffineConstantExpr(offset, context);
915  expr = cst;
916  } else {
917  // Dynamic case, new symbol for the offset.
918  auto sym = getAffineSymbolExpr(nSymbols++, context);
919  expr = sym;
920  }
921 
922  // AffineExpr for strides.
923  for (const auto &en : llvm::enumerate(strides)) {
924  auto dim = en.index();
925  auto stride = en.value();
926  assert(stride != 0 && "Invalid stride specification");
927  auto d = getAffineDimExpr(dim, context);
928  AffineExpr mult;
929  // Static case.
930  if (stride != MemRefType::getDynamicStrideOrOffset())
931  mult = getAffineConstantExpr(stride, context);
932  else
933  // Dynamic case, new symbol for each new stride.
934  mult = getAffineSymbolExpr(nSymbols++, context);
935  expr = expr + d * mult;
936  }
937 
938  return AffineMap::get(strides.size(), nSymbols, expr);
939 }
940 
941 /// Return a version of `t` with identity layout if it can be determined
942 /// statically that the layout is the canonical contiguous strided layout.
943 /// Otherwise pass `t`'s layout into `simplifyAffineMap` and return a copy of
944 /// `t` with simplified layout.
945 /// If `t` has multiple layout maps or a multi-result layout, just return `t`.
946 MemRefType mlir::canonicalizeStridedLayout(MemRefType t) {
947  AffineMap m = t.getLayout().getAffineMap();
948 
949  // Already in canonical form.
950  if (m.isIdentity())
951  return t;
952 
953  // Can't reduce to canonical identity form, return in canonical form.
954  if (m.getNumResults() > 1)
955  return t;
956 
957  // Corner-case for 0-D affine maps.
958  if (m.getNumDims() == 0 && m.getNumSymbols() == 0) {
959  if (auto cst = m.getResult(0).dyn_cast<AffineConstantExpr>())
960  if (cst.getValue() == 0)
961  return MemRefType::Builder(t).setLayout({});
962  return t;
963  }
964 
965  // 0-D corner case for empty shape that still have an affine map. Example:
966  // `memref<f32, affine_map<()[s0] -> (s0)>>`. This is a 1 element memref whose
967  // offset needs to remain, just return t.
968  if (t.getShape().empty())
969  return t;
970 
971  // If the canonical strided layout for the sizes of `t` is equal to the
972  // simplified layout of `t` we can just return an empty layout. Otherwise,
973  // just simplify the existing layout.
974  AffineExpr expr =
975  makeCanonicalStridedLayoutExpr(t.getShape(), t.getContext());
976  auto simplifiedLayoutExpr =
978  if (expr != simplifiedLayoutExpr)
979  return MemRefType::Builder(t).setLayout(AffineMapAttr::get(AffineMap::get(
980  m.getNumDims(), m.getNumSymbols(), simplifiedLayoutExpr)));
981  return MemRefType::Builder(t).setLayout({});
982 }
983 
985  ArrayRef<AffineExpr> exprs,
986  MLIRContext *context) {
987  // Size 0 corner case is useful for canonicalizations.
988  if (sizes.empty())
989  return getAffineConstantExpr(0, context);
990 
991  assert(!exprs.empty() && "expected exprs");
992  auto maps = AffineMap::inferFromExprList(exprs);
993  assert(!maps.empty() && "Expected one non-empty map");
994  unsigned numDims = maps[0].getNumDims(), nSymbols = maps[0].getNumSymbols();
995 
996  AffineExpr expr;
997  bool dynamicPoisonBit = false;
998  int64_t runningSize = 1;
999  for (auto en : llvm::zip(llvm::reverse(exprs), llvm::reverse(sizes))) {
1000  int64_t size = std::get<1>(en);
1001  AffineExpr dimExpr = std::get<0>(en);
1002  AffineExpr stride = dynamicPoisonBit
1003  ? getAffineSymbolExpr(nSymbols++, context)
1004  : getAffineConstantExpr(runningSize, context);
1005  expr = expr ? expr + dimExpr * stride : dimExpr * stride;
1006  if (size > 0) {
1007  runningSize *= size;
1008  assert(runningSize > 0 && "integer overflow in size computation");
1009  } else {
1010  dynamicPoisonBit = true;
1011  }
1012  }
1013  return simplifyAffineExpr(expr, numDims, nSymbols);
1014 }
1015 
1016 /// Return a version of `t` with a layout that has all dynamic offset and
1017 /// strides. This is used to erase the static layout.
1018 MemRefType mlir::eraseStridedLayout(MemRefType t) {
1019  auto val = ShapedType::kDynamicStrideOrOffset;
1020  return MemRefType::Builder(t).setLayout(
1021  AffineMapAttr::get(makeStridedLinearLayoutMap(
1022  SmallVector<int64_t, 4>(t.getRank(), val), val, t.getContext())));
1023 }
1024 
1026  MLIRContext *context) {
1028  exprs.reserve(sizes.size());
1029  for (auto dim : llvm::seq<unsigned>(0, sizes.size()))
1030  exprs.push_back(getAffineDimExpr(dim, context));
1031  return makeCanonicalStridedLayoutExpr(sizes, exprs, context);
1032 }
1033 
1034 /// Return true if the layout for `t` is compatible with strided semantics.
1035 bool mlir::isStrided(MemRefType t) {
1036  int64_t offset;
1037  SmallVector<int64_t, 4> strides;
1038  auto res = getStridesAndOffset(t, strides, offset);
1039  return succeeded(res);
1040 }
1041 
1042 /// Return the layout map in strided linear layout AffineMap form.
1043 /// Return null if the layout is not compatible with a strided layout.
1045  int64_t offset;
1046  SmallVector<int64_t, 4> strides;
1047  if (failed(getStridesAndOffset(t, strides, offset)))
1048  return AffineMap();
1049  return makeStridedLinearLayoutMap(strides, offset, t.getContext());
1050 }
1051 
1052 /// Return the AffineExpr representation of the offset, assuming `memRefType`
1053 /// is a strided memref.
1054 static AffineExpr getOffsetExpr(MemRefType memrefType) {
1055  SmallVector<AffineExpr> strides;
1056  AffineExpr offset;
1057  if (failed(getStridesAndOffset(memrefType, strides, offset)))
1058  assert(false && "expected strided memref");
1059  return offset;
1060 }
1061 
1062 /// Helper to construct a contiguous MemRefType of `shape`, `elementType` and
1063 /// `offset` AffineExpr.
1065  ArrayRef<int64_t> shape,
1066  Type elementType,
1067  AffineExpr offset) {
1068  AffineExpr canonical = makeCanonicalStridedLayoutExpr(shape, context);
1069  AffineExpr contiguousRowMajor = canonical + offset;
1070  AffineMap contiguousRowMajorMap =
1071  AffineMap::inferFromExprList({contiguousRowMajor})[0];
1072  return MemRefType::get(shape, elementType, contiguousRowMajorMap);
1073 }
1074 
1075 /// Helper determining if a memref is static-shape and contiguous-row-major
1076 /// layout, while still allowing for an arbitrary offset (any static or
1077 /// dynamic value).
1078 bool mlir::isStaticShapeAndContiguousRowMajor(MemRefType memrefType) {
1079  if (!memrefType.hasStaticShape())
1080  return false;
1081  AffineExpr offset = getOffsetExpr(memrefType);
1082  MemRefType contiguousRowMajorMemRefType = makeContiguousRowMajorMemRefType(
1083  memrefType.getContext(), memrefType.getShape(),
1084  memrefType.getElementType(), offset);
1085  return canonicalizeStridedLayout(memrefType) ==
1086  canonicalizeStridedLayout(contiguousRowMajorMemRefType);
1087 }
bool hasRank() const
Returns if this type is ranked, i.e. it has a known number of dimensions.
Affine binary operation expression.
Definition: AffineExpr.h:207
Include the generated interface declarations.
Dialect & getDialect() const
Get the dialect this type is registered to.
Definition: Types.h:121
AffineExpr makeCanonicalStridedLayoutExpr(ArrayRef< int64_t > sizes, ArrayRef< AffineExpr > exprs, MLIRContext *context)
Given MemRef sizes that are either static or dynamic, returns the canonical "contiguous" strides Affi...
static LogicalResult extractStrides(AffineExpr e, AffineExpr multiplicativeFactor, MutableArrayRef< AffineExpr > strides, AffineExpr &offset)
Takes a single AffineExpr e and populates the strides array with the strides expressions for each dim...
U cast() const
Definition: Attributes.h:135
RHS of mod is always a constant or a symbolic expression with a positive value.
U dyn_cast_or_null() const
Definition: Attributes.h:131
MemRefType eraseStridedLayout(MemRefType t)
Return a version of t with a layout that has all dynamic offset and strides.
unsigned getNumSymbols() const
Definition: AffineMap.cpp:298
unsigned getNumDims() const
Definition: AffineMap.cpp:294
Attribute getMemorySpace() const
Returns the memory space in which data referred to by this memref resides.
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
Definition: AffineExpr.cpp:514
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:310
AffineMap getStridedLinearLayoutMap(MemRefType t)
Return the layout map in strided linear layout AffineMap form.
llvm::Optional< llvm::SmallDenseSet< unsigned > > computeRankReductionMask(ArrayRef< int64_t > originalShape, ArrayRef< int64_t > reducedShape)
Given an originalShape and a reducedShape assumed to be a subset of originalShape with some 1 entries...
Attribute wrapIntegerMemorySpace(unsigned memorySpace, MLIRContext *ctx)
Wraps deprecated integer memory space to the new Attribute form.
static void extractStridesFromTerm(AffineExpr e, AffineExpr multiplicativeFactor, MutableArrayRef< AffineExpr > strides, AffineExpr &offset)
bool isa() const
Definition: Attributes.h:111
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
static AffineExpr getOffsetExpr(MemRefType memrefType)
Return the AffineExpr representation of the offset, assuming memRefType is a strided memref...
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity...
Definition: SPIRVOps.cpp:685
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
Definition: Types.cpp:87
static FloatType getF32(MLIRContext *ctx)
Definition: BuiltinTypes.h:391
SmallVector< Type, 10 > getFlattenedTypes(TupleType t)
Get the types within a nested Tuple.
SliceVerificationResult isRankReducedType(ShapedType originalType, ShapedType candidateReducedType)
Check if originalType can be rank reduced to candidateReducedType type by dropping some dimensions wi...
TypeRange filterTypesOut(TypeRange types, const BitVector &indices, SmallVectorImpl< Type > &storage)
Filters out any elements referenced by indices.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
Definition: LogicalResult.h:68
bool hasRank() const
Returns if this type is ranked, i.e. it has a known number of dimensions.
TensorType cloneWith(Optional< ArrayRef< int64_t >> shape, Type elementType) const
Clone this type with the given shape and element type.
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
Definition: Traits.cpp:117
Attribute skipDefaultMemorySpace(Attribute memorySpace)
Replaces default memorySpace (integer == 0) with empty Attribute.
An integer constant appearing in affine expression.
Definition: AffineExpr.h:232
const llvm::fltSemantics & getFloatSemantics()
Return the floating semantics of this float type.
AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols)
Simplify an affine expression by flattening and some amount of simple analysis.
AffineExpr getResult(unsigned idx) const
Definition: AffineMap.cpp:311
U dyn_cast() const
Definition: AffineExpr.h:281
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
LogicalResult getStridesAndOffset(MemRefType t, SmallVectorImpl< int64_t > &strides, int64_t &offset)
Returns the strides of the MemRef if the layout map is in strided form.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
static LogicalResult checkTensorElementType(function_ref< InFlightDiagnostic()> emitError, Type elementType)
bool isStrided(MemRefType t)
Return true if the layout for t is compatible with strided semantics.
unsigned getWidth()
Return the bitwidth of this float type.
Dialect & getDialect() const
Get the dialect this attribute is registered to.
Definition: Attributes.h:73
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
U dyn_cast() const
Definition: Types.h:270
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
Definition: AffineExpr.cpp:499
Attributes are known-constant values of operations.
Definition: Attributes.h:24
unsigned getFPMantissaWidth()
Return the width of the mantissa of this type.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:233
BaseMemRefType cloneWith(Optional< ArrayRef< int64_t >> shape, Type elementType) const
Clone this type with the given shape and element type.
SliceVerificationResult
Enum that captures information related to verifier error conditions on slice insert/extract type of o...
Definition: BuiltinTypes.h:347
Base type for affine expression.
Definition: AffineExpr.h:68
MLIRContext * getContext() const
Definition: AffineExpr.cpp:23
RHS of mul is always a constant or a symbolic expression.
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:32
unsigned getNumResults() const
Definition: AffineMap.cpp:302
A multi-dimensional affine map Affine map&#39;s are immutable like Type&#39;s, and they are uniqued...
Definition: AffineMap.h:42
RHS of floordiv is always a constant or a symbolic expression.
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
Definition: BuiltinTypes.h:76
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
Definition: AffineExpr.cpp:489
RHS of ceildiv is always a constant or a symbolic expression.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:72
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition: Types.cpp:19
static MemRefType makeContiguousRowMajorMemRefType(MLIRContext *context, ArrayRef< int64_t > shape, Type elementType, AffineExpr offset)
Helper to construct a contiguous MemRefType of shape, elementType and offset AffineExpr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
This class provides a shared interface for ranked and unranked memref types.
Definition: BuiltinTypes.h:112
unsigned getMemorySpaceAsInt() const
[deprecated] Returns the memory space in old raw integer representation.
static bool isValidElementType(Type type)
Return true if the specified element type is ok in a memref.
Definition: BuiltinTypes.h:372
Type getElementType() const
Returns the element type of this memref type.
Builder & setElementType(Type newElementType)
Definition: BuiltinTypes.h:180
This is a builder type that keeps local references to arguments.
Definition: BuiltinTypes.h:164
A dimensional identifier appearing in an affine expression.
Definition: AffineExpr.h:216
bool isIdentity() const
Returns true if this affine map is an identity affine map.
Definition: AffineMap.cpp:255
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:55
Type getElementType() const
Returns the element type of this tensor type.
FloatType scaleElementBitwidth(unsigned scale)
Get or create a new FloatType with bitwidth scaled by scale.
AffineMap makeStridedLinearLayoutMap(ArrayRef< int64_t > strides, int64_t offset, MLIRContext *context)
Given a list of strides (in which MemRefType::getDynamicStrideOrOffset() represents a dynamic value)...
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
MemRefType canonicalizeStridedLayout(MemRefType t)
Return a version of t with identity layout if it can be determined statically that the layout is the ...
Builder & setMemorySpace(Attribute newMemorySpace)
Definition: BuiltinTypes.h:190
ArrayRef< int64_t > getShape() const
Returns the shape of this memref type.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs, on this operation and any nested operations.
Definition: Verifier.cpp:372
ArrayRef< int64_t > getShape() const
Returns the shape of this tensor type.
static AffineMap getMultiDimIdentityMap(unsigned numDims, MLIRContext *context)
Returns an AffineMap with &#39;numDims&#39; identity result dim exprs.
Definition: AffineMap.cpp:244
static bool isValidElementType(Type type)
Return true if the specified element type is ok in a tensor.
Builder & setLayout(MemRefLayoutAttrInterface newLayout)
Definition: BuiltinTypes.h:185
bool isa() const
Definition: Types.h:254
static SmallVector< AffineMap, 4 > inferFromExprList(ArrayRef< ArrayRef< AffineExpr >> exprsList)
Returns a vector of AffineMaps; each with as many results as exprs.size(), as many dims as the larges...
Definition: AffineMap.cpp:235
bool isSupportedMemorySpace(Attribute memorySpace)
Checks if the memorySpace has supported Attribute type.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
TypeRange insertTypesInto(TypeRange oldTypes, ArrayRef< unsigned > indices, TypeRange newTypes, SmallVectorImpl< Type > &storage)
Insert a set of newTypes into oldTypes at the given indices.
Builder & setShape(ArrayRef< int64_t > newShape)
Definition: BuiltinTypes.h:175
static FloatType getF64(MLIRContext *ctx)
Definition: BuiltinTypes.h:395
unsigned getMemorySpaceAsInt(Attribute memorySpace)
[deprecated] Returns the memory space in old raw integer representation.
bool isStaticShapeAndContiguousRowMajor(MemRefType memrefType)
Helper determining if a memref is static-shape and contiguous-row-major layout, while still allowing ...
static bool isValidNamespace(StringRef str)
Utility function that returns if the given string is a valid dialect namespace.
Definition: Dialect.cpp:91