blob: 6393b3e32e3b1dd6492032f0adec68b8a09ac747 [file] [log] [blame]
MLIR Teamf85a6262018-06-27 11:03:08 -07001//===- AffineExpr.cpp - MLIR Affine Expr 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/AffineExpr.h"
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070019#include "mlir/Support/STLExtras.h"
Uday Bondhugulae082aad2018-07-11 21:19:31 -070020#include "third_party/llvm/llvm/include/llvm/ADT/STLExtras.h"
MLIR Teamf85a6262018-06-27 11:03:08 -070021
22using namespace mlir;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070023
Uday Bondhugulae082aad2018-07-11 21:19:31 -070024AffineBinaryOpExpr::AffineBinaryOpExpr(Kind kind, AffineExpr *lhs,
25 AffineExpr *rhs)
26 : AffineExpr(kind), lhs(lhs), rhs(rhs) {
27 // We verify affine op expr forms at construction time.
28 switch (kind) {
29 case Kind::Add:
30 assert(!isa<AffineConstantExpr>(lhs));
Uday Bondhugulae082aad2018-07-11 21:19:31 -070031 break;
32 case Kind::Mul:
33 assert(!isa<AffineConstantExpr>(lhs));
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070034 assert(rhs->isSymbolicOrConstant());
Uday Bondhugulae082aad2018-07-11 21:19:31 -070035 break;
36 case Kind::FloorDiv:
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070037 assert(rhs->isSymbolicOrConstant());
Uday Bondhugulae082aad2018-07-11 21:19:31 -070038 break;
39 case Kind::CeilDiv:
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070040 assert(rhs->isSymbolicOrConstant());
Uday Bondhugulae082aad2018-07-11 21:19:31 -070041 break;
42 case Kind::Mod:
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070043 assert(rhs->isSymbolicOrConstant());
Uday Bondhugulae082aad2018-07-11 21:19:31 -070044 break;
45 default:
46 llvm_unreachable("unexpected binary affine expr");
47 }
48}
49
Chris Lattner1ac20cb2018-07-10 10:59:53 -070050/// Returns true if this expression is made out of only symbols and
51/// constants (no dimensional identifiers).
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070052bool AffineExpr::isSymbolicOrConstant() const {
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070053 switch (getKind()) {
54 case Kind::Constant:
55 return true;
56 case Kind::DimId:
57 return false;
58 case Kind::SymbolId:
59 return true;
60
61 case Kind::Add:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070062 case Kind::Mul:
63 case Kind::FloorDiv:
64 case Kind::CeilDiv:
Chris Lattner1ac20cb2018-07-10 10:59:53 -070065 case Kind::Mod: {
66 auto expr = cast<AffineBinaryOpExpr>(this);
Uday Bondhugulacbe4cca2018-07-19 13:07:16 -070067 return expr->getLHS()->isSymbolicOrConstant() &&
68 expr->getRHS()->isSymbolicOrConstant();
Chris Lattner1ac20cb2018-07-10 10:59:53 -070069 }
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070070 }
71}
72
Chris Lattner1ac20cb2018-07-10 10:59:53 -070073/// Returns true if this is a pure affine expression, i.e., multiplication,
74/// floordiv, ceildiv, and mod is only allowed w.r.t constants.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070075bool AffineExpr::isPureAffine() const {
76 switch (getKind()) {
77 case Kind::SymbolId:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070078 case Kind::DimId:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070079 case Kind::Constant:
Chris Lattner1ac20cb2018-07-10 10:59:53 -070080 return true;
Uday Bondhugulac1faf662018-07-19 14:08:50 -070081 case Kind::Add: {
82 auto *op = cast<AffineBinaryOpExpr>(this);
Chris Lattner1ac20cb2018-07-10 10:59:53 -070083 return op->getLHS()->isPureAffine() && op->getRHS()->isPureAffine();
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070084 }
Uday Bondhugula3934d4d2018-07-09 09:00:25 -070085
Chris Lattner1ac20cb2018-07-10 10:59:53 -070086 case Kind::Mul: {
87 // TODO: Canonicalize the constants in binary operators to the RHS when
88 // possible, allowing this to merge into the next case.
Uday Bondhugulac1faf662018-07-19 14:08:50 -070089 auto *op = cast<AffineBinaryOpExpr>(this);
Chris Lattner1ac20cb2018-07-10 10:59:53 -070090 return op->getLHS()->isPureAffine() && op->getRHS()->isPureAffine() &&
91 (isa<AffineConstantExpr>(op->getLHS()) ||
92 isa<AffineConstantExpr>(op->getRHS()));
93 }
94 case Kind::FloorDiv:
95 case Kind::CeilDiv:
96 case Kind::Mod: {
Uday Bondhugulac1faf662018-07-19 14:08:50 -070097 auto *op = cast<AffineBinaryOpExpr>(this);
Chris Lattner1ac20cb2018-07-10 10:59:53 -070098 return op->getLHS()->isPureAffine() &&
99 isa<AffineConstantExpr>(op->getRHS());
100 }
101 }
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700102}
Uday Bondhugula83a41c92018-08-30 17:35:15 -0700103
104uint64_t AffineExpr::getKnownGcd() const {
105 AffineBinaryOpExpr *binExpr = nullptr;
106 switch (kind) {
107 case Kind::SymbolId:
108 LLVM_FALLTHROUGH;
109 case Kind::DimId:
110 return 1;
111 case Kind::Constant:
112 return std::abs(cast<AffineConstantExpr>(this)->getValue());
113 case Kind::Mul:
114 binExpr = cast<AffineBinaryOpExpr>(const_cast<AffineExpr *>(this));
115 return binExpr->getLHS()->getKnownGcd() * binExpr->getRHS()->getKnownGcd();
116 case Kind::Add:
117 LLVM_FALLTHROUGH;
118 case Kind::FloorDiv:
119 case Kind::CeilDiv:
120 case Kind::Mod:
121 binExpr = cast<AffineBinaryOpExpr>(const_cast<AffineExpr *>(this));
122 return llvm::GreatestCommonDivisor64(binExpr->getLHS()->getKnownGcd(),
123 binExpr->getRHS()->getKnownGcd());
124 }
125}
126
127bool AffineExpr::isMultipleOf(int64_t factor) const {
128 AffineBinaryOpExpr *binExpr = nullptr;
129 uint64_t l, u;
130 switch (kind) {
131 case Kind::SymbolId:
132 LLVM_FALLTHROUGH;
133 case Kind::DimId:
134 return factor * factor == 1;
135 case Kind::Constant:
136 return cast<AffineConstantExpr>(this)->getValue() % factor == 0;
137 case Kind::Mul:
138 binExpr = cast<AffineBinaryOpExpr>(const_cast<AffineExpr *>(this));
139 // It's probably not worth optimizing this further (to not traverse the
140 // whole sub-tree under - it that would require a version of isMultipleOf
141 // that on a 'false' return also returns the known GCD).
142 return (l = binExpr->getLHS()->getKnownGcd()) % factor == 0 ||
143 (u = binExpr->getRHS()->getKnownGcd()) % factor == 0 ||
144 (l * u) % factor == 0;
145 case Kind::Add:
146 case Kind::FloorDiv:
147 case Kind::CeilDiv:
148 case Kind::Mod:
149 binExpr = cast<AffineBinaryOpExpr>(const_cast<AffineExpr *>(this));
150 return llvm::GreatestCommonDivisor64(binExpr->getLHS()->getKnownGcd(),
151 binExpr->getRHS()->getKnownGcd()) %
152 factor ==
153 0;
154 }
155}