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 for (
auto [
tensor, map] : llvm::zip(allTensors, allMaps)) {
93 bool loopAccessesTensor =
false;
94 unsigned tensorDim = 0;
96 if (
auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
97 if (dimExpr.getPosition() == loop) {
98 loopAccessesTensor =
true;
105 if (loopAccessesTensor) {
112 auto lvlTypes = enc.getLvlTypes();
113 if (tensorDim < lvlTypes.size()) {
114 auto lvlType = lvlTypes[tensorDim];
118 minRank = std::min(minRank, 1u);
120 minRank = std::min(minRank, 2u);
130AffineMap IterationGraphSorter::topoSort() {
133 std::vector<unsigned> redIt;
134 std::vector<unsigned> parIt;
136 for (
unsigned i = 0; i < numLoops; i++) {
137 if (inDegree[i] == 0) {
138 if (iterTypes[i] == utils::IteratorType::reduction)
145 SmallVector<unsigned> loopOrder;
146 while (!redIt.empty() || !parIt.empty()) {
149 auto &it = !parIt.empty() ? parIt : redIt;
160 SmallVector<Value> allTensors = ins;
161 allTensors.push_back(out);
162 SmallVector<AffineMap> allMaps = loop2InsLvl;
163 allMaps.push_back(loop2OutLvl);
166 unsigned minLoop = it[0];
169 for (
auto candidateLoop : it) {
171 if (rank < minRank || (rank == minRank && candidateLoop < minLoop)) {
172 minLoop = candidateLoop;
181 loopOrder.push_back(src);
183 it.erase(std::find(it.begin(), it.end(), src));
185 for (
unsigned dst = 0; dst < numLoops; dst++) {
186 if (itGraph[src][dst] && --inDegree[dst] == 0) {
187 if (iterTypes[dst] == utils::IteratorType::reduction)
188 redIt.push_back(dst);
190 parIt.push_back(dst);
196 if (loopOrder.size() == numLoops)
208 genericOp.getNumDpsInits() == 1);
216 Value out = genericOp.getDpsInitOperand(0)->get();
218 genericOp.getIteratorTypesArray();
220 return IterationGraphSorter(std::move(ins), std::move(loopMap), out, outMap,
221 std::move(iterTypes), strategy);
224IterationGraphSorter::IterationGraphSorter(
229 : ins(std::move(insArg)), loop2InsLvl(std::move(loop2InsLvlArg)), out(out),
230 loop2OutLvl(loop2OutLvl), iterTypes(std::move(iterTypesArg)),
233 assert(loop2InsLvl.size() == ins.size());
235 assert(llvm::all_equal(llvm::map_range(
238 assert(llvm::all_of(llvm::zip(loop2InsLvl, ins), [](
auto mvPair) {
239 auto [m, v] = mvPair;
243 if (
auto shapedType = llvm::dyn_cast<ShapedType>(v.getType())) {
244 return !shapedType.hasRank() ||
257 for (
auto &row : itGraph)
258 llvm::fill(row,
false);
261 llvm::fill(inDegree, 0);
264 for (
auto [in, map] : llvm::zip(ins, loop2InsLvl)) {
270 addConstraints(in, map);
276 addConstraints(out, loop2OutLvl);
282void IterationGraphSorter::addConstraints(
Value t,
AffineMap loop2LvlMap) {
283 auto addIterOrdering = [
this](
unsigned f,
unsigned t) {
284 if (!itGraph[f][t] && f != t) {
285 itGraph[f][t] =
true;
291 AffineDimFinder finder(iterTypes);
292 finder.setPickedIterType(utils::IteratorType::reduction);
298 for (
Level lvl = 1; lvl < lvlRank; lvl++) {
302 if (llvm::isa<AffineDimExpr>(fa) || llvm::isa<AffineDimExpr>(ta)) {
305 AffineDimCollector fCollector;
306 fCollector.walkPostOrder(fa);
307 AffineDimCollector tCollector;
308 tCollector.walkPostOrder(ta);
310 for (
auto fd : fCollector.dims) {
311 for (
auto td : tCollector.dims) {
312 const unsigned f = fd.getPosition();
313 const unsigned t = td.getPosition();
314 addIterOrdering(f, t);
322 finder.walkPostOrder(fa);
323 const AffineDimExpr fexp = finder.getDimExpr();
326 finder.walkPostOrder(ta);
327 const AffineDimExpr texp = finder.getDimExpr();
331 addIterOrdering(fldx, tldx);
333 AffineDimCollector fCollector;
334 fCollector.walkPostOrder(fa);
335 AffineDimCollector tCollector;
336 tCollector.walkPostOrder(ta);
339 for (
auto fd : fCollector.dims) {
340 const unsigned f = fd.getPosition();
341 addIterOrdering(f, fldx);
343 for (
auto td : tCollector.dims) {
344 const unsigned t = td.getPosition();
345 addIterOrdering(t, tldx);
350 for (
auto fd : fCollector.dims) {
351 const unsigned f = fd.getPosition();
354 for (
auto td : tCollector.dims) {
355 const unsigned t = td.getPosition();
358 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)
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.