28 explicit AffineDimFinder(ArrayRef<utils::IteratorType> itTypes)
29 : iterTypes(itTypes) {}
32 void visitDimExpr(AffineDimExpr expr) {
33 if (pickedDim ==
nullptr || pickIterType == iterTypes[expr.
getPosition()])
38 void setPickedIterType(utils::IteratorType iterType) {
39 pickIterType = iterType;
43 AffineDimExpr getDimExpr()
const {
44 return llvm::cast<AffineDimExpr>(pickedDim);
48 void walkPostOrder(AffineExpr expr) {
57 utils::IteratorType pickIterType;
59 ArrayRef<utils::IteratorType> iterTypes;
65 void visitDimExpr(AffineDimExpr expr) { dims.push_back(expr); }
66 SmallVector<AffineDimExpr> dims;
72 return static_cast<unsigned>(mask1) &
static_cast<unsigned>(mask2);
91 bool preferDenseOuter) {
92 const unsigned denseRank = preferDenseOuter ? 0 : 2;
93 const unsigned singletonRank = preferDenseOuter ? 2 : 0;
94 const unsigned compressedRank = 1;
95 const unsigned unknownRank = 3;
97 unsigned minRank = unknownRank;
99 for (
auto [
tensor, map] : llvm::zip(allTensors, allMaps)) {
101 bool loopAccessesTensor =
false;
102 unsigned tensorDim = 0;
104 if (
auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
105 if (dimExpr.getPosition() == loop) {
106 loopAccessesTensor =
true;
113 if (loopAccessesTensor) {
120 auto lvlTypes = enc.getLvlTypes();
121 if (tensorDim < lvlTypes.size()) {
122 auto lvlType = lvlTypes[tensorDim];
126 minRank = std::min(minRank, compressedRank);
128 minRank = std::min(minRank, singletonRank);
138AffineMap IterationGraphSorter::topoSort() {
141 std::vector<unsigned> redIt;
142 std::vector<unsigned> parIt;
144 for (
unsigned i = 0; i < numLoops; i++) {
145 if (inDegree[i] == 0) {
146 if (iterTypes[i] == utils::IteratorType::reduction)
153 SmallVector<unsigned> loopOrder;
154 while (!redIt.empty() || !parIt.empty()) {
157 auto &it = !parIt.empty() ? parIt : redIt;
168 SmallVector<Value> allTensors = ins;
169 allTensors.push_back(out);
170 SmallVector<AffineMap> allMaps = loop2InsLvl;
171 allMaps.push_back(loop2OutLvl);
174 unsigned minLoop = it[0];
178 for (
auto candidateLoop : it) {
181 if (rank < minRank || (rank == minRank && candidateLoop < minLoop)) {
182 minLoop = candidateLoop;
191 SmallVector<Value> allTensors = ins;
192 allTensors.push_back(out);
193 SmallVector<AffineMap> allMaps = loop2InsLvl;
194 allMaps.push_back(loop2OutLvl);
196 unsigned minLoop = it[0];
200 for (
auto candidateLoop : it) {
203 if (rank < minRank || (rank == minRank && candidateLoop < minLoop)) {
204 minLoop = candidateLoop;
213 loopOrder.push_back(src);
215 it.erase(std::find(it.begin(), it.end(), src));
217 for (
unsigned dst = 0; dst < numLoops; dst++) {
218 if (itGraph[src][dst] && --inDegree[dst] == 0) {
219 if (iterTypes[dst] == utils::IteratorType::reduction)
220 redIt.push_back(dst);
222 parIt.push_back(dst);
228 if (loopOrder.size() == numLoops)
240 genericOp.getNumDpsInits() == 1);
248 Value out = genericOp.getDpsInitOperand(0)->get();
250 genericOp.getIteratorTypesArray();
252 return IterationGraphSorter(std::move(ins), std::move(loopMap), out, outMap,
253 std::move(iterTypes), strategy);
256IterationGraphSorter::IterationGraphSorter(
261 : ins(std::move(insArg)), loop2InsLvl(std::move(loop2InsLvlArg)), out(out),
262 loop2OutLvl(loop2OutLvl), iterTypes(std::move(iterTypesArg)),
265 assert(loop2InsLvl.size() == ins.size());
267 assert(llvm::all_equal(llvm::map_range(
270 assert(llvm::all_of(llvm::zip(loop2InsLvl, ins), [](
auto mvPair) {
271 auto [m, v] = mvPair;
275 if (
auto shapedType = llvm::dyn_cast<ShapedType>(v.getType())) {
276 return !shapedType.hasRank() ||
289 for (
auto &row : itGraph)
290 llvm::fill(row,
false);
293 llvm::fill(inDegree, 0);
296 for (
auto [in, map] : llvm::zip(ins, loop2InsLvl)) {
302 addConstraints(in, map);
308 addConstraints(out, loop2OutLvl);
314void IterationGraphSorter::addConstraints(
Value t,
AffineMap loop2LvlMap) {
315 auto addIterOrdering = [
this](
unsigned f,
unsigned t) {
316 if (!itGraph[f][t] && f != t) {
317 itGraph[f][t] =
true;
323 AffineDimFinder finder(iterTypes);
324 finder.setPickedIterType(utils::IteratorType::reduction);
330 for (
Level lvl = 1; lvl < lvlRank; lvl++) {
334 if (llvm::isa<AffineDimExpr>(fa) || llvm::isa<AffineDimExpr>(ta)) {
337 AffineDimCollector fCollector;
338 fCollector.walkPostOrder(fa);
339 AffineDimCollector tCollector;
340 tCollector.walkPostOrder(ta);
342 for (
auto fd : fCollector.dims) {
343 for (
auto td : tCollector.dims) {
344 const unsigned f = fd.getPosition();
345 const unsigned t = td.getPosition();
346 addIterOrdering(f, t);
354 finder.walkPostOrder(fa);
355 const AffineDimExpr fexp = finder.getDimExpr();
358 finder.walkPostOrder(ta);
359 const AffineDimExpr texp = finder.getDimExpr();
363 addIterOrdering(fldx, tldx);
365 AffineDimCollector fCollector;
366 fCollector.walkPostOrder(fa);
367 AffineDimCollector tCollector;
368 tCollector.walkPostOrder(ta);
371 for (
auto fd : fCollector.dims) {
372 const unsigned f = fd.getPosition();
373 addIterOrdering(f, fldx);
375 for (
auto td : tCollector.dims) {
376 const unsigned t = td.getPosition();
377 addIterOrdering(t, tldx);
382 for (
auto fd : fCollector.dims) {
383 const unsigned f = fd.getPosition();
386 for (
auto td : tCollector.dims) {
387 const unsigned t = td.getPosition();
390 addIterOrdering(f, t);
static bool includesDenseOutput(SortMask mask)
static bool includesAny(SortMask mask1, SortMask mask2)
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
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.