16#include "llvm/ADT/DenseSet.h"
29 explicit AffineDimFinder(ArrayRef<utils::IteratorType> itTypes)
30 : iterTypes(itTypes) {}
33 void visitDimExpr(AffineDimExpr expr) {
34 if (pickedDim ==
nullptr || pickIterType == iterTypes[expr.
getPosition()])
39 void setPickedIterType(utils::IteratorType iterType) {
40 pickIterType = iterType;
44 AffineDimExpr getDimExpr()
const {
45 return llvm::cast<AffineDimExpr>(pickedDim);
49 void walkPostOrder(AffineExpr expr) {
58 utils::IteratorType pickIterType;
60 ArrayRef<utils::IteratorType> iterTypes;
66 void visitDimExpr(AffineDimExpr expr) { dims.push_back(expr); }
67 SmallVector<AffineDimExpr> dims;
73 return static_cast<unsigned>(mask1) &
static_cast<unsigned>(mask2);
92 bool preferDenseOuter) {
93 const unsigned denseRank = preferDenseOuter ? 0 : 2;
94 const unsigned singletonRank = preferDenseOuter ? 2 : 0;
95 const unsigned compressedRank = 1;
96 const unsigned unknownRank = 3;
98 unsigned minRank = unknownRank;
100 for (
auto [
tensor, map] : llvm::zip(allTensors, allMaps)) {
102 bool loopAccessesTensor =
false;
103 unsigned tensorDim = 0;
105 if (
auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
106 if (dimExpr.getPosition() == loop) {
107 loopAccessesTensor =
true;
114 if (loopAccessesTensor) {
121 auto lvlTypes = enc.getLvlTypes();
122 if (tensorDim < lvlTypes.size()) {
123 auto lvlType = lvlTypes[tensorDim];
127 minRank = std::min(minRank, compressedRank);
129 minRank = std::min(minRank, singletonRank);
142 llvm::SmallDenseSet<std::pair<Value, AffineMap>> seen;
143 auto maps = genericOp.getIndexingMapsArray();
145 for (
auto [idx, input] : llvm::enumerate(genericOp.getDpsInputs())) {
146 if (genericOp.getRegion().front().getArgument(idx).use_empty())
150 if (!seen.insert({input, map}).second)
153 llvm::SmallDenseSet<unsigned> accessedLoops;
157 if (
auto dim = dyn_cast<AffineDimExpr>(subExpr))
158 accessedLoops.insert(dim.getPosition());
162 for (
unsigned loop : accessedLoops)
168AffineMap IterationGraphSorter::topoSort() {
171 std::vector<unsigned> redIt;
172 std::vector<unsigned> parIt;
174 for (
unsigned i = 0; i < numLoops; i++) {
175 if (inDegree[i] == 0) {
176 if (iterTypes[i] == utils::IteratorType::reduction)
183 SmallVector<unsigned> loopOrder;
184 while (!redIt.empty() || !parIt.empty()) {
187 auto &it = !parIt.empty() ? parIt : redIt;
198 assert(loopUseCounts.size() == numLoops);
202 for (
unsigned candidate : it) {
203 unsigned count = loopUseCounts[candidate];
204 unsigned bestCount = loopUseCounts[src];
206 if (preferMore ? count > bestCount : count < bestCount)
214 SmallVector<Value> allTensors = ins;
215 allTensors.push_back(out);
216 SmallVector<AffineMap> allMaps = loop2InsLvl;
217 allMaps.push_back(loop2OutLvl);
220 unsigned minLoop = it[0];
224 for (
auto candidateLoop : it) {
227 if (rank < minRank || (rank == minRank && candidateLoop < minLoop)) {
228 minLoop = candidateLoop;
237 SmallVector<Value> allTensors = ins;
238 allTensors.push_back(out);
239 SmallVector<AffineMap> allMaps = loop2InsLvl;
240 allMaps.push_back(loop2OutLvl);
242 unsigned minLoop = it[0];
246 for (
auto candidateLoop : it) {
249 if (rank < minRank || (rank == minRank && candidateLoop < minLoop)) {
250 minLoop = candidateLoop;
259 loopOrder.push_back(src);
261 it.erase(std::find(it.begin(), it.end(), src));
263 for (
unsigned dst = 0; dst < numLoops; dst++) {
264 if (itGraph[src][dst] && --inDegree[dst] == 0) {
265 if (iterTypes[dst] == utils::IteratorType::reduction)
266 redIt.push_back(dst);
268 parIt.push_back(dst);
274 if (loopOrder.size() == numLoops)
286 genericOp.getNumDpsInits() == 1);
294 Value out = genericOp.getDpsInitOperand(0)->get();
296 genericOp.getIteratorTypesArray();
298 return IterationGraphSorter(std::move(ins), std::move(loopMap), out, outMap,
299 std::move(iterTypes), genericOp, strategy);
302IterationGraphSorter::IterationGraphSorter(
307 : ins(std::move(insArg)), loop2InsLvl(std::move(loop2InsLvlArg)), out(out),
308 loop2OutLvl(loop2OutLvl), iterTypes(std::move(iterTypesArg)),
311 assert(loop2InsLvl.size() == ins.size());
313 assert(llvm::all_equal(llvm::map_range(
316 assert(llvm::all_of(llvm::zip(loop2InsLvl, ins), [](
auto mvPair) {
317 auto [m, v] = mvPair;
321 if (
auto shapedType = llvm::dyn_cast<ShapedType>(v.getType())) {
322 return !shapedType.hasRank() ||
344 for (
auto &row : itGraph)
345 llvm::fill(row,
false);
348 llvm::fill(inDegree, 0);
351 for (
auto [in, map] : llvm::zip(ins, loop2InsLvl)) {
357 addConstraints(in, map);
363 addConstraints(out, loop2OutLvl);
369void IterationGraphSorter::addConstraints(
Value t,
AffineMap loop2LvlMap) {
370 auto addIterOrdering = [
this](
unsigned f,
unsigned t) {
371 if (!itGraph[f][t] && f != t) {
372 itGraph[f][t] =
true;
378 AffineDimFinder finder(iterTypes);
379 finder.setPickedIterType(utils::IteratorType::reduction);
385 for (
Level lvl = 1; lvl < lvlRank; lvl++) {
389 if (llvm::isa<AffineDimExpr>(fa) || llvm::isa<AffineDimExpr>(ta)) {
392 AffineDimCollector fCollector;
393 fCollector.walkPostOrder(fa);
394 AffineDimCollector tCollector;
395 tCollector.walkPostOrder(ta);
397 for (
auto fd : fCollector.dims) {
398 for (
auto td : tCollector.dims) {
399 const unsigned f = fd.getPosition();
400 const unsigned t = td.getPosition();
401 addIterOrdering(f, t);
409 finder.walkPostOrder(fa);
410 const AffineDimExpr fexp = finder.getDimExpr();
413 finder.walkPostOrder(ta);
414 const AffineDimExpr texp = finder.getDimExpr();
418 addIterOrdering(fldx, tldx);
420 AffineDimCollector fCollector;
421 fCollector.walkPostOrder(fa);
422 AffineDimCollector tCollector;
423 tCollector.walkPostOrder(ta);
426 for (
auto fd : fCollector.dims) {
427 const unsigned f = fd.getPosition();
428 addIterOrdering(f, fldx);
430 for (
auto td : tCollector.dims) {
431 const unsigned t = td.getPosition();
432 addIterOrdering(t, tldx);
437 for (
auto fd : fCollector.dims) {
438 const unsigned f = fd.getPosition();
441 for (
auto td : tCollector.dims) {
442 const unsigned t = td.getPosition();
445 addIterOrdering(f, t);
static bool includesDenseOutput(SortMask mask)
static bool includesAny(SortMask mask1, SortMask mask2)
static SmallVector< unsigned > getLoopUseCounts(linalg::GenericOp genericOp)
Count distinct input accesses whose indexing expressions use each loop.
static unsigned getLoopSparsityRank(unsigned loop, ArrayRef< Value > allTensors, ArrayRef< AffineMap > allMaps, bool preferDenseOuter)
Returns a sparsity rank for loop ordering: lower values indicate dimensions that should be placed in ...
static bool includesDenseInput(SortMask mask)
unsigned getPosition() const
See documentation for AffineExprVisitorBase.
RetTy walkPostOrder(AffineExpr expr)
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
unsigned getNumResults() const
AffineExpr getResult(unsigned idx) const
static AffineMap getPermutationMap(ArrayRef< unsigned > permutation, MLIRContext *context)
Returns an AffineMap representing a permutation.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
static IterationGraphSorter fromGenericOp(linalg::GenericOp genericOp, sparse_tensor::LoopOrderingStrategy strategy)
Factory method that constructs an iteration graph sorter for the given linalg.generic operation with ...
unsigned getNumLoops() const
Returns the number of loops in the iteration graph.
AffineMap sort(SortMask mask, Value ignored=nullptr)
Returns a permutation that represents the scheduled loop order.
bool hasAnySparseOperandOrResult(Operation *op)
Returns true iff MLIR operand has any sparse operand or result.
bool isSingletonLT(LevelType lt)
bool isCompressedLT(LevelType lt)
uint64_t Level
The type of level identifiers and level-ranks.
LoopOrderingStrategy
Defines a strategy for loop ordering during sparse code generation.
SparseTensorEncodingAttr getSparseTensorEncoding(Type type)
Convenience method to get a sparse encoding attribute from a type.
bool isDenseLT(LevelType lt)
bool hasAnyNonIdentityOperandsOrResults(Operation *op)
Returns true iff MLIR operation has any sparse tensor with non-identity dim2lvl maps.
SortMask
Iteration graph sorting mask,.
Include the generated interface declarations.