MLIR 24.0.0git
BuiltinAttributeInterfaces.h
Go to the documentation of this file.
1//===- BuiltinAttributeInterfaces.h - Builtin Attr Interfaces ---*- C++ -*-===//
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 MLIR_IR_BUILTINATTRIBUTEINTERFACES_H
10#define MLIR_IR_BUILTINATTRIBUTEINTERFACES_H
11
12#include "mlir/IR/AffineMap.h"
14#include "mlir/IR/Types.h"
15#include "llvm/Support/raw_ostream.h"
16#include <complex>
17#include <optional>
18
19namespace mlir {
20
21//===----------------------------------------------------------------------===//
22// ElementsAttr
23//===----------------------------------------------------------------------===//
24namespace detail {
25/// This class provides support for indexing into the element range of an
26/// ElementsAttr. It is used to opaquely wrap either a contiguous range, via
27/// `ElementsAttrIndexer::contiguous`, or a non-contiguous range, via
28/// `ElementsAttrIndexer::nonContiguous`, A contiguous range is an array-like
29/// range, where all of the elements are layed out sequentially in memory. A
30/// non-contiguous range implies no contiguity, and elements may even be
31/// materialized when indexing, such as the case for a mapped_range.
33public:
35 : ElementsAttrIndexer(/*isContiguous=*/true, /*isSplat=*/true) {}
37 : isContiguous(rhs.isContiguous), isSplat(rhs.isSplat) {
38 if (isContiguous)
39 conState = rhs.conState;
40 else
41 new (&nonConState) NonContiguousState(std::move(rhs.nonConState));
42 }
44 : isContiguous(rhs.isContiguous), isSplat(rhs.isSplat) {
45 if (isContiguous)
46 conState = rhs.conState;
47 else
48 new (&nonConState) NonContiguousState(rhs.nonConState);
49 }
51 if (!isContiguous)
52 nonConState.~NonContiguousState();
53 }
54
55 /// Construct an indexer for a non-contiguous range starting at the given
56 /// iterator. A non-contiguous range implies no contiguity, and elements may
57 /// even be materialized when indexing, such as the case for a mapped_range.
58 template <typename IteratorT>
59 static ElementsAttrIndexer nonContiguous(bool isSplat, IteratorT &&iterator) {
60 ElementsAttrIndexer indexer(/*isContiguous=*/false, isSplat);
61 new (&indexer.nonConState)
62 NonContiguousState(std::forward<IteratorT>(iterator));
63 return indexer;
64 }
65
66 // Construct an indexer for a contiguous range starting at the given element
67 // pointer. A contiguous range is an array-like range, where all of the
68 // elements are layed out sequentially in memory.
69 template <typename T>
70 static ElementsAttrIndexer contiguous(bool isSplat, const T *firstEltPtr) {
71 ElementsAttrIndexer indexer(/*isContiguous=*/true, isSplat);
72 new (&indexer.conState) ContiguousState(firstEltPtr);
73 return indexer;
74 }
75
76 /// Access the element at the given index.
77 template <typename T>
78 T at(uint64_t index) const {
79 if (isSplat)
80 index = 0;
81 return isContiguous ? conState.at<T>(index) : nonConState.at<T>(index);
82 }
83
84private:
85 ElementsAttrIndexer(bool isContiguous, bool isSplat)
86 : isContiguous(isContiguous), isSplat(isSplat), conState(nullptr) {}
87
88 /// This class contains all of the state necessary to index a contiguous
89 /// range.
90 class ContiguousState {
91 public:
92 ContiguousState(const void *firstEltPtr) : firstEltPtr(firstEltPtr) {}
93
94 /// Access the element at the given index.
95 template <typename T>
96 const T &at(uint64_t index) const {
97 return *(reinterpret_cast<const T *>(firstEltPtr) + index);
98 }
99
100 private:
101 const void *firstEltPtr;
102 };
103
104 /// This class contains all of the state necessary to index a non-contiguous
105 /// range.
106 class NonContiguousState {
107 private:
108 /// This class is used to represent the abstract base of an opaque iterator.
109 /// This allows for all iterator and element types to be completely
110 /// type-erased.
111 struct OpaqueIteratorBase {
112 virtual ~OpaqueIteratorBase() = default;
113 virtual std::unique_ptr<OpaqueIteratorBase> clone() const = 0;
114 };
115 /// This class is used to represent the abstract base of an opaque iterator
116 /// that iterates over elements of type `T`. This allows for all iterator
117 /// types to be completely type-erased.
118 template <typename T>
119 struct OpaqueIteratorValueBase : public OpaqueIteratorBase {
120 virtual T at(uint64_t index) = 0;
121 };
122 /// This class is used to represent an opaque handle to an iterator of type
123 /// `IteratorT` that iterates over elements of type `T`.
124 template <typename IteratorT, typename T>
125 struct OpaqueIterator : public OpaqueIteratorValueBase<T> {
126 template <typename ItTy, typename FuncTy, typename FuncReturnTy>
127 static void isMappedIteratorTestFn(
128 llvm::mapped_iterator<ItTy, FuncTy, FuncReturnTy>) {}
129 template <typename U, typename... Args>
130 using is_mapped_iterator =
131 decltype(isMappedIteratorTestFn(std::declval<U>()));
132 template <typename U>
133 using detect_is_mapped_iterator =
134 llvm::is_detected<is_mapped_iterator, U>;
135
136 /// Access the element within the iterator at the given index.
137 template <typename ItT>
138 static std::enable_if_t<!detect_is_mapped_iterator<ItT>::value, T>
139 atImpl(ItT &&it, uint64_t index) {
140 return *std::next(it, index);
141 }
142 template <typename ItT>
143 static std::enable_if_t<detect_is_mapped_iterator<ItT>::value, T>
144 atImpl(ItT &&it, uint64_t index) {
145 // Special case mapped_iterator to avoid copying the function.
146 return it.getFunction()(*std::next(it.getCurrent(), index));
147 }
148
149 public:
150 template <typename U>
151 OpaqueIterator(U &&iterator) : iterator(std::forward<U>(iterator)) {}
152 std::unique_ptr<OpaqueIteratorBase> clone() const final {
153 return std::make_unique<OpaqueIterator<IteratorT, T>>(iterator);
154 }
155
156 /// Access the element at the given index.
157 T at(uint64_t index) final { return atImpl(iterator, index); }
158
159 private:
160 IteratorT iterator;
161 };
162
163 public:
164 /// Construct the state with the given iterator type.
165 template <typename IteratorT, typename T = typename llvm::remove_cvref_t<
166 decltype(*std::declval<IteratorT>())>>
167 NonContiguousState(IteratorT iterator)
168 : iterator(std::make_unique<OpaqueIterator<IteratorT, T>>(iterator)) {}
169 NonContiguousState(const NonContiguousState &other)
170 : iterator(other.iterator->clone()) {}
171 NonContiguousState(NonContiguousState &&other) = default;
172
173 /// Access the element at the given index.
174 template <typename T>
175 T at(uint64_t index) const {
176 auto *valueIt = static_cast<OpaqueIteratorValueBase<T> *>(iterator.get());
177 return valueIt->at(index);
178 }
179
180 /// The opaque iterator state.
181 std::unique_ptr<OpaqueIteratorBase> iterator;
182 };
183
184 /// A boolean indicating if this range is contiguous or not.
185 bool isContiguous;
186 /// A boolean indicating if this range is a splat.
187 bool isSplat;
188 /// The underlying range state.
189 union {
190 ContiguousState conState;
191 NonContiguousState nonConState;
192 };
193};
194
195/// This class implements a generic iterator for ElementsAttr.
196template <typename T>
198 : public llvm::iterator_facade_base<ElementsAttrIterator<T>,
199 std::random_access_iterator_tag, T,
200 std::ptrdiff_t, T, T> {
201public:
202 ElementsAttrIterator(ElementsAttrIndexer indexer, size_t dataIndex)
203 : indexer(std::move(indexer)), index(dataIndex) {}
204
205 // Boilerplate iterator methods.
206 ptrdiff_t operator-(const ElementsAttrIterator &rhs) const {
207 return index - rhs.index;
208 }
209 bool operator==(const ElementsAttrIterator &rhs) const {
210 return index == rhs.index;
211 }
212 bool operator<(const ElementsAttrIterator &rhs) const {
213 return index < rhs.index;
214 }
215 ElementsAttrIterator &operator+=(ptrdiff_t offset) {
216 index += offset;
217 return *this;
218 }
219 ElementsAttrIterator &operator-=(ptrdiff_t offset) {
220 index -= offset;
221 return *this;
222 }
223
224 /// Return the value at the current iterator position.
225 T operator*() const { return indexer.at<T>(index); }
226
227private:
228 ElementsAttrIndexer indexer;
229 ptrdiff_t index;
230};
231
232/// This class provides iterator utilities for an ElementsAttr range.
233template <typename IteratorT>
234class ElementsAttrRange : public llvm::iterator_range<IteratorT> {
235public:
236 using reference = typename IteratorT::reference;
237
238 ElementsAttrRange(ShapedType shapeType,
240 : llvm::iterator_range<IteratorT>(range), shapeType(shapeType) {}
241 ElementsAttrRange(ShapedType shapeType, IteratorT beginIt, IteratorT endIt)
242 : ElementsAttrRange(shapeType, llvm::make_range(beginIt, endIt)) {}
243
244 /// Return the value at the given index.
245 reference operator[](ArrayRef<uint64_t> index) const;
246 reference operator[](uint64_t index) const {
247 return *std::next(this->begin(), index);
248 }
249
250 /// Return the size of this range.
251 size_t size() const { return llvm::size(*this); }
252
253private:
254 /// The shaped type of the parent ElementsAttr.
255 ShapedType shapeType;
256};
257
258} // namespace detail
259
260//===----------------------------------------------------------------------===//
261// MemRefLayoutAttrInterface
262//===----------------------------------------------------------------------===//
263
264namespace detail {
265
266// Verify the affine map 'm' can be used as a layout specification
267// for memref with 'shape'.
268LogicalResult
269verifyAffineMapAsLayout(AffineMap m, ArrayRef<int64_t> shape,
270 function_ref<InFlightDiagnostic()> emitError);
271
272// Return the strides and offsets that can be inferred from the given affine
273// layout map given the map and a memref shape.
274LogicalResult getAffineMapStridesAndOffset(AffineMap map,
275 ArrayRef<int64_t> shape,
276 SmallVectorImpl<int64_t> &strides,
277 int64_t &offset);
278} // namespace detail
279
280} // namespace mlir
281
282//===----------------------------------------------------------------------===//
283// Tablegen Interface Declarations
284//===----------------------------------------------------------------------===//
285
286#include "mlir/IR/BuiltinAttributeInterfaces.h.inc"
287#include "mlir/IR/OpAsmAttrInterface.h.inc"
288
289//===----------------------------------------------------------------------===//
290// ElementsAttr
291//===----------------------------------------------------------------------===//
292
293namespace mlir {
294namespace detail {
295/// Return the value at the given index.
296template <typename IteratorT>
298 -> reference {
299 // Skip to the element corresponding to the flattened index.
300 return (*this)[ElementsAttr::getFlattenedIndex(shapeType, index)];
301}
302} // namespace detail
303
304/// Return the elements of this attribute as a value of type 'T'.
305template <typename T>
306auto ElementsAttr::value_begin() const -> DefaultValueCheckT<T, iterator<T>> {
307 if (std::optional<iterator<T>> iterator = try_value_begin<T>())
308 return std::move(*iterator);
309 llvm::errs()
310 << "ElementsAttr does not provide iteration facilities for type `"
311 << llvm::getTypeName<T>() << "`, see attribute: " << *this << "\n";
312 llvm_unreachable("invalid `T` for ElementsAttr::getValues");
313}
314template <typename T>
315auto ElementsAttr::try_value_begin() const
316 -> DefaultValueCheckT<T, std::optional<iterator<T>>> {
317 FailureOr<detail::ElementsAttrIndexer> indexer =
318 getValuesImpl(TypeID::get<T>());
319 if (failed(indexer))
320 return std::nullopt;
321 return iterator<T>(std::move(*indexer), 0);
322}
323} // namespace mlir.
324
325#endif // MLIR_IR_BUILTINATTRIBUTEINTERFACES_H
true
Given two iterators into the same block, return "true" if a is before `b.
static TypeID get()
Construct a type info object for the given type T.
Definition TypeID.h:245
ptrdiff_t operator-(const ElementsAttrIterator &rhs) const
T operator*() const
Return the value at the current iterator position.
bool operator<(const ElementsAttrIterator &rhs) const
ElementsAttrIterator(ElementsAttrIndexer indexer, size_t dataIndex)
ElementsAttrIterator & operator-=(ptrdiff_t offset)
ElementsAttrIterator & operator+=(ptrdiff_t offset)
bool operator==(const ElementsAttrIterator &rhs) const
typename IteratorT::reference reference
reference operator[](ArrayRef< uint64_t > index) const
Return the value at the given index.
size_t size() const
Return the size of this range.
reference operator[](uint64_t index) const
ElementsAttrRange(ShapedType shapeType, IteratorT beginIt, IteratorT endIt)
ElementsAttrRange(ShapedType shapeType, const llvm::iterator_range< IteratorT > &range)
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:229
AttrTypeReplacer.
Include the generated interface declarations.
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
This class provides support for indexing into the element range of an ElementsAttr.
static ElementsAttrIndexer contiguous(bool isSplat, const T *firstEltPtr)
static ElementsAttrIndexer nonContiguous(bool isSplat, IteratorT &&iterator)
Construct an indexer for a non-contiguous range starting at the given iterator.
T at(uint64_t index) const
Access the element at the given index.
ElementsAttrIndexer(const ElementsAttrIndexer &rhs)
ElementsAttrIndexer(ElementsAttrIndexer &&rhs)