blob: afa35ba3770ff92335c2c9494007334f64873d69 [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
Tatiana Shpeismande8829f2018-08-24 23:38:14 -070042bool AffineMap::isSingleConstant() const {
43 return getNumResults() == 1 && isa<AffineConstantExpr>(getResult(0));
44}
45
Uday Bondhugulad3004002018-09-11 16:29:24 -070046int64_t AffineMap::getSingleConstantResult() const {
Tatiana Shpeismande8829f2018-08-24 23:38:14 -070047 assert(isSingleConstant() && "map must have a single constant result");
Uday Bondhugulad3004002018-09-11 16:29:24 -070048 return cast<AffineConstantExpr>(getResult(0))->getValue();
Tatiana Shpeismande8829f2018-08-24 23:38:14 -070049}
50
Uday Bondhugula970f5b82018-08-01 22:02:00 -070051/// Simplify add expression. Return nullptr if it can't be simplified.
Uday Bondhugulae082aad2018-07-11 21:19:31 -070052AffineExpr *AffineBinaryOpExpr::simplifyAdd(AffineExpr *lhs, AffineExpr *rhs,
53 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -070054 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
55 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
Uday Bondhugulae082aad2018-07-11 21:19:31 -070056
Uday Bondhugula970f5b82018-08-01 22:02:00 -070057 // Fold if both LHS, RHS are a constant.
58 if (lhsConst && rhsConst)
59 return AffineConstantExpr::get(lhsConst->getValue() + rhsConst->getValue(),
60 context);
61
62 // Canonicalize so that only the RHS is a constant. (4 + d0 becomes d0 + 4).
63 // If only one of them is a symbolic expressions, make it the RHS.
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070064 if (isa<AffineConstantExpr>(lhs) ||
Uday Bondhugula970f5b82018-08-01 22:02:00 -070065 (lhs->isSymbolicOrConstant() && !rhs->isSymbolicOrConstant())) {
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -070066 return AffineBinaryOpExpr::getAdd(rhs, lhs, context);
Uday Bondhugula970f5b82018-08-01 22:02:00 -070067 }
68
69 // At this point, if there was a constant, it would be on the right.
70
71 // Addition with a zero is a noop, return the other input.
72 if (rhsConst) {
73 if (rhsConst->getValue() == 0)
74 return lhs;
75 }
76 // Fold successive additions like (d0 + 2) + 3 into d0 + 5.
77 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
78 if (lBin && rhsConst && lBin->getKind() == Kind::Add) {
79 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -070080 return AffineBinaryOpExpr::getAdd(
81 lBin->getLHS(),
Uday Bondhugula970f5b82018-08-01 22:02:00 -070082 AffineConstantExpr::get(lrhs->getValue() + rhsConst->getValue(),
83 context),
84 context);
85 }
86
87 // When doing successive additions, bring constant to the right: turn (d0 + 2)
88 // + d1 into (d0 + d1) + 2.
89 if (lBin && lBin->getKind() == Kind::Add) {
90 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -070091 return AffineBinaryOpExpr::getAdd(
92 AffineBinaryOpExpr::getAdd(lBin->getLHS(), rhs, context), lrhs,
93 context);
Uday Bondhugula970f5b82018-08-01 22:02:00 -070094 }
95 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -070096
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070097 return nullptr;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070098}
99
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700100/// Simplify a multiply expression. Return nullptr if it can't be simplified.
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700101AffineExpr *AffineBinaryOpExpr::simplifyMul(AffineExpr *lhs, AffineExpr *rhs,
102 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700103 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
104 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
105
106 if (lhsConst && rhsConst)
107 return AffineConstantExpr::get(lhsConst->getValue() * rhsConst->getValue(),
108 context);
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700109
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -0700110 assert(lhs->isSymbolicOrConstant() || rhs->isSymbolicOrConstant());
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700111
112 // Canonicalize the mul expression so that the constant/symbolic term is the
113 // RHS. If both the lhs and rhs are symbolic, swap them if the lhs is a
114 // constant. (Note that a constant is trivially symbolic).
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -0700115 if (!rhs->isSymbolicOrConstant() || isa<AffineConstantExpr>(lhs)) {
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700116 // At least one of them has to be symbolic.
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700117 return AffineBinaryOpExpr::getMul(rhs, lhs, context);
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700118 }
119
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700120 // At this point, if there was a constant, it would be on the right.
121
122 // Multiplication with a one is a noop, return the other input.
123 if (rhsConst) {
124 if (rhsConst->getValue() == 1)
125 return lhs;
126 // Multiplication with zero.
127 if (rhsConst->getValue() == 0)
128 return rhsConst;
129 }
130
131 // Fold successive multiplications: eg: (d0 * 2) * 3 into d0 * 6.
132 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
133 if (lBin && rhsConst && lBin->getKind() == Kind::Mul) {
134 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700135 return AffineBinaryOpExpr::getMul(
136 lBin->getLHS(),
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700137 AffineConstantExpr::get(lrhs->getValue() * rhsConst->getValue(),
138 context),
139 context);
140 }
141
142 // When doing successive multiplication, bring constant to the right: turn (d0
143 // * 2) * d1 into (d0 * d1) * 2.
144 if (lBin && lBin->getKind() == Kind::Mul) {
145 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700146 return AffineBinaryOpExpr::getMul(
147 AffineBinaryOpExpr::getMul(lBin->getLHS(), rhs, context), lrhs,
148 context);
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700149 }
150 }
151
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700152 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700153}
154
155AffineExpr *AffineBinaryOpExpr::simplifyFloorDiv(AffineExpr *lhs,
156 AffineExpr *rhs,
157 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700158 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
159 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
160
161 if (lhsConst && rhsConst)
162 return AffineConstantExpr::get(lhsConst->getValue() / rhsConst->getValue(),
163 context);
164
165 // Fold floordiv of a multiply with a constant that is a multiple of the
166 // divisor. Eg: (i * 128) floordiv 64 = i * 2.
167 if (rhsConst) {
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700168 if (rhsConst->getValue() == 1)
169 return lhs;
170
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700171 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
172 if (lBin && lBin->getKind() == Kind::Mul) {
173 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
174 // rhsConst is known to be positive if a constant.
175 if (lrhs->getValue() % rhsConst->getValue() == 0)
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700176 return AffineBinaryOpExpr::getMul(
177 lBin->getLHS(),
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700178 AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
179 context),
180 context);
181 }
182 }
183 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700184
185 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700186}
187
188AffineExpr *AffineBinaryOpExpr::simplifyCeilDiv(AffineExpr *lhs,
189 AffineExpr *rhs,
190 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700191 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
192 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
193
194 if (lhsConst && rhsConst)
195 return AffineConstantExpr::get(
196 (int64_t)llvm::divideCeil((uint64_t)lhsConst->getValue(),
197 (uint64_t)rhsConst->getValue()),
198 context);
199
200 // Fold ceildiv of a multiply with a constant that is a multiple of the
201 // divisor. Eg: (i * 128) ceildiv 64 = i * 2.
202 if (rhsConst) {
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700203 if (rhsConst->getValue() == 1)
204 return lhs;
205
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700206 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
207 if (lBin && lBin->getKind() == Kind::Mul) {
208 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
209 // rhsConst is known to be positive if a constant.
210 if (lrhs->getValue() % rhsConst->getValue() == 0)
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700211 return AffineBinaryOpExpr::getMul(
212 lBin->getLHS(),
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700213 AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
214 context),
215 context);
216 }
217 }
218 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700219
220 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700221}
222
223AffineExpr *AffineBinaryOpExpr::simplifyMod(AffineExpr *lhs, AffineExpr *rhs,
224 MLIRContext *context) {
Uday Bondhugula257339b2018-08-21 10:32:24 -0700225 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
226 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
227
228 if (lhsConst && rhsConst)
229 return AffineConstantExpr::get(lhsConst->getValue() % rhsConst->getValue(),
230 context);
231
Uday Bondhugula83a41c92018-08-30 17:35:15 -0700232 // Fold modulo of an expression that is known to be a multiple of a constant
233 // to zero if that constant is a multiple of the modulo factor. Eg: (i * 128)
234 // mod 64 is folded to 0, and less trivially, (i*(j*4*(k*32))) mod 128 = 0.
Uday Bondhugula257339b2018-08-21 10:32:24 -0700235 if (rhsConst) {
Uday Bondhugula83a41c92018-08-30 17:35:15 -0700236 // rhsConst is known to be positive if a constant.
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -0700237 if (lhs->getLargestKnownDivisor() % rhsConst->getValue() == 0)
Uday Bondhugula83a41c92018-08-30 17:35:15 -0700238 return AffineConstantExpr::get(0, context);
Uday Bondhugula257339b2018-08-21 10:32:24 -0700239 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700240
241 return nullptr;
Uday Bondhugula257339b2018-08-21 10:32:24 -0700242 // TODO(bondhugula): In general, this can be simplified more by using the GCD
243 // test, or in general using quantifier elimination (add two new variables q
244 // and r, and eliminate all variables from the linear system other than r. All
245 // of this can be done through mlir/Analysis/'s FlatAffineConstraints.
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700246}