2018-06-28 02:03:08 +08:00
|
|
|
//===- AffineMap.cpp - MLIR Affine Map Classes ----------------------------===//
|
|
|
|
//
|
|
|
|
// Copyright 2019 The MLIR Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
// =============================================================================
|
|
|
|
|
|
|
|
#include "mlir/IR/AffineMap.h"
|
2018-07-10 00:00:25 +08:00
|
|
|
#include "mlir/IR/AffineExpr.h"
|
2018-06-28 02:03:08 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2018-07-12 12:19:31 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2018-06-28 02:03:08 +08:00
|
|
|
|
|
|
|
using namespace mlir;
|
|
|
|
|
2018-07-04 11:16:08 +08:00
|
|
|
AffineMap::AffineMap(unsigned numDims, unsigned numSymbols, unsigned numResults,
|
2018-07-12 12:31:07 +08:00
|
|
|
AffineExpr *const *results, AffineExpr *const *rangeSizes)
|
2018-07-04 11:16:08 +08:00
|
|
|
: numDims(numDims), numSymbols(numSymbols), numResults(numResults),
|
2018-07-12 12:31:07 +08:00
|
|
|
results(results), rangeSizes(rangeSizes) {}
|
2018-07-10 00:00:25 +08:00
|
|
|
|
2018-08-15 03:43:51 +08:00
|
|
|
bool AffineMap::isIdentity() const {
|
|
|
|
if (getNumDims() != getNumResults())
|
|
|
|
return false;
|
|
|
|
ArrayRef<AffineExpr *> results = getResults();
|
2018-08-16 06:14:45 +08:00
|
|
|
for (unsigned i = 0, numDims = getNumDims(); i < numDims; ++i) {
|
|
|
|
auto *expr = dyn_cast<AffineDimExpr>(results[i]);
|
|
|
|
if (!expr || expr->getPosition() != i)
|
2018-08-15 03:43:51 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-25 14:38:14 +08:00
|
|
|
bool AffineMap::isSingleConstant() const {
|
|
|
|
return getNumResults() == 1 && isa<AffineConstantExpr>(getResult(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t AffineMap::getSingleConstantValue() const {
|
|
|
|
assert(isSingleConstant() && "map must have a single constant result");
|
|
|
|
return dyn_cast<AffineConstantExpr>(getResult(0))->getValue();
|
|
|
|
}
|
|
|
|
|
2018-08-02 13:02:00 +08:00
|
|
|
/// Simplify add expression. Return nullptr if it can't be simplified.
|
2018-07-12 12:19:31 +08:00
|
|
|
AffineExpr *AffineBinaryOpExpr::simplifyAdd(AffineExpr *lhs, AffineExpr *rhs,
|
|
|
|
MLIRContext *context) {
|
2018-08-02 13:02:00 +08:00
|
|
|
auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
|
|
|
|
auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
|
2018-07-12 12:19:31 +08:00
|
|
|
|
2018-08-02 13:02:00 +08:00
|
|
|
// Fold if both LHS, RHS are a constant.
|
|
|
|
if (lhsConst && rhsConst)
|
|
|
|
return AffineConstantExpr::get(lhsConst->getValue() + rhsConst->getValue(),
|
|
|
|
context);
|
|
|
|
|
|
|
|
// Canonicalize so that only the RHS is a constant. (4 + d0 becomes d0 + 4).
|
|
|
|
// If only one of them is a symbolic expressions, make it the RHS.
|
2018-07-20 04:07:16 +08:00
|
|
|
if (isa<AffineConstantExpr>(lhs) ||
|
2018-08-02 13:02:00 +08:00
|
|
|
(lhs->isSymbolicOrConstant() && !rhs->isSymbolicOrConstant())) {
|
2018-07-20 05:08:50 +08:00
|
|
|
return AffineBinaryOpExpr::get(Kind::Add, rhs, lhs, context);
|
2018-08-02 13:02:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// At this point, if there was a constant, it would be on the right.
|
|
|
|
|
|
|
|
// Addition with a zero is a noop, return the other input.
|
|
|
|
if (rhsConst) {
|
|
|
|
if (rhsConst->getValue() == 0)
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
// Fold successive additions like (d0 + 2) + 3 into d0 + 5.
|
|
|
|
auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
|
|
|
|
if (lBin && rhsConst && lBin->getKind() == Kind::Add) {
|
|
|
|
if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
|
|
|
|
return AffineBinaryOpExpr::get(
|
|
|
|
Kind::Add, lBin->getLHS(),
|
|
|
|
AffineConstantExpr::get(lrhs->getValue() + rhsConst->getValue(),
|
|
|
|
context),
|
|
|
|
context);
|
|
|
|
}
|
|
|
|
|
|
|
|
// When doing successive additions, bring constant to the right: turn (d0 + 2)
|
|
|
|
// + d1 into (d0 + d1) + 2.
|
|
|
|
if (lBin && lBin->getKind() == Kind::Add) {
|
|
|
|
if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
|
|
|
|
return AffineBinaryOpExpr::get(
|
|
|
|
Kind::Add,
|
|
|
|
AffineBinaryOpExpr::get(Kind::Add, lBin->getLHS(), rhs, context),
|
|
|
|
lrhs, context);
|
|
|
|
}
|
|
|
|
}
|
2018-07-12 12:19:31 +08:00
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-08-02 13:02:00 +08:00
|
|
|
/// Simplify a multiply expression. Return nullptr if it can't be simplified.
|
2018-07-12 12:19:31 +08:00
|
|
|
AffineExpr *AffineBinaryOpExpr::simplifyMul(AffineExpr *lhs, AffineExpr *rhs,
|
|
|
|
MLIRContext *context) {
|
2018-08-02 13:02:00 +08:00
|
|
|
auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
|
|
|
|
auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
|
|
|
|
|
|
|
|
if (lhsConst && rhsConst)
|
|
|
|
return AffineConstantExpr::get(lhsConst->getValue() * rhsConst->getValue(),
|
|
|
|
context);
|
2018-07-12 12:19:31 +08:00
|
|
|
|
2018-07-20 04:07:16 +08:00
|
|
|
assert(lhs->isSymbolicOrConstant() || rhs->isSymbolicOrConstant());
|
2018-07-12 12:19:31 +08:00
|
|
|
|
|
|
|
// Canonicalize the mul expression so that the constant/symbolic term is the
|
|
|
|
// RHS. If both the lhs and rhs are symbolic, swap them if the lhs is a
|
|
|
|
// constant. (Note that a constant is trivially symbolic).
|
2018-07-20 04:07:16 +08:00
|
|
|
if (!rhs->isSymbolicOrConstant() || isa<AffineConstantExpr>(lhs)) {
|
2018-07-12 12:19:31 +08:00
|
|
|
// At least one of them has to be symbolic.
|
2018-07-20 05:08:50 +08:00
|
|
|
return AffineBinaryOpExpr::get(Kind::Mul, rhs, lhs, context);
|
2018-07-12 12:19:31 +08:00
|
|
|
}
|
|
|
|
|
2018-08-02 13:02:00 +08:00
|
|
|
// At this point, if there was a constant, it would be on the right.
|
|
|
|
|
|
|
|
// Multiplication with a one is a noop, return the other input.
|
|
|
|
if (rhsConst) {
|
|
|
|
if (rhsConst->getValue() == 1)
|
|
|
|
return lhs;
|
|
|
|
// Multiplication with zero.
|
|
|
|
if (rhsConst->getValue() == 0)
|
|
|
|
return rhsConst;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fold successive multiplications: eg: (d0 * 2) * 3 into d0 * 6.
|
|
|
|
auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
|
|
|
|
if (lBin && rhsConst && lBin->getKind() == Kind::Mul) {
|
|
|
|
if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS()))
|
|
|
|
return AffineBinaryOpExpr::get(
|
|
|
|
Kind::Mul, lBin->getLHS(),
|
|
|
|
AffineConstantExpr::get(lrhs->getValue() * rhsConst->getValue(),
|
|
|
|
context),
|
|
|
|
context);
|
|
|
|
}
|
|
|
|
|
|
|
|
// When doing successive multiplication, bring constant to the right: turn (d0
|
|
|
|
// * 2) * d1 into (d0 * d1) * 2.
|
|
|
|
if (lBin && lBin->getKind() == Kind::Mul) {
|
|
|
|
if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
|
|
|
|
return AffineBinaryOpExpr::get(
|
|
|
|
Kind::Mul,
|
|
|
|
AffineBinaryOpExpr::get(Kind::Mul, lBin->getLHS(), rhs, context),
|
|
|
|
lrhs, context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 00:00:25 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:19:31 +08:00
|
|
|
AffineExpr *AffineBinaryOpExpr::simplifyFloorDiv(AffineExpr *lhs,
|
|
|
|
AffineExpr *rhs,
|
|
|
|
MLIRContext *context) {
|
2018-08-02 13:02:00 +08:00
|
|
|
auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
|
|
|
|
auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
|
|
|
|
|
|
|
|
if (lhsConst && rhsConst)
|
|
|
|
return AffineConstantExpr::get(lhsConst->getValue() / rhsConst->getValue(),
|
|
|
|
context);
|
|
|
|
|
|
|
|
// Fold floordiv of a multiply with a constant that is a multiple of the
|
|
|
|
// divisor. Eg: (i * 128) floordiv 64 = i * 2.
|
|
|
|
if (rhsConst) {
|
|
|
|
auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
|
|
|
|
if (lBin && lBin->getKind() == Kind::Mul) {
|
|
|
|
if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
|
|
|
|
// rhsConst is known to be positive if a constant.
|
|
|
|
if (lrhs->getValue() % rhsConst->getValue() == 0)
|
|
|
|
return AffineBinaryOpExpr::get(
|
|
|
|
Kind::Mul, lBin->getLHS(),
|
|
|
|
AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
|
|
|
|
context),
|
|
|
|
context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-12 12:19:31 +08:00
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
AffineExpr *AffineBinaryOpExpr::simplifyCeilDiv(AffineExpr *lhs,
|
|
|
|
AffineExpr *rhs,
|
|
|
|
MLIRContext *context) {
|
2018-08-02 13:02:00 +08:00
|
|
|
auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
|
|
|
|
auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
|
|
|
|
|
|
|
|
if (lhsConst && rhsConst)
|
|
|
|
return AffineConstantExpr::get(
|
|
|
|
(int64_t)llvm::divideCeil((uint64_t)lhsConst->getValue(),
|
|
|
|
(uint64_t)rhsConst->getValue()),
|
|
|
|
context);
|
|
|
|
|
|
|
|
// Fold ceildiv of a multiply with a constant that is a multiple of the
|
|
|
|
// divisor. Eg: (i * 128) ceildiv 64 = i * 2.
|
|
|
|
if (rhsConst) {
|
|
|
|
auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
|
|
|
|
if (lBin && lBin->getKind() == Kind::Mul) {
|
|
|
|
if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
|
|
|
|
// rhsConst is known to be positive if a constant.
|
|
|
|
if (lrhs->getValue() % rhsConst->getValue() == 0)
|
|
|
|
return AffineBinaryOpExpr::get(
|
|
|
|
Kind::Mul, lBin->getLHS(),
|
|
|
|
AffineConstantExpr::get(lrhs->getValue() / rhsConst->getValue(),
|
|
|
|
context),
|
|
|
|
context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-12 12:19:31 +08:00
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
AffineExpr *AffineBinaryOpExpr::simplifyMod(AffineExpr *lhs, AffineExpr *rhs,
|
|
|
|
MLIRContext *context) {
|
2018-08-22 01:32:24 +08:00
|
|
|
auto *lhsConst = dyn_cast<AffineConstantExpr>(lhs);
|
|
|
|
auto *rhsConst = dyn_cast<AffineConstantExpr>(rhs);
|
|
|
|
|
|
|
|
if (lhsConst && rhsConst)
|
|
|
|
return AffineConstantExpr::get(lhsConst->getValue() % rhsConst->getValue(),
|
|
|
|
context);
|
|
|
|
|
|
|
|
// Fold modulo of a multiply with a constant that is a multiple of the
|
|
|
|
// modulo factor to zero. Eg: (i * 128) mod 64 = 0.
|
|
|
|
if (rhsConst) {
|
|
|
|
auto *lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
|
|
|
|
if (lBin && lBin->getKind() == Kind::Mul) {
|
|
|
|
if (auto *lrhs = dyn_cast<AffineConstantExpr>(lBin->getRHS())) {
|
|
|
|
// rhsConst is known to be positive if a constant.
|
|
|
|
if (lrhs->getValue() % rhsConst->getValue() == 0)
|
|
|
|
return AffineConstantExpr::get(0, context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-12 12:19:31 +08:00
|
|
|
|
|
|
|
return nullptr;
|
2018-08-22 01:32:24 +08:00
|
|
|
// TODO(bondhugula): In general, this can be simplified more by using the GCD
|
|
|
|
// test, or in general using quantifier elimination (add two new variables q
|
|
|
|
// and r, and eliminate all variables from the linear system other than r. All
|
|
|
|
// of this can be done through mlir/Analysis/'s FlatAffineConstraints.
|
2018-07-12 12:19:31 +08:00
|
|
|
}
|