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   // Detect "c1 * expr + c_2 * expr" as "(c1 + c2) * expr".
318   // c1 is rRhsConst, c2 is rLhsConst; firstExpr, secondExpr are their
319   // respective multiplicands.
320   Optional<int64_t> rLhsConst, rRhsConst;
321   AffineExpr firstExpr, secondExpr;
322   AffineConstantExpr rLhsConstExpr;
323   auto lBinOpExpr = lhs.dyn_cast<AffineBinaryOpExpr>();
324   if (lBinOpExpr && lBinOpExpr.getKind() == AffineExprKind::Mul &&
325       (rLhsConstExpr = lBinOpExpr.getRHS().dyn_cast<AffineConstantExpr>())) {
326     rLhsConst = rLhsConstExpr.getValue();
327     firstExpr = lBinOpExpr.getLHS();
328   } else {
329     rLhsConst = 1;
330     firstExpr = lhs;
331   }
332 
333   auto rBinOpExpr = rhs.dyn_cast<AffineBinaryOpExpr>();
334   AffineConstantExpr rRhsConstExpr;
335   if (rBinOpExpr && rBinOpExpr.getKind() == AffineExprKind::Mul &&
336       (rRhsConstExpr = rBinOpExpr.getRHS().dyn_cast<AffineConstantExpr>())) {
337     rRhsConst = rRhsConstExpr.getValue();
338     secondExpr = rBinOpExpr.getLHS();
339   } else {
340     rRhsConst = 1;
341     secondExpr = rhs;
342   }
343 
344   if (rLhsConst && rRhsConst && firstExpr == secondExpr)
345     return getAffineBinaryOpExpr(
346         AffineExprKind::Mul, firstExpr,
347         getAffineConstantExpr(rLhsConst.getValue() + rRhsConst.getValue(),
348                               lhs.getContext()));
349 
350   // When doing successive additions, bring constant to the right: turn (d0 + 2)
351   // + d1 into (d0 + d1) + 2.
352   if (lBin && lBin.getKind() == AffineExprKind::Add) {
353     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>()) {
354       return lBin.getLHS() + rhs + lrhs;
355     }
356   }
357 
358   // Detect and transform "expr - c * (expr floordiv c)" to "expr mod c". This
359   // leads to a much more efficient form when 'c' is a power of two, and in
360   // general a more compact and readable form.
361 
362   // Process '(expr floordiv c) * (-c)'.
363   if (!rBinOpExpr)
364     return nullptr;
365 
366   auto lrhs = rBinOpExpr.getLHS();
367   auto rrhs = rBinOpExpr.getRHS();
368 
369   // Process lrhs, which is 'expr floordiv c'.
370   AffineBinaryOpExpr lrBinOpExpr = lrhs.dyn_cast<AffineBinaryOpExpr>();
371   if (!lrBinOpExpr || lrBinOpExpr.getKind() != AffineExprKind::FloorDiv)
372     return nullptr;
373 
374   auto llrhs = lrBinOpExpr.getLHS();
375   auto rlrhs = lrBinOpExpr.getRHS();
376 
377   if (lhs == llrhs && rlrhs == -rrhs) {
378     return lhs % rlrhs;
379   }
380   return nullptr;
381 }
382 
383 AffineExpr AffineExpr::operator+(int64_t v) const {
384   return *this + getAffineConstantExpr(v, getContext());
385 }
386 AffineExpr AffineExpr::operator+(AffineExpr other) const {
387   if (auto simplified = simplifyAdd(*this, other))
388     return simplified;
389 
390   StorageUniquer &uniquer = getContext()->getAffineUniquer();
391   return uniquer.get<AffineBinaryOpExprStorage>(
392       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::Add), *this, other);
393 }
394 
395 /// Simplify a multiply expression. Return nullptr if it can't be simplified.
396 static AffineExpr simplifyMul(AffineExpr lhs, AffineExpr rhs) {
397   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
398   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
399 
400   if (lhsConst && rhsConst)
401     return getAffineConstantExpr(lhsConst.getValue() * rhsConst.getValue(),
402                                  lhs.getContext());
403 
404   assert(lhs.isSymbolicOrConstant() || rhs.isSymbolicOrConstant());
405 
406   // Canonicalize the mul expression so that the constant/symbolic term is the
407   // RHS. If both the lhs and rhs are symbolic, swap them if the lhs is a
408   // constant. (Note that a constant is trivially symbolic).
409   if (!rhs.isSymbolicOrConstant() || lhs.isa<AffineConstantExpr>()) {
410     // At least one of them has to be symbolic.
411     return rhs * lhs;
412   }
413 
414   // At this point, if there was a constant, it would be on the right.
415 
416   // Multiplication with a one is a noop, return the other input.
417   if (rhsConst) {
418     if (rhsConst.getValue() == 1)
419       return lhs;
420     // Multiplication with zero.
421     if (rhsConst.getValue() == 0)
422       return rhsConst;
423   }
424 
425   // Fold successive multiplications: eg: (d0 * 2) * 3 into d0 * 6.
426   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
427   if (lBin && rhsConst && lBin.getKind() == AffineExprKind::Mul) {
428     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>())
429       return lBin.getLHS() * (lrhs.getValue() * rhsConst.getValue());
430   }
431 
432   // When doing successive multiplication, bring constant to the right: turn (d0
433   // * 2) * d1 into (d0 * d1) * 2.
434   if (lBin && lBin.getKind() == AffineExprKind::Mul) {
435     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>()) {
436       return (lBin.getLHS() * rhs) * lrhs;
437     }
438   }
439 
440   return nullptr;
441 }
442 
443 AffineExpr AffineExpr::operator*(int64_t v) const {
444   return *this * getAffineConstantExpr(v, getContext());
445 }
446 AffineExpr AffineExpr::operator*(AffineExpr other) const {
447   if (auto simplified = simplifyMul(*this, other))
448     return simplified;
449 
450   StorageUniquer &uniquer = getContext()->getAffineUniquer();
451   return uniquer.get<AffineBinaryOpExprStorage>(
452       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::Mul), *this, other);
453 }
454 
455 // Unary minus, delegate to operator*.
456 AffineExpr AffineExpr::operator-() const {
457   return *this * getAffineConstantExpr(-1, getContext());
458 }
459 
460 // Delegate to operator+.
461 AffineExpr AffineExpr::operator-(int64_t v) const { return *this + (-v); }
462 AffineExpr AffineExpr::operator-(AffineExpr other) const {
463   return *this + (-other);
464 }
465 
466 static AffineExpr simplifyFloorDiv(AffineExpr lhs, AffineExpr rhs) {
467   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
468   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
469 
470   // mlir floordiv by zero or negative numbers is undefined and preserved as is.
471   if (!rhsConst || rhsConst.getValue() < 1)
472     return nullptr;
473 
474   if (lhsConst)
475     return getAffineConstantExpr(
476         floorDiv(lhsConst.getValue(), rhsConst.getValue()), lhs.getContext());
477 
478   // Fold floordiv of a multiply with a constant that is a multiple of the
479   // divisor. Eg: (i * 128) floordiv 64 = i * 2.
480   if (rhsConst == 1)
481     return lhs;
482 
483   // Simplify (expr * const) floordiv divConst when expr is known to be a
484   // multiple of divConst.
485   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
486   if (lBin && lBin.getKind() == AffineExprKind::Mul) {
487     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>()) {
488       // rhsConst is known to be a positive constant.
489       if (lrhs.getValue() % rhsConst.getValue() == 0)
490         return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
491     }
492   }
493 
494   // Simplify (expr1 + expr2) floordiv divConst when either expr1 or expr2 is
495   // known to be a multiple of divConst.
496   if (lBin && lBin.getKind() == AffineExprKind::Add) {
497     int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
498     int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
499     // rhsConst is known to be a positive constant.
500     if (llhsDiv % rhsConst.getValue() == 0 ||
501         lrhsDiv % rhsConst.getValue() == 0)
502       return lBin.getLHS().floorDiv(rhsConst.getValue()) +
503              lBin.getRHS().floorDiv(rhsConst.getValue());
504   }
505 
506   return nullptr;
507 }
508 
509 AffineExpr AffineExpr::floorDiv(uint64_t v) const {
510   return floorDiv(getAffineConstantExpr(v, getContext()));
511 }
512 AffineExpr AffineExpr::floorDiv(AffineExpr other) const {
513   if (auto simplified = simplifyFloorDiv(*this, other))
514     return simplified;
515 
516   StorageUniquer &uniquer = getContext()->getAffineUniquer();
517   return uniquer.get<AffineBinaryOpExprStorage>(
518       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::FloorDiv), *this,
519       other);
520 }
521 
522 static AffineExpr simplifyCeilDiv(AffineExpr lhs, AffineExpr rhs) {
523   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
524   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
525 
526   if (!rhsConst || rhsConst.getValue() < 1)
527     return nullptr;
528 
529   if (lhsConst)
530     return getAffineConstantExpr(
531         ceilDiv(lhsConst.getValue(), rhsConst.getValue()), lhs.getContext());
532 
533   // Fold ceildiv of a multiply with a constant that is a multiple of the
534   // divisor. Eg: (i * 128) ceildiv 64 = i * 2.
535   if (rhsConst.getValue() == 1)
536     return lhs;
537 
538   // Simplify (expr * const) ceildiv divConst when const is known to be a
539   // multiple of divConst.
540   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
541   if (lBin && lBin.getKind() == AffineExprKind::Mul) {
542     if (auto lrhs = lBin.getRHS().dyn_cast<AffineConstantExpr>()) {
543       // rhsConst is known to be a positive constant.
544       if (lrhs.getValue() % rhsConst.getValue() == 0)
545         return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
546     }
547   }
548 
549   return nullptr;
550 }
551 
552 AffineExpr AffineExpr::ceilDiv(uint64_t v) const {
553   return ceilDiv(getAffineConstantExpr(v, getContext()));
554 }
555 AffineExpr AffineExpr::ceilDiv(AffineExpr other) const {
556   if (auto simplified = simplifyCeilDiv(*this, other))
557     return simplified;
558 
559   StorageUniquer &uniquer = getContext()->getAffineUniquer();
560   return uniquer.get<AffineBinaryOpExprStorage>(
561       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::CeilDiv), *this,
562       other);
563 }
564 
565 static AffineExpr simplifyMod(AffineExpr lhs, AffineExpr rhs) {
566   auto lhsConst = lhs.dyn_cast<AffineConstantExpr>();
567   auto rhsConst = rhs.dyn_cast<AffineConstantExpr>();
568 
569   // mod w.r.t zero or negative numbers is undefined and preserved as is.
570   if (!rhsConst || rhsConst.getValue() < 1)
571     return nullptr;
572 
573   if (lhsConst)
574     return getAffineConstantExpr(mod(lhsConst.getValue(), rhsConst.getValue()),
575                                  lhs.getContext());
576 
577   // Fold modulo of an expression that is known to be a multiple of a constant
578   // to zero if that constant is a multiple of the modulo factor. Eg: (i * 128)
579   // mod 64 is folded to 0, and less trivially, (i*(j*4*(k*32))) mod 128 = 0.
580   if (lhs.getLargestKnownDivisor() % rhsConst.getValue() == 0)
581     return getAffineConstantExpr(0, lhs.getContext());
582 
583   // Simplify (expr1 + expr2) mod divConst when either expr1 or expr2 is
584   // known to be a multiple of divConst.
585   auto lBin = lhs.dyn_cast<AffineBinaryOpExpr>();
586   if (lBin && lBin.getKind() == AffineExprKind::Add) {
587     int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
588     int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
589     // rhsConst is known to be a positive constant.
590     if (llhsDiv % rhsConst.getValue() == 0)
591       return lBin.getRHS() % rhsConst.getValue();
592     if (lrhsDiv % rhsConst.getValue() == 0)
593       return lBin.getLHS() % rhsConst.getValue();
594   }
595 
596   return nullptr;
597 }
598 
599 AffineExpr AffineExpr::operator%(uint64_t v) const {
600   return *this % getAffineConstantExpr(v, getContext());
601 }
602 AffineExpr AffineExpr::operator%(AffineExpr other) const {
603   if (auto simplified = simplifyMod(*this, other))
604     return simplified;
605 
606   StorageUniquer &uniquer = getContext()->getAffineUniquer();
607   return uniquer.get<AffineBinaryOpExprStorage>(
608       /*initFn=*/{}, static_cast<unsigned>(AffineExprKind::Mod), *this, other);
609 }
610 
611 AffineExpr AffineExpr::compose(AffineMap map) const {
612   SmallVector<AffineExpr, 8> dimReplacements(map.getResults().begin(),
613                                              map.getResults().end());
614   return replaceDimsAndSymbols(dimReplacements, {});
615 }
616 raw_ostream &mlir::operator<<(raw_ostream &os, AffineExpr &expr) {
617   expr.print(os);
618   return os;
619 }
620 
621 /// Constructs an affine expression from a flat ArrayRef. If there are local
622 /// identifiers (neither dimensional nor symbolic) that appear in the sum of
623 /// products expression, `localExprs` is expected to have the AffineExpr
624 /// for it, and is substituted into. The ArrayRef `flatExprs` is expected to be
625 /// in the format [dims, symbols, locals, constant term].
626 AffineExpr mlir::getAffineExprFromFlatForm(ArrayRef<int64_t> flatExprs,
627                                            unsigned numDims,
628                                            unsigned numSymbols,
629                                            ArrayRef<AffineExpr> localExprs,
630                                            MLIRContext *context) {
631   // Assert expected numLocals = flatExprs.size() - numDims - numSymbols - 1.
632   assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
633          "unexpected number of local expressions");
634 
635   auto expr = getAffineConstantExpr(0, context);
636   // Dimensions and symbols.
637   for (unsigned j = 0; j < numDims + numSymbols; j++) {
638     if (flatExprs[j] == 0)
639       continue;
640     auto id = j < numDims ? getAffineDimExpr(j, context)
641                           : getAffineSymbolExpr(j - numDims, context);
642     expr = expr + id * flatExprs[j];
643   }
644 
645   // Local identifiers.
646   for (unsigned j = numDims + numSymbols, e = flatExprs.size() - 1; j < e;
647        j++) {
648     if (flatExprs[j] == 0)
649       continue;
650     auto term = localExprs[j - numDims - numSymbols] * flatExprs[j];
651     expr = expr + term;
652   }
653 
654   // Constant term.
655   int64_t constTerm = flatExprs[flatExprs.size() - 1];
656   if (constTerm != 0)
657     expr = expr + constTerm;
658   return expr;
659 }
660 
661 SimpleAffineExprFlattener::SimpleAffineExprFlattener(unsigned numDims,
662                                                      unsigned numSymbols)
663     : numDims(numDims), numSymbols(numSymbols), numLocals(0) {
664   operandExprStack.reserve(8);
665 }
666 
667 void SimpleAffineExprFlattener::visitMulExpr(AffineBinaryOpExpr expr) {
668   assert(operandExprStack.size() >= 2);
669   // This is a pure affine expr; the RHS will be a constant.
670   assert(expr.getRHS().isa<AffineConstantExpr>());
671   // Get the RHS constant.
672   auto rhsConst = operandExprStack.back()[getConstantIndex()];
673   operandExprStack.pop_back();
674   // Update the LHS in place instead of pop and push.
675   auto &lhs = operandExprStack.back();
676   for (unsigned i = 0, e = lhs.size(); i < e; i++) {
677     lhs[i] *= rhsConst;
678   }
679 }
680 
681 void SimpleAffineExprFlattener::visitAddExpr(AffineBinaryOpExpr expr) {
682   assert(operandExprStack.size() >= 2);
683   const auto &rhs = operandExprStack.back();
684   auto &lhs = operandExprStack[operandExprStack.size() - 2];
685   assert(lhs.size() == rhs.size());
686   // Update the LHS in place.
687   for (unsigned i = 0, e = rhs.size(); i < e; i++) {
688     lhs[i] += rhs[i];
689   }
690   // Pop off the RHS.
691   operandExprStack.pop_back();
692 }
693 
694 //
695 // t = expr mod c   <=>  t = expr - c*q and c*q <= expr <= c*q + c - 1
696 //
697 // A mod expression "expr mod c" is thus flattened by introducing a new local
698 // variable q (= expr floordiv c), such that expr mod c is replaced with
699 // 'expr - c * q' and c * q <= expr <= c * q + c - 1 are added to localVarCst.
700 void SimpleAffineExprFlattener::visitModExpr(AffineBinaryOpExpr expr) {
701   assert(operandExprStack.size() >= 2);
702   // This is a pure affine expr; the RHS will be a constant.
703   assert(expr.getRHS().isa<AffineConstantExpr>());
704   auto rhsConst = operandExprStack.back()[getConstantIndex()];
705   operandExprStack.pop_back();
706   auto &lhs = operandExprStack.back();
707   // TODO(bondhugula): handle modulo by zero case when this issue is fixed
708   // at the other places in the IR.
709   assert(rhsConst > 0 && "RHS constant has to be positive");
710 
711   // Check if the LHS expression is a multiple of modulo factor.
712   unsigned i, e;
713   for (i = 0, e = lhs.size(); i < e; i++)
714     if (lhs[i] % rhsConst != 0)
715       break;
716   // If yes, modulo expression here simplifies to zero.
717   if (i == lhs.size()) {
718     std::fill(lhs.begin(), lhs.end(), 0);
719     return;
720   }
721 
722   // Add a local variable for the quotient, i.e., expr % c is replaced by
723   // (expr - q * c) where q = expr floordiv c. Do this while canceling out
724   // the GCD of expr and c.
725   SmallVector<int64_t, 8> floorDividend(lhs);
726   uint64_t gcd = rhsConst;
727   for (unsigned i = 0, e = lhs.size(); i < e; i++)
728     gcd = llvm::GreatestCommonDivisor64(gcd, std::abs(lhs[i]));
729   // Simplify the numerator and the denominator.
730   if (gcd != 1) {
731     for (unsigned i = 0, e = floorDividend.size(); i < e; i++)
732       floorDividend[i] = floorDividend[i] / static_cast<int64_t>(gcd);
733   }
734   int64_t floorDivisor = rhsConst / static_cast<int64_t>(gcd);
735 
736   // Construct the AffineExpr form of the floordiv to store in localExprs.
737   MLIRContext *context = expr.getContext();
738   auto dividendExpr = getAffineExprFromFlatForm(
739       floorDividend, numDims, numSymbols, localExprs, context);
740   auto divisorExpr = getAffineConstantExpr(floorDivisor, context);
741   auto floorDivExpr = dividendExpr.floorDiv(divisorExpr);
742   int loc;
743   if ((loc = findLocalId(floorDivExpr)) == -1) {
744     addLocalFloorDivId(floorDividend, floorDivisor, floorDivExpr);
745     // Set result at top of stack to "lhs - rhsConst * q".
746     lhs[getLocalVarStartIndex() + numLocals - 1] = -rhsConst;
747   } else {
748     // Reuse the existing local id.
749     lhs[getLocalVarStartIndex() + loc] = -rhsConst;
750   }
751 }
752 
753 void SimpleAffineExprFlattener::visitCeilDivExpr(AffineBinaryOpExpr expr) {
754   visitDivExpr(expr, /*isCeil=*/true);
755 }
756 void SimpleAffineExprFlattener::visitFloorDivExpr(AffineBinaryOpExpr expr) {
757   visitDivExpr(expr, /*isCeil=*/false);
758 }
759 
760 void SimpleAffineExprFlattener::visitDimExpr(AffineDimExpr expr) {
761   operandExprStack.emplace_back(SmallVector<int64_t, 32>(getNumCols(), 0));
762   auto &eq = operandExprStack.back();
763   assert(expr.getPosition() < numDims && "Inconsistent number of dims");
764   eq[getDimStartIndex() + expr.getPosition()] = 1;
765 }
766 
767 void SimpleAffineExprFlattener::visitSymbolExpr(AffineSymbolExpr expr) {
768   operandExprStack.emplace_back(SmallVector<int64_t, 32>(getNumCols(), 0));
769   auto &eq = operandExprStack.back();
770   assert(expr.getPosition() < numSymbols && "inconsistent number of symbols");
771   eq[getSymbolStartIndex() + expr.getPosition()] = 1;
772 }
773 
774 void SimpleAffineExprFlattener::visitConstantExpr(AffineConstantExpr expr) {
775   operandExprStack.emplace_back(SmallVector<int64_t, 32>(getNumCols(), 0));
776   auto &eq = operandExprStack.back();
777   eq[getConstantIndex()] = expr.getValue();
778 }
779 
780 // t = expr floordiv c   <=> t = q, c * q <= expr <= c * q + c - 1
781 // A floordiv is thus flattened by introducing a new local variable q, and
782 // replacing that expression with 'q' while adding the constraints
783 // c * q <= expr <= c * q + c - 1 to localVarCst (done by
784 // FlatAffineConstraints::addLocalFloorDiv).
785 //
786 // A ceildiv is similarly flattened:
787 // t = expr ceildiv c   <=> t =  (expr + c - 1) floordiv c
788 void SimpleAffineExprFlattener::visitDivExpr(AffineBinaryOpExpr expr,
789                                              bool isCeil) {
790   assert(operandExprStack.size() >= 2);
791   assert(expr.getRHS().isa<AffineConstantExpr>());
792 
793   // This is a pure affine expr; the RHS is a positive constant.
794   int64_t rhsConst = operandExprStack.back()[getConstantIndex()];
795   // TODO(bondhugula): handle division by zero at the same time the issue is
796   // fixed at other places.
797   assert(rhsConst > 0 && "RHS constant has to be positive");
798   operandExprStack.pop_back();
799   auto &lhs = operandExprStack.back();
800 
801   // Simplify the floordiv, ceildiv if possible by canceling out the greatest
802   // common divisors of the numerator and denominator.
803   uint64_t gcd = std::abs(rhsConst);
804   for (unsigned i = 0, e = lhs.size(); i < e; i++)
805     gcd = llvm::GreatestCommonDivisor64(gcd, std::abs(lhs[i]));
806   // Simplify the numerator and the denominator.
807   if (gcd != 1) {
808     for (unsigned i = 0, e = lhs.size(); i < e; i++)
809       lhs[i] = lhs[i] / static_cast<int64_t>(gcd);
810   }
811   int64_t divisor = rhsConst / static_cast<int64_t>(gcd);
812   // If the divisor becomes 1, the updated LHS is the result. (The
813   // divisor can't be negative since rhsConst is positive).
814   if (divisor == 1)
815     return;
816 
817   // If the divisor cannot be simplified to one, we will have to retain
818   // the ceil/floor expr (simplified up until here). Add an existential
819   // quantifier to express its result, i.e., expr1 div expr2 is replaced
820   // by a new identifier, q.
821   MLIRContext *context = expr.getContext();
822   auto a =
823       getAffineExprFromFlatForm(lhs, numDims, numSymbols, localExprs, context);
824   auto b = getAffineConstantExpr(divisor, context);
825 
826   int loc;
827   auto divExpr = isCeil ? a.ceilDiv(b) : a.floorDiv(b);
828   if ((loc = findLocalId(divExpr)) == -1) {
829     if (!isCeil) {
830       SmallVector<int64_t, 8> dividend(lhs);
831       addLocalFloorDivId(dividend, divisor, divExpr);
832     } else {
833       // lhs ceildiv c <=>  (lhs + c - 1) floordiv c
834       SmallVector<int64_t, 8> dividend(lhs);
835       dividend.back() += divisor - 1;
836       addLocalFloorDivId(dividend, divisor, divExpr);
837     }
838   }
839   // Set the expression on stack to the local var introduced to capture the
840   // result of the division (floor or ceil).
841   std::fill(lhs.begin(), lhs.end(), 0);
842   if (loc == -1)
843     lhs[getLocalVarStartIndex() + numLocals - 1] = 1;
844   else
845     lhs[getLocalVarStartIndex() + loc] = 1;
846 }
847 
848 // Add a local identifier (needed to flatten a mod, floordiv, ceildiv expr).
849 // The local identifier added is always a floordiv of a pure add/mul affine
850 // function of other identifiers, coefficients of which are specified in
851 // dividend and with respect to a positive constant divisor. localExpr is the
852 // simplified tree expression (AffineExpr) corresponding to the quantifier.
853 void SimpleAffineExprFlattener::addLocalFloorDivId(ArrayRef<int64_t> dividend,
854                                                    int64_t divisor,
855                                                    AffineExpr localExpr) {
856   assert(divisor > 0 && "positive constant divisor expected");
857   for (auto &subExpr : operandExprStack)
858     subExpr.insert(subExpr.begin() + getLocalVarStartIndex() + numLocals, 0);
859   localExprs.push_back(localExpr);
860   numLocals++;
861   // dividend and divisor are not used here; an override of this method uses it.
862 }
863 
864 int SimpleAffineExprFlattener::findLocalId(AffineExpr localExpr) {
865   SmallVectorImpl<AffineExpr>::iterator it;
866   if ((it = llvm::find(localExprs, localExpr)) == localExprs.end())
867     return -1;
868   return it - localExprs.begin();
869 }
870 
871 /// Simplify the affine expression by flattening it and reconstructing it.
872 AffineExpr mlir::simplifyAffineExpr(AffineExpr expr, unsigned numDims,
873                                     unsigned numSymbols) {
874   // TODO(bondhugula): only pure affine for now. The simplification here can
875   // be extended to semi-affine maps in the future.
876   if (!expr.isPureAffine())
877     return expr;
878 
879   SimpleAffineExprFlattener flattener(numDims, numSymbols);
880   flattener.walkPostOrder(expr);
881   ArrayRef<int64_t> flattenedExpr = flattener.operandExprStack.back();
882   auto simplifiedExpr =
883       getAffineExprFromFlatForm(flattenedExpr, numDims, numSymbols,
884                                 flattener.localExprs, expr.getContext());
885   flattener.operandExprStack.pop_back();
886   assert(flattener.operandExprStack.empty());
887 
888   return simplifiedExpr;
889 }
890