blob: 4bd224de732700a3fa7f6ed373875fb7b9d08c5d [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
Uday Bondhugula970f5b82018-08-01 22:02:00 -070030/// Simplify add expression. Return nullptr if it can't be simplified.
Uday Bondhugulae082aad2018-07-11 21:19:31 -070031AffineExpr *AffineBinaryOpExpr::simplifyAdd(AffineExpr *lhs, AffineExpr *rhs,
32 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -070033 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
34 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
Uday Bondhugulae082aad2018-07-11 21:19:31 -070035
Uday Bondhugula970f5b82018-08-01 22:02:00 -070036 // Fold if both LHS, RHS are a constant.
37 if (lhsConst && rhsConst)
38 return AffineConstantExpr::get(lhsConst->getValue() + rhsConst->getValue(),
39 context);
40
41 // Canonicalize so that only the RHS is a constant. (4 + d0 becomes d0 + 4).
42 // If only one of them is a symbolic expressions, make it the RHS.
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070043 if (isa<AffineConstantExpr>(lhs) ||
Uday Bondhugula970f5b82018-08-01 22:02:00 -070044 (lhs->isSymbolicOrConstant() && !rhs->isSymbolicOrConstant())) {
Uday Bondhugulac1faf662018-07-19 14:08:50 -070045 return AffineBinaryOpExpr::get(Kind::Add, rhs, lhs, context);
Uday Bondhugula970f5b82018-08-01 22:02:00 -070046 }
47
48 // At this point, if there was a constant, it would be on the right.
49
50 // Addition with a zero is a noop, return the other input.
51 if (rhsConst) {
52 if (rhsConst->getValue() == 0)
53 return lhs;
54 }
55 // Fold successive additions like (d0 + 2) + 3 into d0 + 5.
56 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
57 if (lBin && rhsConst && lBin->getKind() == Kind::Add) {
58 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
59 return AffineBinaryOpExpr::get(
60 Kind::Add, lBin->getLHS(),
61 AffineConstantExpr::get(lrhs->getValue() + rhsConst->getValue(),
62 context),
63 context);
64 }
65
66 // When doing successive additions, bring constant to the right: turn (d0 + 2)
67 // + d1 into (d0 + d1) + 2.
68 if (lBin && lBin->getKind() == Kind::Add) {
69 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
70 return AffineBinaryOpExpr::get(
71 Kind::Add,
72 AffineBinaryOpExpr::get(Kind::Add, lBin->getLHS(), rhs, context),
73 lrhs, context);
74 }
75 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -070076
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070077 return nullptr;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070078}
79
Uday Bondhugula970f5b82018-08-01 22:02:00 -070080/// Simplify a multiply expression. Return nullptr if it can't be simplified.
Uday Bondhugulae082aad2018-07-11 21:19:31 -070081AffineExpr *AffineBinaryOpExpr::simplifyMul(AffineExpr *lhs, AffineExpr *rhs,
82 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -070083 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
84 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
85
86 if (lhsConst && rhsConst)
87 return AffineConstantExpr::get(lhsConst->getValue() * rhsConst->getValue(),
88 context);
Uday Bondhugulae082aad2018-07-11 21:19:31 -070089
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070090 assert(lhs->isSymbolicOrConstant() || rhs->isSymbolicOrConstant());
Uday Bondhugulae082aad2018-07-11 21:19:31 -070091
92 // Canonicalize the mul expression so that the constant/symbolic term is the
93 // RHS. If both the lhs and rhs are symbolic, swap them if the lhs is a
94 // constant. (Note that a constant is trivially symbolic).
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070095 if (!rhs->isSymbolicOrConstant() || isa<AffineConstantExpr>(lhs)) {
Uday Bondhugulae082aad2018-07-11 21:19:31 -070096 // At least one of them has to be symbolic.
Uday Bondhugulac1faf662018-07-19 14:08:50 -070097 return AffineBinaryOpExpr::get(Kind::Mul, rhs, lhs, context);
Uday Bondhugulae082aad2018-07-11 21:19:31 -070098 }
99
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700100 // At this point, if there was a constant, it would be on the right.
101
102 // Multiplication with a one is a noop, return the other input.
103 if (rhsConst) {
104 if (rhsConst->getValue() == 1)
105 return lhs;
106 // Multiplication with zero.
107 if (rhsConst->getValue() == 0)
108 return rhsConst;
109 }
110
111 // Fold successive multiplications: eg: (d0 * 2) * 3 into d0 * 6.
112 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
113 if (lBin && rhsConst && lBin->getKind() == Kind::Mul) {
114 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
115 return AffineBinaryOpExpr::get(
116 Kind::Mul, lBin->getLHS(),
117 AffineConstantExpr::get(lrhs->getValue() * rhsConst->getValue(),
118 context),
119 context);
120 }
121
122 // When doing successive multiplication, bring constant to the right: turn (d0
123 // * 2) * d1 into (d0 * d1) * 2.
124 if (lBin && lBin->getKind() == Kind::Mul) {
125 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
126 return AffineBinaryOpExpr::get(
127 Kind::Mul,
128 AffineBinaryOpExpr::get(Kind::Mul, lBin->getLHS(), rhs, context),
129 lrhs, context);
130 }
131 }
132
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700133 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700134}
135
136AffineExpr *AffineBinaryOpExpr::simplifyFloorDiv(AffineExpr *lhs,
137 AffineExpr *rhs,
138 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700139 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
140 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
141
142 if (lhsConst && rhsConst)
143 return AffineConstantExpr::get(lhsConst->getValue() / rhsConst->getValue(),
144 context);
145
146 // Fold floordiv of a multiply with a constant that is a multiple of the
147 // divisor. Eg: (i * 128) floordiv 64 = i * 2.
148 if (rhsConst) {
149 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
150 if (lBin && lBin->getKind() == Kind::Mul) {
151 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
152 // rhsConst is known to be positive if a constant.
153 if (lrhs->getValue() % rhsConst->getValue() == 0)
154 return AffineBinaryOpExpr::get(
155 Kind::Mul, lBin->getLHS(),
156 AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
157 context),
158 context);
159 }
160 }
161 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700162
163 return nullptr;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700164}
165
166AffineExpr *AffineBinaryOpExpr::simplifyCeilDiv(AffineExpr *lhs,
167 AffineExpr *rhs,
168 MLIRContext *context) {
Uday Bondhugula970f5b82018-08-01 22:02:00 -0700169 auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
170 auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
171
172 if (lhsConst && rhsConst)
173 return AffineConstantExpr::get(
174 (int64_t)llvm::divideCeil((uint64_t)lhsConst->getValue(),
175 (uint64_t)rhsConst->getValue()),
176 context);
177
178 // Fold ceildiv of a multiply with a constant that is a multiple of the
179 // divisor. Eg: (i * 128) ceildiv 64 = i * 2.
180 if (rhsConst) {
181 auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
182 if (lBin && lBin->getKind() == Kind::Mul) {
183 if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
184 // rhsConst is known to be positive if a constant.
185 if (lrhs->getValue() % rhsConst->getValue() == 0)
186 return AffineBinaryOpExpr::get(
187 Kind::Mul, lBin->getLHS(),
188 AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
189 context),
190 context);
191 }
192 }
193 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700194
195 return nullptr;
196 // TODO(someone): implement more simplification along the lines described in
197 // simplifyMod TODO. For eg: 128*N ceildiv 128 is N.
198}
199
200AffineExpr *AffineBinaryOpExpr::simplifyMod(AffineExpr *lhs, AffineExpr *rhs,
201 MLIRContext *context) {
202 if (auto *l = dyn_cast<AffineConstantExpr>(lhs))
203 if (auto *r = dyn_cast<AffineConstantExpr>(rhs))
204 return AffineConstantExpr::get(l->getValue() % r->getValue(), context);
205
206 return nullptr;
207 // TODO(someone): implement more simplification; for eg: 2*x mod 2 is 0; (2*x
208 // + 1) mod 2 is 1. In general, this can be simplified by using the GCD test
209 // iteratively if the RHS of the mod is a small number, or in general using
210 // quantifier elimination (add two new variables q and r, and eliminate all
211 // variables from the linear system other than r.
212}