MLIR  20.0.0git
SparseTensorIterator.h
Go to the documentation of this file.
1 //===- SparseTensorIterator.h ---------------------------------------------===//
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_DIALECT_SPARSETENSOR_TRANSFORMS_UTILS_SPARSETENSORITERATOR_H_
10 #define MLIR_DIALECT_SPARSETENSOR_TRANSFORMS_UTILS_SPARSETENSORITERATOR_H_
11 
14 
15 namespace mlir {
16 namespace sparse_tensor {
17 
18 // Forward declaration.
19 class SparseIterator;
20 
21 /// The base class for all types of sparse tensor levels. It provides interfaces
22 /// to query the loop range (see `peekRangeAt`) and look up the coordinates (see
23 /// `peekCrdAt`).
26  SparseTensorLevel(const SparseTensorLevel &) = delete;
27  SparseTensorLevel &operator=(SparseTensorLevel &&) = delete;
28  SparseTensorLevel &operator=(const SparseTensorLevel &) = delete;
29 
30 public:
31  virtual ~SparseTensorLevel() = default;
32 
33  std::string toString() const {
34  return std::string(toMLIRString(lt)) + "[" + std::to_string(tid) + "," +
35  std::to_string(lvl) + "]";
36  }
37 
38  virtual Value peekCrdAt(OpBuilder &b, Location l, ValueRange batchPrefix,
39  Value iv) const = 0;
40 
41  /// Peeks the lower and upper bound to *fully* traverse the level with
42  /// the given position `parentPos`, see SparseTensorIterator::getCurPostion(),
43  /// that the immediate parent level is current at. Returns a pair of values
44  /// for *posLo* and *loopHi* respectively.
45  ///
46  /// For a dense level, the *posLo* is the linearized position at beginning,
47  /// while *loopHi* is the largest *coordinate*, it also implies that the
48  /// smallest *coordinate* to start the loop is 0.
49  ///
50  /// For a sparse level, [posLo, loopHi) specifies the range of index pointer
51  /// to load coordinate from the coordinate buffer.
52  virtual std::pair<Value, Value>
54  ValueRange parentPos, Value inPadZone = nullptr) const = 0;
55 
56  virtual std::pair<Value, Value>
58  std::pair<Value, Value> parentRange) const {
59  llvm_unreachable("Not Implemented");
60  };
61 
62  Level getLevel() const { return lvl; }
63  LevelType getLT() const { return lt; }
64  Value getSize() const { return lvlSize; }
65  virtual ValueRange getLvlBuffers() const = 0;
66 
67  //
68  // Level properties
69  //
70  bool isUnique() const { return isUniqueLT(lt); }
71 
72 protected:
74  : tid(tid), lvl(lvl), lt(lt), lvlSize(lvlSize) {};
75 
76 public:
77  const unsigned tid, lvl;
78  const LevelType lt;
79  const Value lvlSize;
80 };
81 
82 enum class IterKind : uint8_t {
83  kTrivial,
84  kDedup,
85  kSubSect,
87  kFilter,
88  kPad,
89 };
90 
91 /// A `SparseIterationSpace` represents a sparse set of coordinates defined by
92 /// (possibly multiple) levels of a specific sparse tensor.
93 /// TODO: remove `SparseTensorLevel` and switch to SparseIterationSpace when
94 /// feature complete.
96 public:
97  SparseIterationSpace() = default;
98 
99  // Constructs a N-D iteration space.
100  SparseIterationSpace(Location loc, OpBuilder &b, Value t, unsigned tid,
101  std::pair<Level, Level> lvlRange, ValueRange parentPos);
102 
103  // Constructs a 1-D iteration space.
104  SparseIterationSpace(Location loc, OpBuilder &b, Value t, unsigned tid,
105  Level lvl, ValueRange parentPos)
106  : SparseIterationSpace(loc, b, t, tid, {lvl, lvl + 1}, parentPos) {};
107 
108  bool isUnique() const { return lvls.back()->isUnique(); }
109 
110  unsigned getSpaceDim() const { return lvls.size(); }
111 
112  // Reconstructs a iteration space directly from the provided ValueRange.
113  static SparseIterationSpace fromValues(IterSpaceType dstTp, ValueRange values,
114  unsigned tid);
115 
116  // The inverse operation of `fromValues`.
118  SmallVector<Value> vals;
119  for (auto &stl : lvls) {
120  llvm::append_range(vals, stl->getLvlBuffers());
121  vals.push_back(stl->getSize());
122  }
123  vals.append({bound.first, bound.second});
124  return vals;
125  }
126 
127  const SparseTensorLevel &getLastLvl() const { return *lvls.back(); }
129  return lvls;
130  }
131 
132  Value getBoundLo() const { return bound.first; }
133  Value getBoundHi() const { return bound.second; }
134 
135  // Extract an iterator to iterate over the sparse iteration space.
136  std::unique_ptr<SparseIterator> extractIterator(OpBuilder &b,
137  Location l) const;
138 
139 private:
141  std::pair<Value, Value> bound;
142 };
143 
144 /// Helper class that generates loop conditions, etc, to traverse a
145 /// sparse tensor level.
147  SparseIterator(SparseIterator &&) = delete;
148  SparseIterator(const SparseIterator &) = delete;
149  SparseIterator &operator=(SparseIterator &&) = delete;
150  SparseIterator &operator=(const SparseIterator &) = delete;
151 
152 protected:
153  SparseIterator(IterKind kind, unsigned tid, unsigned lvl,
154  unsigned cursorValsCnt,
155  SmallVectorImpl<Value> &cursorValStorage)
156  : batchCrds(0), kind(kind), tid(tid), lvl(lvl), crd(nullptr),
157  cursorValsCnt(cursorValsCnt), cursorValsStorageRef(cursorValStorage) {};
158 
159  SparseIterator(IterKind kind, unsigned cursorValsCnt,
160  SmallVectorImpl<Value> &cursorValStorage,
161  const SparseIterator &delegate)
162  : SparseIterator(kind, delegate.tid, delegate.lvl, cursorValsCnt,
163  cursorValStorage) {};
164 
166  unsigned extraCursorCnt = 0)
168  extraCursorCnt + wrap.cursorValsCnt,
169  wrap.cursorValsStorageRef) {
170  assert(wrap.cursorValsCnt == wrap.cursorValsStorageRef.size());
171  cursorValsStorageRef.append(extraCursorCnt, nullptr);
172  assert(cursorValsStorageRef.size() == wrap.cursorValsCnt + extraCursorCnt);
173  };
174 
175 public:
176  virtual ~SparseIterator() = default;
177 
179  emitStrategy = strategy;
180  }
181 
182  virtual std::string getDebugInterfacePrefix() const = 0;
184 
185  Value getCrd() const { return crd; }
186  ValueRange getBatchCrds() const { return batchCrds; }
188  return ValueRange(cursorValsStorageRef).take_front(cursorValsCnt);
189  };
190 
191  // Sets the iterate to the specified position.
192  void seek(ValueRange vals) {
193  assert(vals.size() == cursorValsCnt);
194  std::copy(vals.begin(), vals.end(), cursorValsStorageRef.begin());
195  // Now that the iterator is re-positioned, the coordinate becomes invalid.
196  crd = nullptr;
197  }
198 
199  // Reconstructs a iteration space directly from the provided ValueRange.
200  static std::unique_ptr<SparseIterator>
201  fromValues(IteratorType dstTp, ValueRange values, unsigned tid);
202 
203  // The inverse operation of `fromValues`.
204  SmallVector<Value> toValues() const { llvm_unreachable("Not implemented"); }
205 
206  //
207  // Iterator properties.
208  //
209 
210  // Whether the iterator is a iterator over a batch level.
211  virtual bool isBatchIterator() const = 0;
212 
213  // Whether the iterator support random access (i.e., support look up by
214  // *coordinate*). A random access iterator must also traverses a dense space.
215  virtual bool randomAccessible() const = 0;
216 
217  // Whether the iterator can simply traversed by a for loop.
218  virtual bool iteratableByFor() const { return false; };
219 
220  // Get the upper bound of the sparse space that the iterator might visited. A
221  // sparse space is a subset of a dense space [0, bound), this function returns
222  // *bound*.
223  virtual Value upperBound(OpBuilder &b, Location l) const = 0;
224 
225  // Serializes and deserializes the current status to/from a set of values. The
226  // ValueRange should contain values that are sufficient to recover the current
227  // iterating postion (i.e., itVals) as well as loop bound.
228  //
229  // Not every type of iterator supports the operations, e.g., non-empty
230  // subsection iterator does not because the the number of non-empty
231  // subsections can not be determined easily.
232  //
233  // NOTE: All the values should have index type.
234  virtual SmallVector<Value> serialize() const {
235  llvm_unreachable("unsupported");
236  };
237  virtual void deserialize(ValueRange vs) { llvm_unreachable("unsupported"); };
238 
239  //
240  // Core functions.
241  //
242 
243  // Initializes the iterator according to the parent iterator's state.
244  void genInit(OpBuilder &b, Location l, const SparseIterator *p);
245 
246  // Forwards the iterator to the next element.
248 
249  // Locate the iterator to the position specified by *crd*, this can only
250  // be done on an iterator that supports randm access.
251  void locate(OpBuilder &b, Location l, Value crd);
252 
253  // Returns a boolean value that equals `!it.end()`
255 
256  // Dereferences the iterator, loads the coordinate at the current position.
257  //
258  // The method assumes that the iterator is not currently exhausted (i.e.,
259  // it != it.end()).
260  Value deref(OpBuilder &b, Location l);
261 
262  // Actual Implementation provided by derived class.
263  virtual void genInitImpl(OpBuilder &, Location, const SparseIterator *) = 0;
265  virtual void locateImpl(OpBuilder &b, Location l, Value crd) {
266  llvm_unreachable("Unsupported");
267  }
268  virtual Value genNotEndImpl(OpBuilder &b, Location l) = 0;
269  virtual Value derefImpl(OpBuilder &b, Location l) = 0;
270  // Gets the ValueRange that together specifies the current position of the
271  // iterator. For a unique level, the position can be a single index points to
272  // the current coordinate being visited. For a non-unique level, an extra
273  // index for the `segment high` is needed to to specifies the range of
274  // duplicated coordinates. The ValueRange should be able to uniquely identify
275  // the sparse range for the next level. See SparseTensorLevel::peekRangeAt();
276  //
277  // Not every type of iterator supports the operation, e.g., non-empty
278  // subsection iterator does not because it represent a range of coordinates
279  // instead of just one.
280  virtual ValueRange getCurPosition() const { return getCursor(); };
281 
282  // Returns a pair of values for *upper*, *lower* bound respectively.
283  virtual std::pair<Value, Value> genForCond(OpBuilder &b, Location l) {
284  assert(randomAccessible());
285  // Random-access iterator is traversed by coordinate, i.e., [curCrd, UB).
286  return {getCrd(), upperBound(b, l)};
287  }
288 
289  // Generates a bool value for scf::ConditionOp.
290  std::pair<Value, ValueRange> genWhileCond(OpBuilder &b, Location l,
291  ValueRange vs) {
292  ValueRange rem = linkNewScope(vs);
293  return std::make_pair(genNotEnd(b, l), rem);
294  }
295 
296  // Generate a conditional it.next() in the following form
297  //
298  // if (cond)
299  // yield it.next
300  // else
301  // yield it
302  //
303  // The function is virtual to allow alternative implementation. For example,
304  // if it.next() is trivial to compute, we can use a select operation instead.
305  // E.g.,
306  //
307  // it = select cond ? it+1 : it
308  virtual ValueRange forwardIf(OpBuilder &b, Location l, Value cond);
309 
310  // Update the SSA value for the iterator after entering a new scope.
312  assert(!randomAccessible() && "random accessible iterators are traversed "
313  "by coordinate, call locate() instead.");
314  seek(pos.take_front(cursorValsCnt));
315  return pos.drop_front(cursorValsCnt);
316  };
317 
318 protected:
319  void updateCrd(Value crd) { this->crd = crd; }
320 
322  MutableArrayRef<Value> ref = cursorValsStorageRef;
323  return ref.take_front(cursorValsCnt);
324  }
325 
326  void inherentBatch(const SparseIterator &parent) {
327  batchCrds = parent.batchCrds;
328  }
329 
332 
333 public:
334  const IterKind kind; // For LLVM-style RTTI.
335  const unsigned tid, lvl; // tensor level identifier.
336 
337 private:
338  Value crd; // The sparse coordinate used to coiterate;
339 
340  // A range of value that together defines the current state of the
341  // iterator. Only loop variants should be included.
342  //
343  // For trivial iterators, it is the position; for dedup iterators, it consists
344  // of the positon and the segment high, for non-empty subsection iterator, it
345  // is the metadata that specifies the subsection.
346  // Note that the wrapped iterator shares the same storage to maintain itVals
347  // with it wrapper, which means the wrapped iterator might only own a subset
348  // of all the values stored in itValStorage.
349  const unsigned cursorValsCnt;
350  SmallVectorImpl<Value> &cursorValsStorageRef;
351 };
352 
353 /// Helper function to create a TensorLevel object from given `tensor`.
354 std::unique_ptr<SparseTensorLevel> makeSparseTensorLevel(OpBuilder &b,
355  Location l, Value t,
356  unsigned tid,
357  Level lvl);
358 
359 /// Helper function to create a TensorLevel object from given ValueRange.
360 std::unique_ptr<SparseTensorLevel> makeSparseTensorLevel(LevelType lt, Value sz,
361  ValueRange buffers,
362  unsigned tid, Level l);
363 
364 /// Helper function to create a simple SparseIterator object that iterate
365 /// over the entire iteration space.
366 std::unique_ptr<SparseIterator>
368  const SparseIterationSpace &iterSpace);
369 
370 /// Helper function to create a simple SparseIterator object that iterate
371 /// over the sparse tensor level.
372 /// TODO: switch to `SparseIterationSpace` (which support N-D iterator) when
373 /// feature complete.
374 std::unique_ptr<SparseIterator> makeSimpleIterator(
375  const SparseTensorLevel &stl,
377 
378 /// Helper function to create a synthetic SparseIterator object that iterates
379 /// over a dense space specified by [0,`sz`).
380 std::pair<std::unique_ptr<SparseTensorLevel>, std::unique_ptr<SparseIterator>>
381 makeSynLevelAndIterator(Value sz, unsigned tid, unsigned lvl,
382  SparseEmitStrategy strategy);
383 
384 /// Helper function to create a SparseIterator object that iterates over a
385 /// sliced space, the orignal space (before slicing) is traversed by `sit`.
386 std::unique_ptr<SparseIterator>
387 makeSlicedLevelIterator(std::unique_ptr<SparseIterator> &&sit, Value offset,
388  Value stride, Value size, SparseEmitStrategy strategy);
389 
390 /// Helper function to create a SparseIterator object that iterates over a
391 /// padded sparse level (the padded value must be zero).
392 std::unique_ptr<SparseIterator>
393 makePaddedIterator(std::unique_ptr<SparseIterator> &&sit, Value padLow,
394  Value padHigh, SparseEmitStrategy strategy);
395 
396 /// Helper function to create a SparseIterator object that iterate over the
397 /// non-empty subsections set.
398 std::unique_ptr<SparseIterator> makeNonEmptySubSectIterator(
399  OpBuilder &b, Location l, const SparseIterator *parent, Value loopBound,
400  std::unique_ptr<SparseIterator> &&delegate, Value size, unsigned stride,
401  SparseEmitStrategy strategy);
402 
403 /// Helper function to create a SparseIterator object that iterates over a
404 /// non-empty subsection created by NonEmptySubSectIterator.
405 std::unique_ptr<SparseIterator> makeTraverseSubSectIterator(
406  OpBuilder &b, Location l, const SparseIterator &subsectIter,
407  const SparseIterator &parent, std::unique_ptr<SparseIterator> &&wrap,
408  Value loopBound, unsigned stride, SparseEmitStrategy strategy);
409 
410 } // namespace sparse_tensor
411 } // namespace mlir
412 
413 #endif // MLIR_DIALECT_SPARSETENSOR_TRANSFORMS_UTILS_SPARSETENSORITERATOR_H_
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
This class helps build Operations.
Definition: Builders.h:210
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
A SparseIterationSpace represents a sparse set of coordinates defined by (possibly multiple) levels o...
const SparseTensorLevel & getLastLvl() const
static SparseIterationSpace fromValues(IterSpaceType dstTp, ValueRange values, unsigned tid)
std::unique_ptr< SparseIterator > extractIterator(OpBuilder &b, Location l) const
ArrayRef< std::unique_ptr< SparseTensorLevel > > getLvlRef() const
SparseIterationSpace(Location loc, OpBuilder &b, Value t, unsigned tid, Level lvl, ValueRange parentPos)
Helper class that generates loop conditions, etc, to traverse a sparse tensor level.
virtual std::pair< Value, Value > genForCond(OpBuilder &b, Location l)
MutableArrayRef< Value > getMutCursorVals()
virtual void genInitImpl(OpBuilder &, Location, const SparseIterator *)=0
ValueRange forward(OpBuilder &b, Location l)
SmallVector< Value > toValues() const
SparseIterator(IterKind kind, unsigned cursorValsCnt, SmallVectorImpl< Value > &cursorValStorage, const SparseIterator &delegate)
void setSparseEmitStrategy(SparseEmitStrategy strategy)
virtual bool isBatchIterator() const =0
virtual void locateImpl(OpBuilder &b, Location l, Value crd)
void genInit(OpBuilder &b, Location l, const SparseIterator *p)
virtual Value upperBound(OpBuilder &b, Location l) const =0
virtual Value derefImpl(OpBuilder &b, Location l)=0
Value genNotEnd(OpBuilder &b, Location l)
void locate(OpBuilder &b, Location l, Value crd)
virtual void deserialize(ValueRange vs)
SparseIterator(IterKind kind, const SparseIterator &wrap, unsigned extraCursorCnt=0)
static std::unique_ptr< SparseIterator > fromValues(IteratorType dstTp, ValueRange values, unsigned tid)
virtual ValueRange forwardIf(OpBuilder &b, Location l, Value cond)
virtual Value genNotEndImpl(OpBuilder &b, Location l)=0
void inherentBatch(const SparseIterator &parent)
ValueRange linkNewScope(ValueRange pos)
virtual std::string getDebugInterfacePrefix() const =0
virtual SmallVector< Value > serialize() const
virtual ValueRange getCurPosition() const
Value deref(OpBuilder &b, Location l)
virtual bool randomAccessible() const =0
virtual ValueRange forwardImpl(OpBuilder &b, Location l)=0
virtual SmallVector< Type > getCursorValTypes(OpBuilder &b) const =0
SparseIterator(IterKind kind, unsigned tid, unsigned lvl, unsigned cursorValsCnt, SmallVectorImpl< Value > &cursorValStorage)
std::pair< Value, ValueRange > genWhileCond(OpBuilder &b, Location l, ValueRange vs)
The base class for all types of sparse tensor levels.
virtual std::pair< Value, Value > peekRangeAt(OpBuilder &b, Location l, ValueRange batchPrefix, ValueRange parentPos, Value inPadZone=nullptr) const =0
Peeks the lower and upper bound to fully traverse the level with the given position parentPos,...
virtual std::pair< Value, Value > collapseRangeBetween(OpBuilder &b, Location l, ValueRange batchPrefix, std::pair< Value, Value > parentRange) const
virtual Value peekCrdAt(OpBuilder &b, Location l, ValueRange batchPrefix, Value iv) const =0
virtual ValueRange getLvlBuffers() const =0
SparseTensorLevel(unsigned tid, unsigned lvl, LevelType lt, Value lvlSize)
MlirDiagnostic wrap(mlir::Diagnostic &diagnostic)
Definition: Diagnostics.h:24
bool isUniqueLT(LevelType lt)
Definition: Enums.h:428
std::string toMLIRString(LevelType lt)
Definition: Enums.h:447
std::unique_ptr< SparseTensorLevel > makeSparseTensorLevel(OpBuilder &b, Location l, Value t, unsigned tid, Level lvl)
Helper function to create a TensorLevel object from given tensor.
std::unique_ptr< SparseIterator > makeTraverseSubSectIterator(OpBuilder &b, Location l, const SparseIterator &subsectIter, const SparseIterator &parent, std::unique_ptr< SparseIterator > &&wrap, Value loopBound, unsigned stride, SparseEmitStrategy strategy)
Helper function to create a SparseIterator object that iterates over a non-empty subsection created b...
uint64_t Level
The type of level identifiers and level-ranks.
Definition: SparseTensor.h:42
std::pair< std::unique_ptr< SparseTensorLevel >, std::unique_ptr< SparseIterator > > makeSynLevelAndIterator(Value sz, unsigned tid, unsigned lvl, SparseEmitStrategy strategy)
Helper function to create a synthetic SparseIterator object that iterates over a dense space specifie...
std::unique_ptr< SparseIterator > makePaddedIterator(std::unique_ptr< SparseIterator > &&sit, Value padLow, Value padHigh, SparseEmitStrategy strategy)
Helper function to create a SparseIterator object that iterates over a padded sparse level (the padde...
std::unique_ptr< SparseIterator > makeSimpleIterator(OpBuilder &b, Location l, const SparseIterationSpace &iterSpace)
Helper function to create a simple SparseIterator object that iterate over the entire iteration space...
std::unique_ptr< SparseIterator > makeSlicedLevelIterator(std::unique_ptr< SparseIterator > &&sit, Value offset, Value stride, Value size, SparseEmitStrategy strategy)
Helper function to create a SparseIterator object that iterates over a sliced space,...
std::unique_ptr< SparseIterator > makeNonEmptySubSectIterator(OpBuilder &b, Location l, const SparseIterator *parent, Value loopBound, std::unique_ptr< SparseIterator > &&delegate, Value size, unsigned stride, SparseEmitStrategy strategy)
Helper function to create a SparseIterator object that iterate over the non-empty subsections set.
Include the generated interface declarations.
SparseEmitStrategy
Defines a scope for reinterpret map pass.
Definition: Passes.h:52
This enum defines all the sparse representations supportable by the SparseTensor dialect.
Definition: Enums.h:238