blob: 95cd8ffc527efd0ab2a9d5c5ff346b9d47c2e4c4 [file] [log] [blame]
MLIR Teamf85a6262018-06-27 11:03:08 -07001//===- AffineMap.cpp - MLIR Affine Map Classes ----------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17
18#include "mlir/IR/AffineMap.h"
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070019#include "mlir/IR/AffineExpr.h"
MLIR Teamf85a6262018-06-27 11:03:08 -070020#include "llvm/ADT/StringRef.h"
Uday Bondhugulae082aad2018-07-11 21:19:31 -070021#include "llvm/Support/MathExtras.h"
MLIR Teamf85a6262018-06-27 11:03:08 -070022
23using namespace mlir;
24
Uday Bondhugula015cbb12018-07-03 20:16:08 -070025AffineMap::AffineMap(unsigned numDims, unsigned numSymbols, unsigned numResults,
Uday Bondhugula0115dbb2018-07-11 21:31:07 -070026 AffineExpr *const *results, AffineExpr *const *rangeSizes)
Uday Bondhugula015cbb12018-07-03 20:16:08 -070027 : numDims(numDims), numSymbols(numSymbols), numResults(numResults),
Uday Bondhugula0115dbb2018-07-11 21:31:07 -070028 results(results), rangeSizes(rangeSizes) {}
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070029
MLIR Teamcfeca5f2018-08-14 12:43:51 -070030bool AffineMap::isIdentity() const {
31 if (getNumDims() != getNumResults())
32 return false;
33 ArrayRef<AffineExpr *> results = getResults();
MLIR Team04914bc2018-08-15 15:14:45 -070034 for (unsigned i = 0, numDims = getNumDims(); i < numDims; ++i) {
35 auto *expr = dyn_cast<AffineDimExpr>(results[i]);
36 if (!expr || expr->getPosition() != i)
MLIR Teamcfeca5f2018-08-14 12:43:51 -070037 return false;
38 }
39 return true;
40}
41
Uday Bondhugula970f5b82018-08-01 22:02:00 -070042/// Simplify add expression. Return nullptr if it can't be simplified.
Uday Bondhugulae082aad2018-07-11 21:19:31 -070043AffineExpr *AffineBinaryOpExpr::simplifyAdd(AffineExpr *lhs, AffineExpr *rhs,
44 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -070045 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
46 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
Uday Bondhugulae082aad2018-07-11 21:19:31 -070047
Uday Bondhugula970f5b82018-08-01 22:02:00 -070048 // Fold if both LHS, RHS are a constant.
49 if (lhsConst && rhsConst)
50 return AffineConstantExpr::get(lhsConst->getValue() + rhsConst->getValue(),
51 context);
52
53 // Canonicalize so that only the RHS is a constant. (4 + d0 becomes d0 + 4).
54 // If only one of them is a symbolic expressions, make it the RHS.
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070055 if (isa<AffineConstantExpr>(lhs) ||
Uday Bondhugula970f5b82018-08-01 22:02:00 -070056 (lhs->isSymbolicOrConstant() && !rhs->isSymbolicOrConstant())) {
Uday Bondhugulac1faf662018-07-19 14:08:50 -070057 return AffineBinaryOpExpr::get(Kind::Add, rhs, lhs, context);
Uday Bondhugula970f5b82018-08-01 22:02:00 -070058 }
59
60 // At this point, if there was a constant, it would be on the right.
61
62 // Addition with a zero is a noop, return the other input.
63 if (rhsConst) {
64 if (rhsConst->getValue() == 0)
65 return lhs;
66 }
67 // Fold successive additions like (d0 + 2) + 3 into d0 + 5.
68 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
69 if (lBin && rhsConst && lBin->getKind() == Kind::Add) {
70 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
71 return AffineBinaryOpExpr::get(
72 Kind::Add, lBin->getLHS(),
73 AffineConstantExpr::get(lrhs->getValue() + rhsConst->getValue(),
74 context),
75 context);
76 }
77
78 // When doing successive additions, bring constant to the right: turn (d0 + 2)
79 // + d1 into (d0 + d1) + 2.
80 if (lBin && lBin->getKind() == Kind::Add) {
81 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
82 return AffineBinaryOpExpr::get(
83 Kind::Add,
84 AffineBinaryOpExpr::get(Kind::Add, lBin->getLHS(), rhs, context),
85 lrhs, context);
86 }
87 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -070088
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070089 return nullptr;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070090}
91
Uday Bondhugula970f5b82018-08-01 22:02:00 -070092/// Simplify a multiply expression. Return nullptr if it can't be simplified.
Uday Bondhugulae082aad2018-07-11 21:19:31 -070093AffineExpr *AffineBinaryOpExpr::simplifyMul(AffineExpr *lhs, AffineExpr *rhs,
94 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -070095 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
96 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
97
98 if (lhsConst && rhsConst)
99 return AffineConstantExpr::get(lhsConst->getValue() * rhsConst->getValue(),
100 context);
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700101
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -0700102 assert(lhs->isSymbolicOrConstant() || rhs->isSymbolicOrConstant());
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700103
104 // Canonicalize the mul expression so that the constant/symbolic term is the
105 // RHS. If both the lhs and rhs are symbolic, swap them if the lhs is a
106 // constant. (Note that a constant is trivially symbolic).
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -0700107 if (!rhs->isSymbolicOrConstant() || isa<AffineConstantExpr>(lhs)) {
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700108 // At least one of them has to be symbolic.
Uday Bondhugulac1faf662018-07-19 14:08:50 -0700109 return AffineBinaryOpExpr::get(Kind::Mul, rhs, lhs, context);
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700110 }
111
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700112 // At this point, if there was a constant, it would be on the right.
113
114 // Multiplication with a one is a noop, return the other input.
115 if (rhsConst) {
116 if (rhsConst->getValue() == 1)
117 return lhs;
118 // Multiplication with zero.
119 if (rhsConst->getValue() == 0)
120 return rhsConst;
121 }
122
123 // Fold successive multiplications: eg: (d0 * 2) * 3 into d0 * 6.
124 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
125 if (lBin && rhsConst && lBin->getKind() == Kind::Mul) {
126 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
127 return AffineBinaryOpExpr::get(
128 Kind::Mul, lBin->getLHS(),
129 AffineConstantExpr::get(lrhs->getValue() * rhsConst->getValue(),
130 context),
131 context);
132 }
133
134 // When doing successive multiplication, bring constant to the right: turn (d0
135 // * 2) * d1 into (d0 * d1) * 2.
136 if (lBin && lBin->getKind() == Kind::Mul) {
137 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
138 return AffineBinaryOpExpr::get(
139 Kind::Mul,
140 AffineBinaryOpExpr::get(Kind::Mul, lBin->getLHS(), rhs, context),
141 lrhs, context);
142 }
143 }
144
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700145 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700146}
147
148AffineExpr *AffineBinaryOpExpr::simplifyFloorDiv(AffineExpr *lhs,
149 AffineExpr *rhs,
150 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700151 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
152 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
153
154 if (lhsConst && rhsConst)
155 return AffineConstantExpr::get(lhsConst->getValue() / rhsConst->getValue(),
156 context);
157
158 // Fold floordiv of a multiply with a constant that is a multiple of the
159 // divisor. Eg: (i * 128) floordiv 64 = i * 2.
160 if (rhsConst) {
161 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
162 if (lBin && lBin->getKind() == Kind::Mul) {
163 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
164 // rhsConst is known to be positive if a constant.
165 if (lrhs->getValue() % rhsConst->getValue() == 0)
166 return AffineBinaryOpExpr::get(
167 Kind::Mul, lBin->getLHS(),
168 AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
169 context),
170 context);
171 }
172 }
173 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700174
175 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700176}
177
178AffineExpr *AffineBinaryOpExpr::simplifyCeilDiv(AffineExpr *lhs,
179 AffineExpr *rhs,
180 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700181 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
182 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
183
184 if (lhsConst && rhsConst)
185 return AffineConstantExpr::get(
186 (int64_t)llvm::divideCeil((uint64_t)lhsConst->getValue(),
187 (uint64_t)rhsConst->getValue()),
188 context);
189
190 // Fold ceildiv of a multiply with a constant that is a multiple of the
191 // divisor. Eg: (i * 128) ceildiv 64 = i * 2.
192 if (rhsConst) {
193 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
194 if (lBin && lBin->getKind() == Kind::Mul) {
195 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
196 // rhsConst is known to be positive if a constant.
197 if (lrhs->getValue() % rhsConst->getValue() == 0)
198 return AffineBinaryOpExpr::get(
199 Kind::Mul, lBin->getLHS(),
200 AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
201 context),
202 context);
203 }
204 }
205 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700206
207 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700208}
209
210AffineExpr *AffineBinaryOpExpr::simplifyMod(AffineExpr *lhs, AffineExpr *rhs,
211 MLIRContext *context) {
Uday Bondhugula257339b2018-08-21 10:32:24 -0700212 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
213 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
214
215 if (lhsConst && rhsConst)
216 return AffineConstantExpr::get(lhsConst->getValue() % rhsConst->getValue(),
217 context);
218
219 // Fold modulo of a multiply with a constant that is a multiple of the
220 // modulo factor to zero. Eg: (i * 128) mod 64 = 0.
221 if (rhsConst) {
222 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
223 if (lBin && lBin->getKind() == Kind::Mul) {
224 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
225 // rhsConst is known to be positive if a constant.
226 if (lrhs->getValue() % rhsConst->getValue() == 0)
227 return AffineConstantExpr::get(0, context);
228 }
229 }
230 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700231
232 return nullptr;
Uday Bondhugula257339b2018-08-21 10:32:24 -0700233 // TODO(bondhugula): In general, this can be simplified more by using the GCD
234 // test, or in general using quantifier elimination (add two new variables q
235 // and r, and eliminate all variables from the linear system other than r. All
236 // of this can be done through mlir/Analysis/'s FlatAffineConstraints.
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700237}