1 //===- AffineExpr.cpp - MLIR Affine Expr Classes --------------------------===//
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 #include "mlir/IR/AffineExpr.h"
10 #include "AffineExprDetail.h"
11 #include "mlir/IR/AffineExprVisitor.h"
12 #include "mlir/IR/AffineMap.h"
13 #include "mlir/IR/IntegerSet.h"
14 #include "mlir/Support/MathExtras.h"
15 #include "mlir/Support/STLExtras.h"
16 #include "llvm/ADT/STLExtras.h"
17 
18 using namespace mlir;
19 using namespace mlir::detail;
20 
21 MLIRContext *AffineExpr::getContext() const { return expr->context; }
22 
23 AffineExprKind AffineExpr::getKind() const {
24   return static_cast<AffineExprKind>(expr->getKind());
25 }
26 
27 /// Walk all of the AffineExprs in this subgraph in postorder.
28 void AffineExpr::walk(std::function<void(AffineExpr)> callback) const {
29   struct AffineExprWalker : public AffineExprVisitor<AffineExprWalker> {
30     std::function<void(AffineExpr)> callback;
31 
32     AffineExprWalker(std::function<void(AffineExpr)> callback)
33         : callback(callback) {}
34 
35     void visitAffineBinaryOpExpr(AffineBinaryOpExpr expr) { callback(expr); }
36     void visitConstantExpr(AffineConstantExpr expr) { callback(expr); }
37     void visitDimExpr(AffineDimExpr expr) { callback(expr); }
38     void visitSymbolExpr(AffineSymbolExpr expr) { callback(expr); }
39   };
40 
41   AffineExprWalker(callback).walkPostOrder(*this);
42 }
43 
44 // Dispatch affine expression construction based on kind.
45 AffineExpr mlir::getAffineBinaryOpExpr(AffineExprKind kind, AffineExpr lhs,
46                                        AffineExpr rhs) {
47   if (kind == AffineExprKind::Add)
48     return lhs + rhs;
49   if (kind == AffineExprKind::Mul)
50     return lhs * rhs;
51   if (kind == AffineExprKind::FloorDiv)
52     return lhs.floorDiv(rhs);
53   if (kind == AffineExprKind::CeilDiv)
54     return lhs.ceilDiv(rhs);
55   if (kind == AffineExprKind::Mod)
56     return lhs % rhs;
57 
58   llvm_unreachable("unknown binary operation on affine expressions");
59 }
60 
61 /// This method substitutes any uses of dimensions and symbols (e.g.
62 /// dim#0 with dimReplacements[0]) and returns the modified expression tree.
63 AffineExpr
64 AffineExpr::replaceDimsAndSymbols(ArrayRef<AffineExpr> dimReplacements,
65                                   ArrayRef<AffineExpr> symReplacements) const {
66   switch (getKind()) {
67   case AffineExprKind::Constant:
68     return *this;
69   case AffineExprKind::DimId: {
70     unsigned dimId = cast<AffineDimExpr>().getPosition();
71     if (dimId >= dimReplacements.size())
72       return *this;
73     return dimReplacements[dimId];
74   }
75   case AffineExprKind::SymbolId: {
76     unsigned symId = cast<AffineSymbolExpr>().getPosition();
77     if (symId >= symReplacements.size())
78       return *this;
79     return symReplacements[symId];
80   }
81   case AffineExprKind::Add:
82   case AffineExprKind::Mul:
83   case AffineExprKind::FloorDiv:
84   case AffineExprKind::CeilDiv:
85   case AffineExprKind::Mod:
86     auto binOp = cast<AffineBinaryOpExpr>();
87     auto lhs = binOp.getLHS(), rhs = binOp.getRHS();
88     auto newLHS = lhs.replaceDimsAndSymbols(dimReplacements, symReplacements);
89     auto newRHS = rhs.replaceDimsAndSymbols(dimReplacements, symReplacements);
90     if (newLHS == lhs && newRHS == rhs)
91       return *this;
92     return getAffineBinaryOpExpr(getKind(), newLHS, newRHS);
93   }
94   llvm_unreachable("Unknown AffineExpr");
95 }
96 
97 /// Returns true if this expression is made out of only symbols and
98 /// constants (no dimensional identifiers).
99 bool AffineExpr::isSymbolicOrConstant() const {
100   switch (getKind()) {
101   case AffineExprKind::Constant:
102     return true;
103   case AffineExprKind::DimId:
104     return false;
105   case AffineExprKind::SymbolId:
106     return true;
107 
108   case AffineExprKind::Add:
109   case AffineExprKind::Mul:
110   case AffineExprKind::FloorDiv:
111   case AffineExprKind::CeilDiv:
112   case AffineExprKind::Mod: {
113     auto expr = this->cast<AffineBinaryOpExpr>();
114     return expr.getLHS().isSymbolicOrConstant() &&
115            expr.getRHS().isSymbolicOrConstant();
116   }
117   }
118   llvm_unreachable("Unknown AffineExpr");
119 }
120 
121 /// Returns true if this is a pure affine expression, i.e., multiplication,
122 /// floordiv, ceildiv, and mod is only allowed w.r.t constants.
123 bool AffineExpr::isPureAffine() const {
124   switch (getKind()) {
125   case AffineExprKind::SymbolId:
126   case AffineExprKind::DimId:
127   case AffineExprKind::Constant:
128     return true;
129   case AffineExprKind::Add: {
130     auto op = cast<AffineBinaryOpExpr>();
131     return op.getLHS().isPureAffine() && op.getRHS().isPureAffine();
132   }
133 
134   case AffineExprKind::Mul: {
135     // TODO: Canonicalize the constants in binary operators to the RHS when
136     // possible, allowing this to merge into the next case.
137     auto op = cast<AffineBinaryOpExpr>();
138     return op.getLHS().isPureAffine() && op.getRHS().isPureAffine() &&
139            (op.getLHS().template isa<AffineConstantExpr>() ||
140             op.getRHS().template isa<AffineConstantExpr>());
141   }
142   case AffineExprKind::FloorDiv:
143   case AffineExprKind::CeilDiv:
144   case AffineExprKind::Mod: {
145     auto op = cast<AffineBinaryOpExpr>();
146     return op.getLHS().isPureAffine() &&
147            op.getRHS().template isa<AffineConstantExpr>();
148   }
149   }
150   llvm_unreachable("Unknown AffineExpr");
151 }
152 
153 // Returns the greatest known integral divisor of this affine expression.
154 int64_t AffineExpr::getLargestKnownDivisor() const {
155   AffineBinaryOpExpr binExpr(nullptr);
156   switch (getKind()) {
157   case AffineExprKind::SymbolId:
158     LLVM_FALLTHROUGH;
159   case AffineExprKind::DimId:
160     return 1;
161   case AffineExprKind::Constant:
162     return std::abs(this->cast<AffineConstantExpr>().getValue());
163   case AffineExprKind::Mul: {
164     binExpr = this->cast<AffineBinaryOpExpr>();
165     return binExpr.getLHS().getLargestKnownDivisor() *
166            binExpr.getRHS().getLargestKnownDivisor();
167   }
168   case AffineExprKind::Add:
169     LLVM_FALLTHROUGH;
170   case AffineExprKind::FloorDiv:
171   case AffineExprKind::CeilDiv:
172   case AffineExprKind::Mod: {
173     binExpr = cast<AffineBinaryOpExpr>();
174     return llvm::GreatestCommonDivisor64(
175         binExpr.getLHS().getLargestKnownDivisor(),
176         binExpr.getRHS().getLargestKnownDivisor());
177   }
178   }
179   llvm_unreachable("Unknown AffineExpr");
180 }
181 
182 bool AffineExpr::isMultipleOf(int64_t factor) const {
183   AffineBinaryOpExpr binExpr(nullptr);
184   uint64_t l, u;
185   switch (getKind()) {
186   case AffineExprKind::SymbolId:
187     LLVM_FALLTHROUGH;
188   case AffineExprKind::DimId:
189     return factor * factor == 1;
190   case AffineExprKind::Constant:
191     return cast<AffineConstantExpr>().getValue() % factor == 0;
192   case AffineExprKind::Mul: {
193     binExpr = cast<AffineBinaryOpExpr>();
194     // It's probably not worth optimizing this further (to not traverse the
195     // whole sub-tree under - it that would require a version of isMultipleOf
196     // that on a 'false' return also returns the largest known divisor).
197     return (l = binExpr.getLHS().getLargestKnownDivisor()) % factor == 0 ||
198            (u = binExpr.getRHS().getLargestKnownDivisor()) % factor == 0 ||
199            (l * u) % factor == 0;
200   }
201   case AffineExprKind::Add:
202   case AffineExprKind::FloorDiv:
203   case AffineExprKind::CeilDiv:
204   case AffineExprKind::Mod: {
205     binExpr = cast<AffineBinaryOpExpr>();
206     return llvm::GreatestCommonDivisor64(
207                binExpr.getLHS().getLargestKnownDivisor(),
208                binExpr.getRHS().getLargestKnownDivisor()) %
209                factor ==
210            0;
211   }
212   }
213   llvm_unreachable("Unknown AffineExpr");
214 }
215 
216 bool AffineExpr::isFunctionOfDim(unsigned position) const {
217   if (getKind() == AffineExprKind::DimId) {
218     return *this == mlir::getAffineDimExpr(position, getContext());
219   }
220   if (auto expr = this->dyn_cast<AffineBinaryOpExpr>()) {
221     return expr.getLHS().isFunctionOfDim(position) ||
222            expr.getRHS().isFunctionOfDim(position);
223   }
224   return false;
225 }
226 
227 AffineBinaryOpExpr::AffineBinaryOpExpr(AffineExpr::ImplType *ptr)
228     : AffineExpr(ptr) {}
229 AffineExpr AffineBinaryOpExpr::getLHS() const {
230   return static_cast<ImplType *>(expr)->lhs;
231 }
232 AffineExpr AffineBinaryOpExpr::getRHS() const {
233   return static_cast<ImplType *>(expr)->rhs;
234 }
235 
236 AffineDimExpr::AffineDimExpr(AffineExpr::ImplType *ptr) : AffineExpr(ptr) {}
237 unsigned AffineDimExpr::getPosition() const {
238   return static_cast<ImplType *>(expr)->position;
239 }
240 
241 static AffineExpr getAffineDimOrSymbol(AffineExprKind kind, unsigned position,
242                                        MLIRContext *context) {
243   auto assignCtx = [context](AffineDimExprStorage *storage) {
244     storage->context = context;
245   };
246 
247   StorageUniquer &uniquer = context->getAffineUniquer();
248   return uniquer.get<AffineDimExprStorage>(
249       assignCtx, static_cast<unsigned>(kind), position);
250 }
251 
252 AffineExpr mlir::getAffineDimExpr(unsigned position, MLIRContext *context) {
253   return getAffineDimOrSymbol(AffineExprKind::DimId, position, context);
254 }
255 
256 AffineSymbolExpr::AffineSymbolExpr(AffineExpr::ImplType *ptr)
257     : AffineExpr(ptr) {}
258 unsigned AffineSymbolExpr::getPosition() const {
259   return static_cast<ImplType *>(expr)->position;
260 }
261 
262 AffineExpr mlir::getAffineSymbolExpr(unsigned position, MLIRContext *context) {
263   return getAffineDimOrSymbol(AffineExprKind::SymbolId, position, context);
264   ;
265 }
266 
267 AffineConstantExpr::AffineConstantExpr(AffineExpr::ImplType *ptr)
268     : AffineExpr(ptr) {}
269 int64_t AffineConstantExpr::getValue() const {
270   return static_cast<ImplType *>(expr)->constant;
271 }
272 
273 bool AffineExpr::operator==(int64_t v) const {
274   return *this == getAffineConstantExpr(v, getContext());
275 }
276 
277 AffineExpr mlir::getAffineConstantExpr(int64_t constant, MLIRContext *context) {
278   auto assignCtx = [context](AffineConstantExprStorage *storage) {
279     storage->context = context;
280   };
281 
282   StorageUniquer &uniquer = context->getAffineUniquer();
283   return uniquer.get<AffineConstantExprStorage>(
284       assignCtx, static_cast<unsigned>(AffineExprKind::Constant), constant);
285 }
286 
287 /// Simplify add expression. Return nullptr if it can't be simplified.
288 static AffineExpr simplifyAdd(AffineExpr lhs, AffineExpr rhs) {
289   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
290   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
291   // Fold if both LHS, RHS are a constant.
292   if (lhsConst && rhsConst)
293     return getAffineConstantExpr(lhsConst.getValue() + rhsConst.getValue(),
294                                  lhs.getContext());
295 
296   // Canonicalize so that only the RHS is a constant. (4 + d0 becomes d0 + 4).
297   // If only one of them is a symbolic expressions, make it the RHS.
298   if (lhs.isa<AffineConstantExpr>() ||
299       (lhs.isSymbolicOrConstant() && !rhs.isSymbolicOrConstant())) {
300     return rhs + lhs;
301   }
302 
303   // At this point, if there was a constant, it would be on the right.
304 
305   // Addition with a zero is a noop, return the other input.
306   if (rhsConst) {
307     if (rhsConst.getValue() == 0)
308       return lhs;
309   }
310   // Fold successive additions like (d0 + 2) + 3 into d0 + 5.
311   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
312   if (lBin && rhsConst && lBin.getKind() == AffineExprKind::Add) {
313     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>())
314       return lBin.getLHS() + (lrhs.getValue() + rhsConst.getValue());
315   }
316 
317   // When doing successive additions, bring constant to the right: turn (d0 + 2)
318   // + d1 into (d0 + d1) + 2.
319   if (lBin && lBin.getKind() == AffineExprKind::Add) {
320     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>()) {
321       return lBin.getLHS() + rhs + lrhs;
322     }
323   }
324 
325   // Detect and transform "expr - c * (expr floordiv c)" to "expr mod c". This
326   // leads to a much more efficient form when 'c' is a power of two, and in
327   // general a more compact and readable form.
328 
329   // Process '(expr floordiv c) * (-c)'.
330   AffineBinaryOpExpr rBinOpExpr = rhs.dyn_cast<AffineBinaryOpExpr>();
331   if (!rBinOpExpr)
332     return nullptr;
333 
334   auto lrhs = rBinOpExpr.getLHS();
335   auto rrhs = rBinOpExpr.getRHS();
336 
337   // Process lrhs, which is 'expr floordiv c'.
338   AffineBinaryOpExpr lrBinOpExpr = lrhs.dyn_cast<AffineBinaryOpExpr>();
339   if (!lrBinOpExpr || lrBinOpExpr.getKind() != AffineExprKind::FloorDiv)
340     return nullptr;
341 
342   auto llrhs = lrBinOpExpr.getLHS();
343   auto rlrhs = lrBinOpExpr.getRHS();
344 
345   if (lhs == llrhs && rlrhs == -rrhs) {
346     return lhs % rlrhs;
347   }
348   return nullptr;
349 }
350 
351 AffineExpr AffineExpr::operator+(int64_t v) const {
352   return *this + getAffineConstantExpr(v, getContext());
353 }
354 AffineExpr AffineExpr::operator+(AffineExpr other) const {
355   if (auto simplified = simplifyAdd(*this, other))
356     return simplified;
357 
358   StorageUniquer &uniquer = getContext()->getAffineUniquer();
359   return uniquer.get<AffineBinaryOpExprStorage>(
360       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::Add), *this, other);
361 }
362 
363 /// Simplify a multiply expression. Return nullptr if it can't be simplified.
364 static AffineExpr simplifyMul(AffineExpr lhs, AffineExpr rhs) {
365   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
366   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
367 
368   if (lhsConst && rhsConst)
369     return getAffineConstantExpr(lhsConst.getValue() * rhsConst.getValue(),
370                                  lhs.getContext());
371 
372   assert(lhs.isSymbolicOrConstant() || rhs.isSymbolicOrConstant());
373 
374   // Canonicalize the mul expression so that the constant/symbolic term is the
375   // RHS. If both the lhs and rhs are symbolic, swap them if the lhs is a
376   // constant. (Note that a constant is trivially symbolic).
377   if (!rhs.isSymbolicOrConstant() || lhs.isa<AffineConstantExpr>()) {
378     // At least one of them has to be symbolic.
379     return rhs * lhs;
380   }
381 
382   // At this point, if there was a constant, it would be on the right.
383 
384   // Multiplication with a one is a noop, return the other input.
385   if (rhsConst) {
386     if (rhsConst.getValue() == 1)
387       return lhs;
388     // Multiplication with zero.
389     if (rhsConst.getValue() == 0)
390       return rhsConst;
391   }
392 
393   // Fold successive multiplications: eg: (d0 * 2) * 3 into d0 * 6.
394   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
395   if (lBin && rhsConst && lBin.getKind() == AffineExprKind::Mul) {
396     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>())
397       return lBin.getLHS() * (lrhs.getValue() * rhsConst.getValue());
398   }
399 
400   // When doing successive multiplication, bring constant to the right: turn (d0
401   // * 2) * d1 into (d0 * d1) * 2.
402   if (lBin && lBin.getKind() == AffineExprKind::Mul) {
403     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>()) {
404       return (lBin.getLHS() * rhs) * lrhs;
405     }
406   }
407 
408   return nullptr;
409 }
410 
411 AffineExpr AffineExpr::operator*(int64_t v) const {
412   return *this * getAffineConstantExpr(v, getContext());
413 }
414 AffineExpr AffineExpr::operator*(AffineExpr other) const {
415   if (auto simplified = simplifyMul(*this, other))
416     return simplified;
417 
418   StorageUniquer &uniquer = getContext()->getAffineUniquer();
419   return uniquer.get<AffineBinaryOpExprStorage>(
420       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::Mul), *this, other);
421 }
422 
423 // Unary minus, delegate to operator*.
424 AffineExpr AffineExpr::operator-() const {
425   return *this * getAffineConstantExpr(-1, getContext());
426 }
427 
428 // Delegate to operator+.
429 AffineExpr AffineExpr::operator-(int64_t v) const { return *this + (-v); }
430 AffineExpr AffineExpr::operator-(AffineExpr other) const {
431   return *this + (-other);
432 }
433 
434 static AffineExpr simplifyFloorDiv(AffineExpr lhs, AffineExpr rhs) {
435   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
436   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
437 
438   // mlir floordiv by zero or negative numbers is undefined and preserved as is.
439   if (!rhsConst || rhsConst.getValue() < 1)
440     return nullptr;
441 
442   if (lhsConst)
443     return getAffineConstantExpr(
444         floorDiv(lhsConst.getValue(), rhsConst.getValue()), lhs.getContext());
445 
446   // Fold floordiv of a multiply with a constant that is a multiple of the
447   // divisor. Eg: (i * 128) floordiv 64 = i * 2.
448   if (rhsConst == 1)
449     return lhs;
450 
451   // Simplify (expr * const) floordiv divConst when expr is known to be a
452   // multiple of divConst.
453   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
454   if (lBin && lBin.getKind() == AffineExprKind::Mul) {
455     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>()) {
456       // rhsConst is known to be a positive constant.
457       if (lrhs.getValue() % rhsConst.getValue() == 0)
458         return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
459     }
460   }
461 
462   // Simplify (expr1 + expr2) floordiv divConst when either expr1 or expr2 is
463   // known to be a multiple of divConst.
464   if (lBin && lBin.getKind() == AffineExprKind::Add) {
465     int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
466     int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
467     // rhsConst is known to be a positive constant.
468     if (llhsDiv % rhsConst.getValue() == 0 ||
469         lrhsDiv % rhsConst.getValue() == 0)
470       return lBin.getLHS().floorDiv(rhsConst.getValue()) +
471              lBin.getRHS().floorDiv(rhsConst.getValue());
472   }
473 
474   return nullptr;
475 }
476 
477 AffineExpr AffineExpr::floorDiv(uint64_t v) const {
478   return floorDiv(getAffineConstantExpr(v, getContext()));
479 }
480 AffineExpr AffineExpr::floorDiv(AffineExpr other) const {
481   if (auto simplified = simplifyFloorDiv(*this, other))
482     return simplified;
483 
484   StorageUniquer &uniquer = getContext()->getAffineUniquer();
485   return uniquer.get<AffineBinaryOpExprStorage>(
486       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::FloorDiv), *this,
487       other);
488 }
489 
490 static AffineExpr simplifyCeilDiv(AffineExpr lhs, AffineExpr rhs) {
491   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
492   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
493 
494   if (!rhsConst || rhsConst.getValue() < 1)
495     return nullptr;
496 
497   if (lhsConst)
498     return getAffineConstantExpr(
499         ceilDiv(lhsConst.getValue(), rhsConst.getValue()), lhs.getContext());
500 
501   // Fold ceildiv of a multiply with a constant that is a multiple of the
502   // divisor. Eg: (i * 128) ceildiv 64 = i * 2.
503   if (rhsConst.getValue() == 1)
504     return lhs;
505 
506   // Simplify (expr * const) ceildiv divConst when const is known to be a
507   // multiple of divConst.
508   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
509   if (lBin && lBin.getKind() == AffineExprKind::Mul) {
510     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>()) {
511       // rhsConst is known to be a positive constant.
512       if (lrhs.getValue() % rhsConst.getValue() == 0)
513         return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
514     }
515   }
516 
517   return nullptr;
518 }
519 
520 AffineExpr AffineExpr::ceilDiv(uint64_t v) const {
521   return ceilDiv(getAffineConstantExpr(v, getContext()));
522 }
523 AffineExpr AffineExpr::ceilDiv(AffineExpr other) const {
524   if (auto simplified = simplifyCeilDiv(*this, other))
525     return simplified;
526 
527   StorageUniquer &uniquer = getContext()->getAffineUniquer();
528   return uniquer.get<AffineBinaryOpExprStorage>(
529       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::CeilDiv), *this,
530       other);
531 }
532 
533 static AffineExpr simplifyMod(AffineExpr lhs, AffineExpr rhs) {
534   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
535   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
536 
537   // mod w.r.t zero or negative numbers is undefined and preserved as is.
538   if (!rhsConst || rhsConst.getValue() < 1)
539     return nullptr;
540 
541   if (lhsConst)
542     return getAffineConstantExpr(mod(lhsConst.getValue(), rhsConst.getValue()),
543                                  lhs.getContext());
544 
545   // Fold modulo of an expression that is known to be a multiple of a constant
546   // to zero if that constant is a multiple of the modulo factor. Eg: (i * 128)
547   // mod 64 is folded to 0, and less trivially, (i*(j*4*(k*32))) mod 128 = 0.
548   if (lhs.getLargestKnownDivisor() % rhsConst.getValue() == 0)
549     return getAffineConstantExpr(0, lhs.getContext());
550 
551   // Simplify (expr1 + expr2) mod divConst when either expr1 or expr2 is
552   // known to be a multiple of divConst.
553   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
554   if (lBin && lBin.getKind() == AffineExprKind::Add) {
555     int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
556     int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
557     // rhsConst is known to be a positive constant.
558     if (llhsDiv % rhsConst.getValue() == 0)
559       return lBin.getRHS() % rhsConst.getValue();
560     if (lrhsDiv % rhsConst.getValue() == 0)
561       return lBin.getLHS() % rhsConst.getValue();
562   }
563 
564   return nullptr;
565 }
566 
567 AffineExpr AffineExpr::operator%(uint64_t v) const {
568   return *this % getAffineConstantExpr(v, getContext());
569 }
570 AffineExpr AffineExpr::operator%(AffineExpr other) const {
571   if (auto simplified = simplifyMod(*this, other))
572     return simplified;
573 
574   StorageUniquer &uniquer = getContext()->getAffineUniquer();
575   return uniquer.get<AffineBinaryOpExprStorage>(
576       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::Mod), *this, other);
577 }
578 
579 AffineExpr AffineExpr::compose(AffineMap map) const {
580   SmallVector<AffineExpr, 8> dimReplacements(map.getResults().begin(),
581                                              map.getResults().end());
582   return replaceDimsAndSymbols(dimReplacements, {});
583 }
584 raw_ostream &mlir::operator<<(raw_ostream &os, AffineExpr &expr) {
585   expr.print(os);
586   return os;
587 }
588 
589 /// Constructs an affine expression from a flat ArrayRef. If there are local
590 /// identifiers (neither dimensional nor symbolic) that appear in the sum of
591 /// products expression, `localExprs` is expected to have the AffineExpr
592 /// for it, and is substituted into. The ArrayRef `flatExprs` is expected to be
593 /// in the format [dims, symbols, locals, constant term].
594 AffineExpr mlir::getAffineExprFromFlatForm(ArrayRef<int64_t> flatExprs,
595                                            unsigned numDims,
596                                            unsigned numSymbols,
597                                            ArrayRef<AffineExpr> localExprs,
598                                            MLIRContext *context) {
599   // Assert expected numLocals = flatExprs.size() - numDims - numSymbols - 1.
600   assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
601          "unexpected number of local expressions");
602 
603   auto expr = getAffineConstantExpr(0, context);
604   // Dimensions and symbols.
605   for (unsigned j = 0; j < numDims + numSymbols; j++) {
606     if (flatExprs[j] == 0)
607       continue;
608     auto id = j < numDims ? getAffineDimExpr(j, context)
609                           : getAffineSymbolExpr(j - numDims, context);
610     expr = expr + id * flatExprs[j];
611   }
612 
613   // Local identifiers.
614   for (unsigned j = numDims + numSymbols, e = flatExprs.size() - 1; j < e;
615        j++) {
616     if (flatExprs[j] == 0)
617       continue;
618     auto term = localExprs[j - numDims - numSymbols] * flatExprs[j];
619     expr = expr + term;
620   }
621 
622   // Constant term.
623   int64_t constTerm = flatExprs[flatExprs.size() - 1];
624   if (constTerm != 0)
625     expr = expr + constTerm;
626   return expr;
627 }
628 
629 SimpleAffineExprFlattener::SimpleAffineExprFlattener(unsigned numDims,
630                                                      unsigned numSymbols)
631     : numDims(numDims), numSymbols(numSymbols), numLocals(0) {
632   operandExprStack.reserve(8);
633 }
634 
635 void SimpleAffineExprFlattener::visitMulExpr(AffineBinaryOpExpr expr) {
636   assert(operandExprStack.size() >= 2);
637   // This is a pure affine expr; the RHS will be a constant.
638   assert(expr.getRHS().isa<AffineConstantExpr>());
639   // Get the RHS constant.
640   auto rhsConst = operandExprStack.back()[getConstantIndex()];
641   operandExprStack.pop_back();
642   // Update the LHS in place instead of pop and push.
643   auto &lhs = operandExprStack.back();
644   for (unsigned i = 0, e = lhs.size(); i < e; i++) {
645     lhs[i] *= rhsConst;
646   }
647 }
648 
649 void SimpleAffineExprFlattener::visitAddExpr(AffineBinaryOpExpr expr) {
650   assert(operandExprStack.size() >= 2);
651   const auto &rhs = operandExprStack.back();
652   auto &lhs = operandExprStack[operandExprStack.size() - 2];
653   assert(lhs.size() == rhs.size());
654   // Update the LHS in place.
655   for (unsigned i = 0, e = rhs.size(); i < e; i++) {
656     lhs[i] += rhs[i];
657   }
658   // Pop off the RHS.
659   operandExprStack.pop_back();
660 }
661 
662 //
663 // t = expr mod c   <=>  t = expr - c*q and c*q <= expr <= c*q + c - 1
664 //
665 // A mod expression "expr mod c" is thus flattened by introducing a new local
666 // variable q (= expr floordiv c), such that expr mod c is replaced with
667 // 'expr - c * q' and c * q <= expr <= c * q + c - 1 are added to localVarCst.
668 void SimpleAffineExprFlattener::visitModExpr(AffineBinaryOpExpr expr) {
669   assert(operandExprStack.size() >= 2);
670   // This is a pure affine expr; the RHS will be a constant.
671   assert(expr.getRHS().isa<AffineConstantExpr>());
672   auto rhsConst = operandExprStack.back()[getConstantIndex()];
673   operandExprStack.pop_back();
674   auto &lhs = operandExprStack.back();
675   // TODO(bondhugula): handle modulo by zero case when this issue is fixed
676   // at the other places in the IR.
677   assert(rhsConst > 0 && "RHS constant has to be positive");
678 
679   // Check if the LHS expression is a multiple of modulo factor.
680   unsigned i, e;
681   for (i = 0, e = lhs.size(); i < e; i++)
682     if (lhs[i] % rhsConst != 0)
683       break;
684   // If yes, modulo expression here simplifies to zero.
685   if (i == lhs.size()) {
686     std::fill(lhs.begin(), lhs.end(), 0);
687     return;
688   }
689 
690   // Add a local variable for the quotient, i.e., expr % c is replaced by
691   // (expr - q * c) where q = expr floordiv c. Do this while canceling out
692   // the GCD of expr and c.
693   SmallVector<int64_t, 8> floorDividend(lhs);
694   uint64_t gcd = rhsConst;
695   for (unsigned i = 0, e = lhs.size(); i < e; i++)
696     gcd = llvm::GreatestCommonDivisor64(gcd, std::abs(lhs[i]));
697   // Simplify the numerator and the denominator.
698   if (gcd != 1) {
699     for (unsigned i = 0, e = floorDividend.size(); i < e; i++)
700       floorDividend[i] = floorDividend[i] / static_cast<int64_t>(gcd);
701   }
702   int64_t floorDivisor = rhsConst / static_cast<int64_t>(gcd);
703 
704   // Construct the AffineExpr form of the floordiv to store in localExprs.
705   MLIRContext *context = expr.getContext();
706   auto dividendExpr = getAffineExprFromFlatForm(
707       floorDividend, numDims, numSymbols, localExprs, context);
708   auto divisorExpr = getAffineConstantExpr(floorDivisor, context);
709   auto floorDivExpr = dividendExpr.floorDiv(divisorExpr);
710   int loc;
711   if ((loc = findLocalId(floorDivExpr)) == -1) {
712     addLocalFloorDivId(floorDividend, floorDivisor, floorDivExpr);
713     // Set result at top of stack to "lhs - rhsConst * q".
714     lhs[getLocalVarStartIndex() + numLocals - 1] = -rhsConst;
715   } else {
716     // Reuse the existing local id.
717     lhs[getLocalVarStartIndex() + loc] = -rhsConst;
718   }
719 }
720 
721 void SimpleAffineExprFlattener::visitCeilDivExpr(AffineBinaryOpExpr expr) {
722   visitDivExpr(expr, /*isCeil=*/true);
723 }
724 void SimpleAffineExprFlattener::visitFloorDivExpr(AffineBinaryOpExpr expr) {
725   visitDivExpr(expr, /*isCeil=*/false);
726 }
727 
728 void SimpleAffineExprFlattener::visitDimExpr(AffineDimExpr expr) {
729   operandExprStack.emplace_back(SmallVector<int64_t, 32>(getNumCols(), 0));
730   auto &eq = operandExprStack.back();
731   assert(expr.getPosition() < numDims && "Inconsistent number of dims");
732   eq[getDimStartIndex() + expr.getPosition()] = 1;
733 }
734 
735 void SimpleAffineExprFlattener::visitSymbolExpr(AffineSymbolExpr expr) {
736   operandExprStack.emplace_back(SmallVector<int64_t, 32>(getNumCols(), 0));
737   auto &eq = operandExprStack.back();
738   assert(expr.getPosition() < numSymbols && "inconsistent number of symbols");
739   eq[getSymbolStartIndex() + expr.getPosition()] = 1;
740 }
741 
742 void SimpleAffineExprFlattener::visitConstantExpr(AffineConstantExpr expr) {
743   operandExprStack.emplace_back(SmallVector<int64_t, 32>(getNumCols(), 0));
744   auto &eq = operandExprStack.back();
745   eq[getConstantIndex()] = expr.getValue();
746 }
747 
748 // t = expr floordiv c   <=> t = q, c * q <= expr <= c * q + c - 1
749 // A floordiv is thus flattened by introducing a new local variable q, and
750 // replacing that expression with 'q' while adding the constraints
751 // c * q <= expr <= c * q + c - 1 to localVarCst (done by
752 // FlatAffineConstraints::addLocalFloorDiv).
753 //
754 // A ceildiv is similarly flattened:
755 // t = expr ceildiv c   <=> t =  (expr + c - 1) floordiv c
756 void SimpleAffineExprFlattener::visitDivExpr(AffineBinaryOpExpr expr,
757                                              bool isCeil) {
758   assert(operandExprStack.size() >= 2);
759   assert(expr.getRHS().isa<AffineConstantExpr>());
760 
761   // This is a pure affine expr; the RHS is a positive constant.
762   int64_t rhsConst = operandExprStack.back()[getConstantIndex()];
763   // TODO(bondhugula): handle division by zero at the same time the issue is
764   // fixed at other places.
765   assert(rhsConst > 0 && "RHS constant has to be positive");
766   operandExprStack.pop_back();
767   auto &lhs = operandExprStack.back();
768 
769   // Simplify the floordiv, ceildiv if possible by canceling out the greatest
770   // common divisors of the numerator and denominator.
771   uint64_t gcd = std::abs(rhsConst);
772   for (unsigned i = 0, e = lhs.size(); i < e; i++)
773     gcd = llvm::GreatestCommonDivisor64(gcd, std::abs(lhs[i]));
774   // Simplify the numerator and the denominator.
775   if (gcd != 1) {
776     for (unsigned i = 0, e = lhs.size(); i < e; i++)
777       lhs[i] = lhs[i] / static_cast<int64_t>(gcd);
778   }
779   int64_t divisor = rhsConst / static_cast<int64_t>(gcd);
780   // If the divisor becomes 1, the updated LHS is the result. (The
781   // divisor can't be negative since rhsConst is positive).
782   if (divisor == 1)
783     return;
784 
785   // If the divisor cannot be simplified to one, we will have to retain
786   // the ceil/floor expr (simplified up until here). Add an existential
787   // quantifier to express its result, i.e., expr1 div expr2 is replaced
788   // by a new identifier, q.
789   MLIRContext *context = expr.getContext();
790   auto a =
791       getAffineExprFromFlatForm(lhs, numDims, numSymbols, localExprs, context);
792   auto b = getAffineConstantExpr(divisor, context);
793 
794   int loc;
795   auto divExpr = isCeil ? a.ceilDiv(b) : a.floorDiv(b);
796   if ((loc = findLocalId(divExpr)) == -1) {
797     if (!isCeil) {
798       SmallVector<int64_t, 8> dividend(lhs);
799       addLocalFloorDivId(dividend, divisor, divExpr);
800     } else {
801       // lhs ceildiv c <=>  (lhs + c - 1) floordiv c
802       SmallVector<int64_t, 8> dividend(lhs);
803       dividend.back() += divisor - 1;
804       addLocalFloorDivId(dividend, divisor, divExpr);
805     }
806   }
807   // Set the expression on stack to the local var introduced to capture the
808   // result of the division (floor or ceil).
809   std::fill(lhs.begin(), lhs.end(), 0);
810   if (loc == -1)
811     lhs[getLocalVarStartIndex() + numLocals - 1] = 1;
812   else
813     lhs[getLocalVarStartIndex() + loc] = 1;
814 }
815 
816 // Add a local identifier (needed to flatten a mod, floordiv, ceildiv expr).
817 // The local identifier added is always a floordiv of a pure add/mul affine
818 // function of other identifiers, coefficients of which are specified in
819 // dividend and with respect to a positive constant divisor. localExpr is the
820 // simplified tree expression (AffineExpr) corresponding to the quantifier.
821 void SimpleAffineExprFlattener::addLocalFloorDivId(ArrayRef<int64_t> dividend,
822                                                    int64_t divisor,
823                                                    AffineExpr localExpr) {
824   assert(divisor > 0 && "positive constant divisor expected");
825   for (auto &subExpr : operandExprStack)
826     subExpr.insert(subExpr.begin() + getLocalVarStartIndex() + numLocals, 0);
827   localExprs.push_back(localExpr);
828   numLocals++;
829   // dividend and divisor are not used here; an override of this method uses it.
830 }
831 
832 int SimpleAffineExprFlattener::findLocalId(AffineExpr localExpr) {
833   SmallVectorImpl<AffineExpr>::iterator it;
834   if ((it = llvm::find(localExprs, localExpr)) == localExprs.end())
835     return -1;
836   return it - localExprs.begin();
837 }
838 
839 /// Simplify the affine expression by flattening it and reconstructing it.
840 AffineExpr mlir::simplifyAffineExpr(AffineExpr expr, unsigned numDims,
841                                     unsigned numSymbols) {
842   // TODO(bondhugula): only pure affine for now. The simplification here can
843   // be extended to semi-affine maps in the future.
844   if (!expr.isPureAffine())
845     return expr;
846 
847   SimpleAffineExprFlattener flattener(numDims, numSymbols);
848   flattener.walkPostOrder(expr);
849   ArrayRef<int64_t> flattenedExpr = flattener.operandExprStack.back();
850   auto simplifiedExpr =
851       getAffineExprFromFlatForm(flattenedExpr, numDims, numSymbols,
852                                 flattener.localExprs, expr.getContext());
853   flattener.operandExprStack.pop_back();
854   assert(flattener.operandExprStack.empty());
855 
856   return simplifiedExpr;
857 }
858