blob: 8dc0d1f72a51629e0071bae66098b3cba101e2b6 [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();
34 for (unsigned i = 0; i < getNumDims(); ++i) {
35 auto *expr = results[i];
36 if (!isa<AffineDimExpr>(expr) ||
37 cast<AffineDimExpr>(expr)->getPosition() != i)
38 return false;
39 }
40 return true;
41}
42
Uday Bondhugula970f5b82018-08-01 22:02:00 -070043/// Simplify add expression. Return nullptr if it can't be simplified.
Uday Bondhugulae082aad2018-07-11 21:19:31 -070044AffineExpr *AffineBinaryOpExpr::simplifyAdd(AffineExpr *lhs, AffineExpr *rhs,
45 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -070046 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
47 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
Uday Bondhugulae082aad2018-07-11 21:19:31 -070048
Uday Bondhugula970f5b82018-08-01 22:02:00 -070049 // Fold if both LHS, RHS are a constant.
50 if (lhsConst && rhsConst)
51 return AffineConstantExpr::get(lhsConst->getValue() + rhsConst->getValue(),
52 context);
53
54 // Canonicalize so that only the RHS is a constant. (4 + d0 becomes d0 + 4).
55 // If only one of them is a symbolic expressions, make it the RHS.
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070056 if (isa<AffineConstantExpr>(lhs) ||
Uday Bondhugula970f5b82018-08-01 22:02:00 -070057 (lhs->isSymbolicOrConstant() && !rhs->isSymbolicOrConstant())) {
Uday Bondhugulac1faf662018-07-19 14:08:50 -070058 return AffineBinaryOpExpr::get(Kind::Add, rhs, lhs, context);
Uday Bondhugula970f5b82018-08-01 22:02:00 -070059 }
60
61 // At this point, if there was a constant, it would be on the right.
62
63 // Addition with a zero is a noop, return the other input.
64 if (rhsConst) {
65 if (rhsConst->getValue() == 0)
66 return lhs;
67 }
68 // Fold successive additions like (d0 + 2) + 3 into d0 + 5.
69 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
70 if (lBin && rhsConst && lBin->getKind() == Kind::Add) {
71 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
72 return AffineBinaryOpExpr::get(
73 Kind::Add, lBin->getLHS(),
74 AffineConstantExpr::get(lrhs->getValue() + rhsConst->getValue(),
75 context),
76 context);
77 }
78
79 // When doing successive additions, bring constant to the right: turn (d0 + 2)
80 // + d1 into (d0 + d1) + 2.
81 if (lBin && lBin->getKind() == Kind::Add) {
82 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
83 return AffineBinaryOpExpr::get(
84 Kind::Add,
85 AffineBinaryOpExpr::get(Kind::Add, lBin->getLHS(), rhs, context),
86 lrhs, context);
87 }
88 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -070089
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070090 return nullptr;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070091}
92
Uday Bondhugula970f5b82018-08-01 22:02:00 -070093/// Simplify a multiply expression. Return nullptr if it can't be simplified.
Uday Bondhugulae082aad2018-07-11 21:19:31 -070094AffineExpr *AffineBinaryOpExpr::simplifyMul(AffineExpr *lhs, AffineExpr *rhs,
95 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -070096 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
97 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
98
99 if (lhsConst && rhsConst)
100 return AffineConstantExpr::get(lhsConst->getValue() * rhsConst->getValue(),
101 context);
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700102
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -0700103 assert(lhs->isSymbolicOrConstant() || rhs->isSymbolicOrConstant());
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700104
105 // Canonicalize the mul expression so that the constant/symbolic term is the
106 // RHS. If both the lhs and rhs are symbolic, swap them if the lhs is a
107 // constant. (Note that a constant is trivially symbolic).
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -0700108 if (!rhs->isSymbolicOrConstant() || isa<AffineConstantExpr>(lhs)) {
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700109 // At least one of them has to be symbolic.
Uday Bondhugulac1faf662018-07-19 14:08:50 -0700110 return AffineBinaryOpExpr::get(Kind::Mul, rhs, lhs, context);
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700111 }
112
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700113 // At this point, if there was a constant, it would be on the right.
114
115 // Multiplication with a one is a noop, return the other input.
116 if (rhsConst) {
117 if (rhsConst->getValue() == 1)
118 return lhs;
119 // Multiplication with zero.
120 if (rhsConst->getValue() == 0)
121 return rhsConst;
122 }
123
124 // Fold successive multiplications: eg: (d0 * 2) * 3 into d0 * 6.
125 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
126 if (lBin && rhsConst && lBin->getKind() == Kind::Mul) {
127 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
128 return AffineBinaryOpExpr::get(
129 Kind::Mul, lBin->getLHS(),
130 AffineConstantExpr::get(lrhs->getValue() * rhsConst->getValue(),
131 context),
132 context);
133 }
134
135 // When doing successive multiplication, bring constant to the right: turn (d0
136 // * 2) * d1 into (d0 * d1) * 2.
137 if (lBin && lBin->getKind() == Kind::Mul) {
138 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
139 return AffineBinaryOpExpr::get(
140 Kind::Mul,
141 AffineBinaryOpExpr::get(Kind::Mul, lBin->getLHS(), rhs, context),
142 lrhs, context);
143 }
144 }
145
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700146 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700147}
148
149AffineExpr *AffineBinaryOpExpr::simplifyFloorDiv(AffineExpr *lhs,
150 AffineExpr *rhs,
151 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700152 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
153 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
154
155 if (lhsConst && rhsConst)
156 return AffineConstantExpr::get(lhsConst->getValue() / rhsConst->getValue(),
157 context);
158
159 // Fold floordiv of a multiply with a constant that is a multiple of the
160 // divisor. Eg: (i * 128) floordiv 64 = i * 2.
161 if (rhsConst) {
162 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
163 if (lBin && lBin->getKind() == Kind::Mul) {
164 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
165 // rhsConst is known to be positive if a constant.
166 if (lrhs->getValue() % rhsConst->getValue() == 0)
167 return AffineBinaryOpExpr::get(
168 Kind::Mul, lBin->getLHS(),
169 AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
170 context),
171 context);
172 }
173 }
174 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700175
176 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700177}
178
179AffineExpr *AffineBinaryOpExpr::simplifyCeilDiv(AffineExpr *lhs,
180 AffineExpr *rhs,
181 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700182 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
183 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
184
185 if (lhsConst && rhsConst)
186 return AffineConstantExpr::get(
187 (int64_t)llvm::divideCeil((uint64_t)lhsConst->getValue(),
188 (uint64_t)rhsConst->getValue()),
189 context);
190
191 // Fold ceildiv of a multiply with a constant that is a multiple of the
192 // divisor. Eg: (i * 128) ceildiv 64 = i * 2.
193 if (rhsConst) {
194 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
195 if (lBin && lBin->getKind() == Kind::Mul) {
196 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
197 // rhsConst is known to be positive if a constant.
198 if (lrhs->getValue() % rhsConst->getValue() == 0)
199 return AffineBinaryOpExpr::get(
200 Kind::Mul, lBin->getLHS(),
201 AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
202 context),
203 context);
204 }
205 }
206 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700207
208 return nullptr;
209 // TODO(someone): implement more simplification along the lines described in
210 // simplifyMod TODO. For eg: 128*N ceildiv 128 is N.
211}
212
213AffineExpr *AffineBinaryOpExpr::simplifyMod(AffineExpr *lhs, AffineExpr *rhs,
214 MLIRContext *context) {
215 if (auto *l = dyn_cast<AffineConstantExpr>(lhs))
216 if (auto *r = dyn_cast<AffineConstantExpr>(rhs))
217 return AffineConstantExpr::get(l->getValue() % r->getValue(), context);
218
219 return nullptr;
220 // TODO(someone): implement more simplification; for eg: 2*x mod 2 is 0; (2*x
221 // + 1) mod 2 is 1. In general, this can be simplified by using the GCD test
222 // iteratively if the RHS of the mod is a small number, or in general using
223 // quantifier elimination (add two new variables q and r, and eliminate all
224 // variables from the linear system other than r.
225}