unroll/unroll-and-jam more powerful; add additional affine expr builder methods
- use previously added analysis/simplification to infer multiple of unroll
factor trip counts, making loop unroll/unroll-and-jam more general.
- for loop unroll, support bounds that are single result affine map's with the
same set of operands. For unknown loop bounds, loop unroll will now work as
long as trip count can be determined to be a multiple of unroll factor.
- extend getConstantTripCount to deal with single result affine map's with the
same operands. move it to mlir/Analysis/LoopAnalysis.cpp
- add additional builder utility methods for affine expr arithmetic
(difference, mod/floordiv/ceildiv w.r.t postitive constant). simplify code to
use the utility methods.
- move affine analysis routines to AffineAnalysis.cpp/.h from
AffineStructures.cpp/.h.
- Rename LoopUnrollJam to LoopUnrollAndJam to match class name.
- add an additional simplification for simplifyFloorDiv, simplifyCeilDiv
- Rename AffineMap::getNumOperands() getNumInputs: an affine map by itself does
not have operands. Operands are passed to it through affine_apply, from loop
bounds/if condition's, etc., operands are stored in the latter.
This should be sufficiently powerful for now as far as unroll/unroll-and-jam go for TPU
code generation, and can move to other analyses/transformations.
Loop nests like these are now unrolled without any cleanup loop being generated.
for %i = 1 to 100 {
// unroll factor 4: no cleanup loop will be generated.
for %j = (d0) -> (d0) (%i) to (d0) -> (5*d0 + 3) (%i) {
%x = "foo"(%j) : (affineint) -> i32
}
}
for %i = 1 to 100 {
// unroll factor 4: no cleanup loop will be generated.
for %j = (d0) -> (d0) (%i) to (d0) -> (d0 - d mod 4 - 1) (%i) {
%y = "foo"(%j) : (affineint) -> i32
}
}
for %i = 1 to 100 {
for %j = (d0) -> (d0) (%i) to (d0) -> (d0 + 128) (%i) {
%x = "foo"() : () -> i32
}
}
TODO(bondhugula): extend this to LoopUnrollAndJam as well in the next CL (with minor
changes).
PiperOrigin-RevId: 212661212
90 lines
3.1 KiB
C++
90 lines
3.1 KiB
C++
//===- AffineStructures.cpp - MLIR Affine Structures Class-------*- C++ -*-===//
|
|
//
|
|
// 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.
|
|
// =============================================================================
|
|
//
|
|
// Structures for affine/polyhedral analysis of MLIR functions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/Analysis/AffineStructures.h"
|
|
#include "mlir/Analysis/AffineAnalysis.h"
|
|
#include "mlir/IR/AffineMap.h"
|
|
#include "mlir/IR/IntegerSet.h"
|
|
#include "mlir/IR/StandardOps.h"
|
|
|
|
using namespace mlir;
|
|
|
|
MutableAffineMap::MutableAffineMap(AffineMap *map, MLIRContext *context)
|
|
: numDims(map->getNumDims()), numSymbols(map->getNumSymbols()),
|
|
context(context) {
|
|
for (auto *result : map->getResults())
|
|
results.push_back(result);
|
|
for (auto *rangeSize : map->getRangeSizes())
|
|
results.push_back(rangeSize);
|
|
}
|
|
|
|
bool MutableAffineMap::isMultipleOf(unsigned idx, int64_t factor) const {
|
|
if (results[idx]->isMultipleOf(factor))
|
|
return true;
|
|
|
|
// TODO(bondhugula): use simplifyAffineExpr and FlatAffineConstraints to
|
|
// complete this (for a more powerful analysis).
|
|
return false;
|
|
}
|
|
|
|
// Simplifies the result affine expressions of this map. The expressions have to
|
|
// be pure for the simplification implemented.
|
|
void MutableAffineMap::simplify() {
|
|
// Simplify each of the results if possible.
|
|
for (unsigned i = 0, e = getNumResults(); i < e; i++) {
|
|
AffineExpr *sExpr =
|
|
simplifyAffineExpr(getResult(i), numDims, numSymbols, context);
|
|
if (sExpr)
|
|
results[i] = sExpr;
|
|
}
|
|
}
|
|
|
|
MutableIntegerSet::MutableIntegerSet(IntegerSet *set, MLIRContext *context)
|
|
: numDims(set->getNumDims()), numSymbols(set->getNumSymbols()),
|
|
context(context) {
|
|
// TODO(bondhugula)
|
|
}
|
|
|
|
// Universal set.
|
|
MutableIntegerSet::MutableIntegerSet(unsigned numDims, unsigned numSymbols,
|
|
MLIRContext *context)
|
|
: numDims(numDims), numSymbols(numSymbols), context(context) {}
|
|
|
|
AffineValueMap::AffineValueMap(const AffineApplyOp &op, MLIRContext *context)
|
|
: map(op.getAffineMap(), context) {
|
|
// TODO: pull operands and results in.
|
|
}
|
|
|
|
inline bool AffineValueMap::isMultipleOf(unsigned idx, int64_t factor) const {
|
|
return map.isMultipleOf(idx, factor);
|
|
}
|
|
|
|
AffineValueMap::~AffineValueMap() {}
|
|
|
|
void FlatAffineConstraints::addEquality(ArrayRef<int64_t> eq) {
|
|
assert(eq.size() == getNumCols());
|
|
unsigned offset = equalities.size();
|
|
equalities.resize(equalities.size() + eq.size());
|
|
for (unsigned i = 0, e = eq.size(); i < e; i++) {
|
|
equalities[offset + i] = eq[i];
|
|
}
|
|
}
|