results.append(m.getResults().begin(), m.getResults().end());
current = mlir::AffineMap::get(
std::max(current.getNumDims(), m.getNumDims()),
- current.getNumSymbols() + m.getNumSymbols(), results, {});
+ current.getNumSymbols() + m.getNumSymbols(), results);
}
return inverseSubMap(current);
}
seenExprs.push_back(expr);
assert(map.getNumSymbols() == 0 && "expected map without symbols");
assert(seenExprs.size() == map.getNumInputs() && "map is not invertible");
- return AffineMap::get(map.getNumResults(), 0, seenExprs, {});
+ return AffineMap::get(map.getNumResults(), 0, seenExprs);
}
mlir::AffineMap linalg::inverseSubMap(AffineMap map, unsigned beginResult,
endResult = map.getNumResults();
auto subMap = AffineMap::get(
map.getNumDims(), map.getNumSymbols(),
- map.getResults().slice(beginResult, endResult - beginResult), {});
+ map.getResults().slice(beginResult, endResult - beginResult));
return inversePermutationMap(subMap);
}
auto d0 = getAffineDimExpr(0, context); // K
// A(K), B(K), C()
// (d0) -> (d0, d0)(%k)
- return SmallVector<AffineMap, 8>{AffineMap::get(1, 0, {d0}, {}), // A(K)
- AffineMap::get(1, 0, {d0}, {}), // B(K)
- AffineMap()}; // C()
+ return SmallVector<AffineMap, 8>{AffineMap::get(1, 0, {d0}), // A(K)
+ AffineMap::get(1, 0, {d0}), // B(K)
+ AffineMap()}; // C()
}
void linalg::DotOp::emitScalarImplementation(
auto d1 = getAffineDimExpr(1, context); // K
// A(M, K), B(K), C(M)
// (d0, d1) -> (d0, d1, d1, d0)(%m, %k)
- return SmallVector<AffineMap, 8>{
- AffineMap::get(2, 0, {d0, d1}, {}), // A(M, K)
- AffineMap::get(2, 0, {d1}, {}), // B(K)
- AffineMap::get(2, 0, {d0}, {})}; // C(M)
+ return SmallVector<AffineMap, 8>{AffineMap::get(2, 0, {d0, d1}), // A(M, K)
+ AffineMap::get(2, 0, {d1}), // B(K)
+ AffineMap::get(2, 0, {d0})}; // C(M)
}
// The body expression for matvec is: C(i) = scalarC + A(i, r_j) * B(r_j)
// A(M, K), B(K, N), C(M, N):
// (d0, d1, d2) -> (d0, d2, d2, d1, d0, d1)(%m, %n, %k)
return SmallVector<AffineMap, 8>{
- AffineMap::get(3, 0, {d0, d2}, {}), // A(M, K)
- AffineMap::get(3, 0, {d2, d1}, {}), // B(K, N)
- AffineMap::get(3, 0, {d0, d1}, {}) // C(M, N)
+ AffineMap::get(3, 0, {d0, d2}), // A(M, K)
+ AffineMap::get(3, 0, {d2, d1}), // B(K, N)
+ AffineMap::get(3, 0, {d0, d1}) // C(M, N)
};
}
assert(map.getNumInputs() == ranges.size());
unsigned numDims = map.getNumDims();
assert(map.getNumSymbols() == 0);
- assert(map.getRangeSizes().empty());
RangeParts res(map.getNumResults());
RangeParts rangeParts(ranges);
for (auto expr : map.getResults()) {
- AffineMap map = AffineMap::get(numDims, 0, expr, {});
+ AffineMap map = AffineMap::get(numDims, 0, expr);
res.mins.push_back(makeFoldedComposedAffineApply(map, rangeParts.mins));
res.maxes.push_back(makeFoldedComposedAffineApply(map, rangeParts.maxes));
res.steps.push_back(makeFoldedComposedAffineApply(map, rangeParts.steps));
// 1. Take the first ivs results of the map, the other ones are not composed
// but merely copied over.
assert(map.getNumSymbols() == 0);
- assert(map.getRangeSizes().empty());
MLIRContext *context = ScopedContext::getContext();
unsigned numParallel = op->getNumParallelDims();
unsigned numReduction = op->getNumReductionDims();
for (auto en : llvm::enumerate(map.getResults())) {
auto index = en.index();
auto expr = en.value();
- AffineMap exprMap = AffineMap::get(numDims, 0, expr, {});
+ AffineMap exprMap = AffineMap::get(numDims, 0, expr);
ValueHandle offset(makeFoldedComposedAffineApply(exprMap, ivs));
// Offset is normally a function of loop induction variables.
// If it is 0, it must come from a dimension that was not tiled.
### Dimensions and Symbols
Dimensions and symbols are the two kinds of identifiers that can appear in the
-polyhedral structures, and are always of [`index`](../LangRef.md#index-type) type. Dimensions
-are declared in parentheses and symbols are declared in square brackets.
+polyhedral structures, and are always of [`index`](../LangRef.md#index-type)
+type. Dimensions are declared in parentheses and symbols are declared in square
+brackets.
Examples:
```mlir {.mlir}
// A 2d to 3d affine mapping.
// d0/d1 are dimensions, s0 is a symbol
-#affine_map2to3 = (d0, d1)[s0] -> (d0, d1 + s0, d1 - s0) size (10, 20, 30)
+#affine_map2to3 = (d0, d1)[s0] -> (d0, d1 + s0, d1 - s0)
```
Dimensional identifiers correspond to the dimensions of the underlying structure
Example:
```mlir {.mlir}
-#affine_map2to3 = (d0, d1)[s0] -> (d0, d1 + s0, d1 - s0) size (10,20,30)
+#affine_map2to3 = (d0, d1)[s0] -> (d0, d1 + s0, d1 - s0)
// Binds %N to the s0 symbol in affine_map2to3.
%x = alloc()[%N] : memref<40x50xf32, #affine_map2to3>
```
second argument is always positive, its results are always positive in our
usage. The `integer-literal` operand for ceildiv, floordiv, and mod is always
expected to be positive. `bare-id` is an identifier which must have type
-[index](../LangRef.md#index-type). The precedence of operations in an affine expression are
-ordered from highest to lowest in the order: (1) parenthesization, (2) negation,
-(3) modulo, multiplication, floordiv, and ceildiv, and (4) addition and
-subtraction. All of these operators associate from left to right.
+[index](../LangRef.md#index-type). The precedence of operations in an affine
+expression are ordered from highest to lowest in the order: (1)
+parenthesization, (2) negation, (3) modulo, multiplication, floordiv, and
+ceildiv, and (4) addition and subtraction. All of these operators associate from
+left to right.
A _multi-dimensional affine expression_ is a comma separated list of
one-dimensional affine expressions, with the entire list enclosed in
``` {.ebnf}
affine-map-inline
::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
- ( `size` `(` dim-size (`,` dim-size)* `)` )?
-
-dim-size ::= affine-expr
- | `min` `(` affine-expr ( `,` affine-expr)+ `)`
```
The identifiers in the dimensions and symbols lists must be unique. These are
-the only identifiers that may appear in 'multi-dim-affine-expr'. In addition,
-only symbolic identifiers and constants can appear in 'dim-size'. Affine maps
+the only identifiers that may appear in 'multi-dim-affine-expr'. Affine maps
with one or more symbols in its specification are known as "symbolic affine
-maps", and those with no symbols as "non-symbolic affine maps". An affine map
-has an optional "size" tuple which provides the size for each corresponding
-dimension. Affine maps with a size in their specification are known as "bounded
-affine maps", and those without a size are "unbounded affine maps".
+maps", and those with no symbols as "non-symbolic affine maps".
**Context:** Affine maps are mathematical functions that transform a list of
dimension indices and symbols into a list of results, with affine expressions
```mlir {.mlir}
// Affine map out-of-line definition and usage example.
-#affine_map42 =
- (d0, d1)[s0] -> (d0, d0 + d1 + floordiv(s0,2)) size (10, s0)
+#affine_map42 = (d0, d1)[s0] -> (d0, d0 + d1 + floordiv(s0,2))
// Use an affine mapping definition in an alloc operation, binding the
// SSA value %N to the symbol s0.
%a = alloc()[%N] : memref<4x4xf32, #affine_map42>
// Same thing with an inline affine mapping definition.
-%b = alloc()[%N] : memref<4x4xf32, (d0, d1)[s0] -> (d0, d0 + d1 + floordiv(s0,2))
- size (10, s0)>
+%b = alloc()[%N] : memref<4x4xf32, (d0, d1)[s0] -> (d0, d0 + d1 + floordiv(s0,2))>
```
### Semi-affine maps
``` {.ebnf}
semi-affine-map-inline
::= dim-and-symbol-id-lists `->` multi-dim-semi-affine-expr
- ( `size` `(` dim-size (`,` dim-size)* `)` )?
```
Semi-affine maps may be defined inline at the point of use, or may be hoisted to
private:
// Same meaning as AffineMap's fields.
SmallVector<AffineExpr, 8> results;
- SmallVector<AffineExpr, 8> rangeSizes;
unsigned numDims;
unsigned numSymbols;
/// A pointer to the IR's context to store all newly created
AffineMap &operator=(const AffineMap &other) = default;
static AffineMap get(unsigned dimCount, unsigned symbolCount,
- ArrayRef<AffineExpr> results,
- ArrayRef<AffineExpr> rangeSizes);
+ ArrayRef<AffineExpr> results);
/// Returns a single constant result affine map.
static AffineMap getConstantMap(int64_t val, MLIRContext *context);
bool operator==(AffineMap other) const { return other.map == map; }
bool operator!=(AffineMap other) const { return !(other.map == map); }
- /// Returns true if the co-domain (or more loosely speaking, range) of this
- /// map is bounded. Bounded affine maps have a size (extent) for each of
- /// their range dimensions (more accurately co-domain dimensions).
- bool isBounded() const;
-
/// Returns true if this affine map is an identity affine map.
/// An identity affine map corresponds to an identity affine function on the
/// dimensional identifiers.
ArrayRef<AffineExpr> getResults() const;
AffineExpr getResult(unsigned idx) const;
- ArrayRef<AffineExpr> getRangeSizes() const;
-
- /// Walk all of the AffineExpr's in this mapping. The results are visited
- /// first, and then the range sizes (if present). Each node in an expression
+ /// Walk all of the AffineExpr's in this mapping. Each node in an expression
/// tree is visited in postorder.
void walkExprs(std::function<void(AffineExpr)> callback) const;
/// Prerequisites:
/// The maps are composable, i.e. that the number of AffineDimExpr of `this`
/// matches the number of results of `map`.
- /// At this time, composition of bounded AffineMap is not supported. Both
- /// `this` and `map` must be unbounded.
///
/// Example:
/// map1: `(d0, d1)[s0, s1] -> (d0 + 1 + s1, d1 - 1 - s0)`
/// map2: `(d0)[s0] -> (d0 + s0, d0 - s0))`
/// map1.compose(map2):
/// `(d0)[s0, s1, s2] -> (d0 + s1 + s2 + 1, d0 - s0 - s2 - 1)`
- // TODO(ntv): support composition of bounded maps when we have a need for it.
AffineMap compose(AffineMap map);
friend ::llvm::hash_code hash_value(AffineMap arg);
return ::llvm::hash_value(arg.map);
}
-/// Simplify an affine map by simplifying its underlying AffineExpr results and
-/// sizes.
+/// Simplify an affine map by simplifying its underlying AffineExpr results.
AffineMap simplifyAffineMap(AffineMap map);
/// Returns a map of codomain to domain dimensions such that the first codomain
/// Prerequisites:
/// 1. `map` is a permutation of full rank.
/// 2. `map` has no symbols.
-/// 3. `map` has empty `rangeSizes`.
///
/// Example:
///
AffineMap inversePermutation(AffineMap map);
/// Concatenates a list of `maps` into a single AffineMap, stepping over
-/// potentially empty maps. Assumes each of the underlying map has 0 symbols and
-/// empty `rangeSizes`.
+/// potentially empty maps. Assumes each of the underlying map has 0 symbols.
/// The resulting map has a number of dims equal to the max of `maps`' dims and
/// the concatenated results as its results.
///
AffineExpr getAffineConstantExpr(int64_t constant);
AffineMap getAffineMap(unsigned dimCount, unsigned symbolCount,
- ArrayRef<AffineExpr> results,
- ArrayRef<AffineExpr> rangeSizes);
+ ArrayRef<AffineExpr> results);
// Special cases of affine maps and integer sets
/// Returns a single constant result affine map with 0 dimensions and 0
/// the access is statically guaranteed to be within bounds;
/// 2. an attribute of type AffineMap to specify a slice of the original
/// MemRef access and its transposition into the super-vector shape.
-/// The permutation_map is an unbounded AffineMap that must
-/// represent a permutation from the MemRef dim space projected onto the
-/// vector dim space.
+/// The permutation_map is an AffineMap that must represent a permutation
+/// from the MemRef dim space projected onto the vector dim space.
/// This permutation_map has as many output dimensions as the vector rank.
/// However, it is not necessarily full rank on the target space to signify
/// that broadcast operations will be needed along certain vector
ArrayRef<Value *> operands)
: AffineApplyNormalizer() {
static_assert(kMaxAffineApplyDepth > 0, "kMaxAffineApplyDepth must be > 0");
- assert(map.getRangeSizes().empty() && "Unbounded map expected");
assert(map.getNumInputs() == operands.size() &&
"number of operands does not match the number of map inputs");
"Unexpected number of concatenated symbols");
auto numDims = dimValueToPosition.size();
auto numSymbols = concatenatedSymbols.size() - map.getNumSymbols();
- auto auxiliaryMap = AffineMap::get(numDims, numSymbols, auxiliaryExprs, {});
+ auto auxiliaryMap = AffineMap::get(numDims, numSymbols, auxiliaryExprs);
LLVM_DEBUG(map.print(dbgs() << "\nCompose map: "));
LLVM_DEBUG(auxiliaryMap.print(dbgs() << "\nWith map: "));
context(map.getResult(0).getContext()) {
for (auto result : map.getResults())
results.push_back(result);
- for (auto rangeSize : map.getRangeSizes())
- results.push_back(rangeSize);
}
void MutableAffineMap::reset(AffineMap map) {
results.clear();
- rangeSizes.clear();
numDims = map.getNumDims();
numSymbols = map.getNumSymbols();
// A map always has at least 1 result by construction
context = map.getResult(0).getContext();
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 {
}
AffineMap MutableAffineMap::getAffineMap() const {
- return AffineMap::get(numDims, numSymbols, results, rangeSizes);
+ return AffineMap::get(numDims, numSymbols, results);
}
MutableIntegerSet::MutableIntegerSet(IntegerSet set, MLIRContext *context)
auto expr = mlir::toAffineExpr(lb, dimCount, symCount, localExprs, context);
exprs.push_back(expr);
}
- auto lbMap = exprs.empty() ? AffineMap()
- : AffineMap::get(dimCount, symCount, exprs, {});
+ auto lbMap =
+ exprs.empty() ? AffineMap() : AffineMap::get(dimCount, symCount, exprs);
exprs.clear();
exprs.reserve(ubIndices.size());
// Upper bound is exclusive.
exprs.push_back(expr + 1);
}
- auto ubMap = exprs.empty() ? AffineMap()
- : AffineMap::get(dimCount, symCount, exprs, {});
+ auto ubMap =
+ exprs.empty() ? AffineMap() : AffineMap::get(dimCount, symCount, exprs);
return {lbMap, ubMap};
}
AffineMap &ubMap = (*ubMaps)[pos];
if (expr) {
- lbMap = AffineMap::get(numMapDims, numMapSymbols, expr, {});
- ubMap = AffineMap::get(numMapDims, numMapSymbols, expr + 1, {});
+ lbMap = AffineMap::get(numMapDims, numMapSymbols, expr);
+ ubMap = AffineMap::get(numMapDims, numMapSymbols, expr + 1);
} else {
// TODO(bondhugula): Whenever there are local identifiers in the
// dependence constraints, we'll conservatively over-approximate, since we
if (lbConst.hasValue()) {
lbMap = AffineMap::get(
numMapDims, numMapSymbols,
- getAffineConstantExpr(lbConst.getValue(), context), {});
+ getAffineConstantExpr(lbConst.getValue(), context));
}
}
if (!ubMap || ubMap.getNumResults() > 1) {
if (ubConst.hasValue()) {
(ubMap) = AffineMap::get(
numMapDims, numMapSymbols,
- getAffineConstantExpr(ubConst.getValue() + 1, context), {});
+ getAffineConstantExpr(ubConst.getValue() + 1, context));
}
}
}
for (auto ubExpr : ubMap.getResults())
ubs.push_back(b.create<AffineApplyOp>(
forOp.getLoc(),
- b.getAffineMap(ubMap.getNumDims(), ubMap.getNumSymbols(), {ubExpr}, {}),
+ b.getAffineMap(ubMap.getNumDims(), ubMap.getNumSymbols(), {ubExpr}),
ubOperands));
tripCountOperands->clear();
for (unsigned i = 0, e = ubs.size(); i < e; i++)
tripCountExprs[i] =
(b.getAffineDimExpr(1 + i) - b.getAffineDimExpr(0)).ceilDiv(step);
- *map = b.getAffineMap(1 + ubs.size(), 0, tripCountExprs, {});
+ *map = b.getAffineMap(1 + ubs.size(), 0, tripCountExprs);
fullyComposeAffineMapAndOperands(map, tripCountOperands);
*map = simplifyAffineMap(*map);
"Vectorization prerequisite violated: at most 1 index may be "
"invariant wrt a vectorized loop");
}
- return AffineMap::get(indices.size(), 0, perm, {});
+ return AffineMap::get(indices.size(), 0, perm);
}
/// Implementation detail that walks up the parents and records the ones with
if (v1) {
operands.push_back(v1);
}
- auto map = AffineMap::get(numDims, numSymbols, {affCombiner(d0, d1)}, {});
+ auto map = AffineMap::get(numDims, numSymbols, {affCombiner(d0, d1)});
// TODO: createOrFold when available.
return ValueHandle::createComposedAffineApply(map, operands);
}
/// Returns a single constant result affine map.
AffineMap AffineMap::getConstantMap(int64_t val, MLIRContext *context) {
return get(/*dimCount=*/0, /*symbolCount=*/0,
- {getAffineConstantExpr(val, context)}, {});
+ {getAffineConstantExpr(val, context)});
}
AffineMap AffineMap::getMultiDimIdentityMap(unsigned numDims,
dimExprs.reserve(numDims);
for (unsigned i = 0; i < numDims; ++i)
dimExprs.push_back(mlir::getAffineDimExpr(i, context));
- return get(/*dimCount=*/numDims, /*symbolCount=*/0, dimExprs, {});
+ return get(/*dimCount=*/numDims, /*symbolCount=*/0, dimExprs);
}
MLIRContext *AffineMap::getContext() const { return getResult(0).getContext(); }
-bool AffineMap::isBounded() const {
- assert(map && "uninitialized AffineMap");
- return !map->rangeSizes.empty();
-}
-
bool AffineMap::isIdentity() const {
if (getNumDims() != getNumResults())
return false;
assert(map && "uninitialized map storage");
return map->results[idx];
}
-ArrayRef<AffineExpr> AffineMap::getRangeSizes() const {
- assert(map && "uninitialized map storage");
- return map->rangeSizes;
-}
/// Folds the results of the application of an affine map on the provided
/// operands to a constant if possible. Returns false if the folding happens,
return success();
}
-/// Walk all of the AffineExpr's in this mapping. The results are visited
-/// first, and then the range sizes (if present). Each node in an expression
+/// Walk all of the AffineExpr's in this mapping. Each node in an expression
/// tree is visited in postorder.
void AffineMap::walkExprs(std::function<void(AffineExpr)> callback) const {
for (auto expr : getResults())
expr.walk(callback);
-
- for (auto expr : getRangeSizes())
- expr.walk(callback);
}
/// This method substitutes any uses of dimensions and symbols (e.g.
results.push_back(
expr.replaceDimsAndSymbols(dimReplacements, symReplacements));
- SmallVector<AffineExpr, 8> resultRanges;
- resultRanges.reserve(getRangeSizes().size());
- for (auto expr : getRangeSizes())
- resultRanges.push_back(
- expr.replaceDimsAndSymbols(dimReplacements, symReplacements));
-
- return get(numResultDims, numResultSyms, results, resultRanges);
+ return get(numResultDims, numResultSyms, results);
}
AffineMap AffineMap::compose(AffineMap map) {
assert(getNumDims() == map.getNumResults() && "Number of results mismatch");
- assert(getRangeSizes().empty() && "TODO: support bounded AffineMap");
- assert(map.getRangeSizes().empty() && "TODO: support bounded AffineMap");
// Prepare `map` by concatenating the symbols and rewriting its exprs.
unsigned numDims = map.getNumDims();
unsigned numSymbolsThisMap = getNumSymbols();
exprs.reserve(getResults().size());
for (auto expr : getResults())
exprs.push_back(expr.compose(newMap));
- return AffineMap::get(numDims, numSymbols, exprs, {});
+ return AffineMap::get(numDims, numSymbols, exprs);
}
AffineMap mlir::simplifyAffineMap(AffineMap map) {
- SmallVector<AffineExpr, 8> exprs, sizes;
+ SmallVector<AffineExpr, 8> exprs;
for (auto e : map.getResults()) {
exprs.push_back(
simplifyAffineExpr(e, map.getNumDims(), map.getNumSymbols()));
}
- for (auto e : map.getRangeSizes()) {
- sizes.push_back(
- simplifyAffineExpr(e, map.getNumDims(), map.getNumSymbols()));
- }
- return AffineMap::get(map.getNumDims(), map.getNumSymbols(), exprs, sizes);
+ return AffineMap::get(map.getNumDims(), map.getNumSymbols(), exprs);
}
AffineMap mlir::inversePermutation(AffineMap map) {
assert(map.getNumSymbols() == 0 && "expected map without symbols");
- assert(map.getRangeSizes().empty() && "expected map without range sizes");
SmallVector<AffineExpr, 4> exprs(map.getNumDims());
for (auto en : llvm::enumerate(map.getResults())) {
auto expr = en.value();
if (expr)
seenExprs.push_back(expr);
assert(seenExprs.size() == map.getNumInputs() && "map is not full rank");
- return AffineMap::get(map.getNumResults(), 0, seenExprs, {});
+ return AffineMap::get(map.getNumResults(), 0, seenExprs);
}
AffineMap mlir::concatAffineMaps(ArrayRef<AffineMap> maps) {
if (!m)
continue;
assert(m.getNumSymbols() == 0 && "expected map without symbols");
- assert(m.getRangeSizes().empty() && "expected map without range sizes");
results.append(m.getResults().begin(), m.getResults().end());
numDims = std::max(m.getNumDims(), numDims);
}
- return AffineMap::get(numDims, 0, results, {});
+ return AffineMap::get(numDims, 0, results);
}
/// The affine expressions for this (multi-dimensional) map.
/// TODO: use trailing objects for this.
ArrayRef<AffineExpr> results;
-
- /// The extents along each of the range dimensions if the map is bounded,
- /// nullptr otherwise.
- ArrayRef<AffineExpr> rangeSizes;
};
} // end namespace detail
interleaveComma(map.getResults(),
[&](AffineExpr expr) { printAffineExpr(expr); });
os << ')';
-
- if (!map.isBounded()) {
- return;
- }
-
- // Print range sizes for bounded affine maps.
- os << " size (";
- interleaveComma(map.getRangeSizes(),
- [&](AffineExpr expr) { printAffineExpr(expr); });
- os << ')';
}
void ModulePrinter::printIntegerSet(IntegerSet set) {
//===----------------------------------------------------------------------===//
AffineMap Builder::getAffineMap(unsigned dimCount, unsigned symbolCount,
- ArrayRef<AffineExpr> results,
- ArrayRef<AffineExpr> rangeSizes) {
- return AffineMap::get(dimCount, symbolCount, results, rangeSizes);
+ ArrayRef<AffineExpr> results) {
+ return AffineMap::get(dimCount, symbolCount, results);
}
AffineExpr Builder::getAffineDimExpr(unsigned position) {
AffineMap Builder::getConstantAffineMap(int64_t val) {
return AffineMap::get(/*dimCount=*/0, /*symbolCount=*/0,
- {getAffineConstantExpr(val)}, {});
+ {getAffineConstantExpr(val)});
}
AffineMap Builder::getDimIdentityMap() {
return AffineMap::get(/*dimCount=*/1, /*symbolCount=*/0,
- {getAffineDimExpr(0)}, {});
+ {getAffineDimExpr(0)});
}
AffineMap Builder::getMultiDimIdentityMap(unsigned rank) {
dimExprs.reserve(rank);
for (unsigned i = 0; i < rank; ++i)
dimExprs.push_back(getAffineDimExpr(i));
- return AffineMap::get(/*dimCount=*/rank, /*symbolCount=*/0, dimExprs, {});
+ return AffineMap::get(/*dimCount=*/rank, /*symbolCount=*/0, dimExprs);
}
AffineMap Builder::getSymbolIdentityMap() {
return AffineMap::get(/*dimCount=*/0, /*symbolCount=*/1,
- {getAffineSymbolExpr(0)}, {});
+ {getAffineSymbolExpr(0)});
}
AffineMap Builder::getSingleDimShiftAffineMap(int64_t shift) {
// expr = d0 + shift.
auto expr = getAffineDimExpr(0) + shift;
- return AffineMap::get(/*dimCount=*/1, /*symbolCount=*/0, {expr}, {});
+ return AffineMap::get(/*dimCount=*/1, /*symbolCount=*/0, {expr});
}
AffineMap Builder::getShiftedAffineMap(AffineMap map, int64_t shift) {
for (auto resultExpr : map.getResults()) {
shiftedResults.push_back(resultExpr + shift);
}
- return AffineMap::get(map.getNumDims(), map.getNumSymbols(), shiftedResults,
- map.getRangeSizes());
+ return AffineMap::get(map.getNumDims(), map.getNumSymbols(), shiftedResults);
}
//===----------------------------------------------------------------------===//
struct AffineMapKeyInfo : DenseMapInfo<AffineMap> {
// Affine maps are uniqued based on their dim/symbol counts and affine
// expressions.
- using KeyTy = std::tuple<unsigned, unsigned, ArrayRef<AffineExpr>,
- ArrayRef<AffineExpr>>;
+ using KeyTy = std::tuple<unsigned, unsigned, ArrayRef<AffineExpr>>;
using DenseMapInfo<AffineMap>::isEqual;
static unsigned getHashValue(const AffineMap &key) {
- return getHashValue(KeyTy(key.getNumDims(), key.getNumSymbols(),
- key.getResults(), key.getRangeSizes()));
+ return getHashValue(
+ KeyTy(key.getNumDims(), key.getNumSymbols(), key.getResults()));
}
static unsigned getHashValue(KeyTy key) {
return hash_combine(
std::get<0>(key), std::get<1>(key),
- hash_combine_range(std::get<2>(key).begin(), std::get<2>(key).end()),
- hash_combine_range(std::get<3>(key).begin(), std::get<3>(key).end()));
+ hash_combine_range(std::get<2>(key).begin(), std::get<2>(key).end()));
}
static bool isEqual(const KeyTy &lhs, AffineMap rhs) {
if (rhs == getEmptyKey() || rhs == getTombstoneKey())
return false;
return lhs == std::make_tuple(rhs.getNumDims(), rhs.getNumSymbols(),
- rhs.getResults(), rhs.getRangeSizes());
+ rhs.getResults());
}
};
}
AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
- ArrayRef<AffineExpr> results,
- ArrayRef<AffineExpr> rangeSizes) {
+ ArrayRef<AffineExpr> results) {
// The number of results can't be zero.
assert(!results.empty());
- assert(rangeSizes.empty() || results.size() == rangeSizes.size());
-
auto &impl = results[0].getContext()->getImpl();
- auto key = std::make_tuple(dimCount, symbolCount, results, rangeSizes);
+ auto key = std::make_tuple(dimCount, symbolCount, results);
// Safely get or create an AffineMap instance.
return safeGetOrCreate(impl.affineMaps, key, impl.affineMutex, [&] {
auto *res = impl.affineAllocator.Allocate<detail::AffineMapStorage>();
- // Copy the results and range sizes into the bump pointer.
+ // Copy the results into the bump pointer.
results = copyArrayRefInto(impl.affineAllocator, results);
- rangeSizes = copyArrayRefInto(impl.affineAllocator, rangeSizes);
// Initialize the memory using placement new.
- new (res)
- detail::AffineMapStorage{dimCount, symbolCount, results, rangeSizes};
+ new (res) detail::AffineMapStorage{dimCount, symbolCount, results};
return AffineMap(res);
});
}
++i;
}
- // Drop the unbounded identity maps from the composition.
+ // Drop identity maps from the composition.
// This may lead to the composition becoming empty, which is interpreted as an
// implicit identity.
llvm::SmallVector<AffineMap, 2> cleanedAffineMapComposition;
for (const auto &map : affineMapComposition) {
- if (map.isIdentity() && !map.isBounded())
+ if (map.isIdentity())
continue;
cleanedAffineMapComposition.push_back(map);
}
auto k = getAffineDimExpr(2, context);
if (isa<DotOp>(op))
// A(r_i) * B(r_i) -> C()
- return SmallVector<AffineMap, 4>{AffineMap::get(1, 0, {i}, {}),
- AffineMap::get(1, 0, {i}, {}),
- AffineMap()};
+ return SmallVector<AffineMap, 4>{AffineMap::get(1, 0, {i}),
+ AffineMap::get(1, 0, {i}), AffineMap()};
if (isa<MatvecOp>(op))
// A(i, r_j) * B(r_j) -> C(i)
- return SmallVector<AffineMap, 4>{AffineMap::get(2, 0, {i, j}, {}),
- AffineMap::get(2, 0, {j}, {}),
- AffineMap::get(2, 0, {i}, {})};
+ return SmallVector<AffineMap, 4>{AffineMap::get(2, 0, {i, j}),
+ AffineMap::get(2, 0, {j}),
+ AffineMap::get(2, 0, {i})};
if (isa<MatmulOp>(op))
// A(i, r_k) * B(r_k, j) -> C(i, j)
- return SmallVector<AffineMap, 4>{AffineMap::get(3, 0, {i, k}, {}),
- AffineMap::get(3, 0, {k, j}, {}),
- AffineMap::get(3, 0, {i, j}, {})};
+ return SmallVector<AffineMap, 4>{AffineMap::get(3, 0, {i, k}),
+ AffineMap::get(3, 0, {k, j}),
+ AffineMap::get(3, 0, {i, j})};
llvm_unreachable("Missing loopToOperandRangesMaps for op");
}
// ranges. If the resulting application can be folded into a Value*, the
// folding occurs eagerly. Otherwise, an affine.apply operation is emitted.
for (auto expr : map.getResults()) {
- AffineMap map = AffineMap::get(numDims, 0, expr, {});
+ AffineMap map = AffineMap::get(numDims, 0, expr);
res.push_back(emitOrFoldComposedAffineApply(b, loc, map, values, state));
}
return res;
/// Parse the range and sizes affine map definition inline.
///
/// affine-map ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
-/// (`size` `(` dim-size (`,` dim-size)* `)`)?
-/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
///
/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
AffineMap AffineParser::parseAffineMapRange(unsigned numDims,
if (parseCommaSeparatedListUntil(Token::r_paren, parseElt, false))
return AffineMap();
- // Parse optional range sizes.
- // range-sizes ::= (`size` `(` dim-size (`,` dim-size)* `)`)?
- // dim-size ::= affine-expr | `min` `(` affine-expr (`,` affine-expr)+ `)`
- // TODO(bondhugula): support for min of several affine expressions.
- // TODO: check if sizes are non-negative whenever they are constant.
- SmallVector<AffineExpr, 4> rangeSizes;
- if (consumeIf(Token::kw_size)) {
- // Location of the l_paren token (if it exists) for error reporting later.
- auto loc = getToken().getLoc();
- if (parseToken(Token::l_paren, "expected '(' at start of affine map range"))
- return AffineMap();
-
- auto parseRangeSize = [&]() -> ParseResult {
- auto loc = getToken().getLoc();
- auto elt = parseAffineExpr();
- if (!elt)
- return failure();
-
- if (!elt.isSymbolicOrConstant())
- return emitError(loc,
- "size expressions cannot refer to dimension values");
-
- rangeSizes.push_back(elt);
- return success();
- };
-
- if (parseCommaSeparatedListUntil(Token::r_paren, parseRangeSize, false))
- return AffineMap();
- if (exprs.size() > rangeSizes.size())
- return (emitError(loc, "fewer range sizes than range expressions"),
- AffineMap());
- if (exprs.size() < rangeSizes.size())
- return (emitError(loc, "more range sizes than range expressions"),
- AffineMap());
- }
-
// Parsed a valid affine map.
- return builder.getAffineMap(numDims, numSymbols, exprs, rangeSizes);
+ return builder.getAffineMap(numDims, numSymbols, exprs);
}
/// Parse an ambiguous reference to either and affine map or an integer set.
// The coordinate for the start location is just the lower bound along the
// corresponding dimension on the memory region (stored in 'offset').
auto map = top.getAffineMap(
- cst->getNumDimIds() + cst->getNumSymbolIds() - rank, 0, offset, {});
+ cst->getNumDimIds() + cst->getNumSymbolIds() - rank, 0, offset);
memIndices.push_back(b->create<AffineApplyOp>(loc, map, regionSymbols));
}
// The fast buffer is DMAed into at location zero; addressing is relative.
auto dimExpr = b->getAffineDimExpr(regionSymbols.size() + i);
remapExprs.push_back(dimExpr - offsets[i]);
}
- auto indexRemap =
- b->getAffineMap(regionSymbols.size() + rank, 0, remapExprs, {});
+ auto indexRemap = b->getAffineMap(regionSymbols.size() + rank, 0, remapExprs);
// Record the begin since it may be invalidated by memref replacement.
Block::iterator prev;
simplifyAffineExpr(dimExpr - offsets[i], outerIVs.size() + rank, 0);
remapExprs.push_back(remapExpr);
}
- auto indexRemap =
- zeroOffsetCount == rank
- ? AffineMap()
- : b.getAffineMap(outerIVs.size() + rank, 0, remapExprs, {});
+ auto indexRemap = zeroOffsetCount == rank
+ ? AffineMap()
+ : b.getAffineMap(outerIVs.size() + rank, 0, remapExprs);
// Replace all users of 'oldMemRef' with 'newMemRef'.
bool ret =
replaceAllMemRefUsesWith(oldMemRef, newMemRef, {}, indexRemap,
boundExprs.append(origUbMap.getResults().begin(),
origUbMap.getResults().end());
auto ubMap = b.getAffineMap(origUbMap.getNumDims() + 1,
- origUbMap.getNumSymbols(), boundExprs, {});
+ origUbMap.getNumSymbols(), boundExprs);
newLoops[width + i].setUpperBound(/*operands=*/ubOperands, ubMap);
} else {
// No need of the min expression.
auto dim = b.getAffineDimExpr(0);
- auto ubMap = b.getAffineMap(1, 0, dim + tileSizes[i], {});
+ auto ubMap = b.getAffineMap(1, 0, dim + tileSizes[i]);
newLoops[width + i].setUpperBound(newLoops[i].getInductionVar(), ubMap);
}
}
if (!forOpIV->use_empty()) {
// iv' = iv + i, i = 1 to unrollJamFactor-1.
auto d0 = builder.getAffineDimExpr(0);
- auto bumpMap = builder.getAffineMap(1, 0, {d0 + i * step}, {});
+ auto bumpMap = builder.getAffineMap(1, 0, {d0 + i * step});
auto ivUnroll =
builder.create<AffineApplyOp>(forInst->getLoc(), bumpMap, forOpIV);
operandMapping.map(forOpIV, ivUnroll);
SmallVector<mlir::Value *, 8> res;
res.reserve(affineExprs.size());
for (auto expr : affineExprs) {
- auto map = AffineMap::get(numIndices, 0, expr, {});
+ auto map = AffineMap::get(numIndices, 0, expr);
res.push_back(makeComposedAffineApply(b, b->getInsertionPoint()->getLoc(),
map, memrefIndices));
}
if (keep.empty()) {
return permutationMap;
}
- auto projectionMap = AffineMap::get(optionalRatio->size(), 0, keep, {});
+ auto projectionMap = AffineMap::get(optionalRatio->size(), 0, keep);
LLVM_DEBUG(projectionMap.print(dbgs() << "\nprojectionMap: "));
return simplifyAffineMap(projectionMap.compose(permutationMap));
}
auto d0 = bInner.getAffineDimExpr(0);
int64_t step = forOp.getStep();
auto modTwoMap = bInner.getAffineMap(/*dimCount=*/1, /*symbolCount=*/0,
- {d0.floorDiv(step) % 2}, {});
+ {d0.floorDiv(step) % 2});
auto ivModTwoOp = bInner.create<AffineApplyOp>(forOp.getLoc(), modTwoMap,
forOp.getInductionVar());
for (unsigned i = 0, e = tripCountMap.getNumResults(); i < e; i++) {
auto tripCountExpr = tripCountMap.getResult(i);
bumpExprs[i] = (tripCountExpr - tripCountExpr % unrollFactor) * step;
- auto bumpMap =
- b->getAffineMap(tripCountMap.getNumDims(), tripCountMap.getNumSymbols(),
- bumpExprs[i], {});
+ auto bumpMap = b->getAffineMap(tripCountMap.getNumDims(),
+ tripCountMap.getNumSymbols(), bumpExprs[i]);
bumpValues[i] =
b->create<AffineApplyOp>(forOp.getLoc(), bumpMap, tripCountOperands);
}
operands->clear();
operands->push_back(lb);
operands->append(bumpValues.begin(), bumpValues.end());
- *map = b->getAffineMap(1 + tripCountMap.getNumResults(), 0, newUbExprs, {});
+ *map = b->getAffineMap(1 + tripCountMap.getNumResults(), 0, newUbExprs);
// Simplify the map + operands.
fullyComposeAffineMapAndOperands(map, operands);
*map = simplifyAffineMap(*map);
if (!forOpIV->use_empty()) {
// iv' = iv + 1/2/3...unrollFactor-1;
auto d0 = builder.getAffineDimExpr(0);
- auto bumpMap = builder.getAffineMap(1, 0, {d0 + i * step}, {});
+ auto bumpMap = builder.getAffineMap(1, 0, {d0 + i * step});
auto ivUnroll =
builder.create<AffineApplyOp>(forOp.getLoc(), bumpMap, forOpIV);
operandMap.map(forOpIV, ivUnroll);
auto bounds = llvm::to_vector<4>(map->getResults());
bounds.push_back(b->getAffineDimExpr(map->getNumDims()) + offset);
operands->insert(operands->begin() + map->getNumDims(), iv);
- *map =
- b->getAffineMap(map->getNumDims() + 1, map->getNumSymbols(), bounds, {});
+ *map = b->getAffineMap(map->getNumDims() + 1, map->getNumSymbols(), bounds);
canonicalizeMapAndOperands(map, operands);
}
// Remapped indices.
for (auto resultExpr : indexRemap.getResults()) {
- auto singleResMap =
- builder.getAffineMap(indexRemap.getNumDims(),
- indexRemap.getNumSymbols(), resultExpr, {});
+ auto singleResMap = builder.getAffineMap(
+ indexRemap.getNumDims(), indexRemap.getNumSymbols(), resultExpr);
auto afOp = builder.create<AffineApplyOp>(opInst->getLoc(),
singleResMap, remapOperands);
state.operands.push_back(afOp);
sliceOps->reserve(composedMap.getNumResults());
for (auto resultExpr : composedMap.getResults()) {
auto singleResMap = builder.getAffineMap(
- composedMap.getNumDims(), composedMap.getNumSymbols(), resultExpr, {});
+ composedMap.getNumDims(), composedMap.getNumSymbols(), resultExpr);
sliceOps->push_back(builder.create<AffineApplyOp>(
opInst->getLoc(), singleResMap, composedOpOperands));
}
return emitOpError("requires an AffineMapAttr named 'permutation_map'");
}
auto permutationMap = getPermutationMap();
- if (!permutationMap.getRangeSizes().empty()) {
- return emitOpError("requires an unbounded permutation_map");
- }
if (permutationMap.getNumSymbols() != 0) {
return emitOpError("requires a permutation_map without symbols");
}
return emitOpError("requires an AffineMapAttr named 'permutation_map'");
}
auto permutationMap = getPermutationMap();
- if (!permutationMap.getRangeSizes().empty()) {
- return emitOpError("requires an unbounded permutation_map");
- }
if (permutationMap.getNumSymbols() != 0) {
return emitOpError("requires a permutation_map without symbols");
}
// CHECK: #map{{[0-9]+}} = (d0, d1)[s0, s1] -> (d0 * s0, d0 + s0, d0 + 2, d1 * 2, s1 * 2, s0 + 2)
#map39 = (i, j)[M, N] -> (i*M, M + i, 2+i, j*2, N*2, 2 + M)
-// CHECK: #map{{[0-9]+}} = (d0, d1) -> (d0, d1) size (10, 20)
-#map40 = (i, j) -> (i, j) size (10, 20)
-
-// CHECK: #map{{[0-9]+}} = (d0, d1)[s0, s1] -> (d0, d1) size (s0, s1 + 10)
-#map41 = (i, j)[N, M] -> (i, j) size (N, M+10)
-
-// CHECK: #map{{[0-9]+}} = (d0, d1)[s0, s1] -> (d0, d1) size (128, s0 * 2 + s1 + 5)
-#map42 = (i, j)[N, M] -> (i, j) size (64 + 64, 5 + 2*N + M)
-
// CHECK: #map{{[0-9]+}} = (d0, d1)[s0] -> ((d0 * 5) floordiv 4, (d1 ceildiv 7) mod s0)
#map43 = (i, j) [s0] -> ( i * 5 floordiv 4, j ceildiv 7 mod s0)
// CHECK: func @f39(memref<2x4xi8, #map{{[0-9]+}}, 1>)
func @f39(memref<2x4xi8, #map39, 1>)
-// CHECK: func @f40(memref<2x4xi8, #map{{[0-9]+}}, 1>)
-func @f40(memref<2x4xi8, #map40, 1>)
-
-// CHECK: func @f41(memref<2x4xi8, #map{{[0-9]+}}, 1>)
-func @f41(memref<2x4xi8, #map41, 1>)
-
-// CHECK: func @f42(memref<2x4xi8, #map{{[0-9]+}}, 1>)
-func @f42(memref<2x4xi8, #map42, 1>)
-
// CHECK: func @f43(memref<2x4xi8, #map{{[0-9]+}}>)
func @f43(memref<2x4xi8, #map43>)
// -----
#hello_world = (i, j) -> (i, 3*d0 + ) // expected-error {{use of undeclared identifier}}
-// -----
-#hello_world = (i, j) -> (i, j) size (10, x) // expected-error {{use of undeclared identifier}}
-
-// -----
-#hello_world = (i, j) [M] -> (i, j) size (10, j) // expected-error {{size expressions cannot refer to dimension values}}
-
-// -----
-#hello_world = (i, j) [M] -> (i, j) size (10, M+i) // expected-error {{size expressions cannot refer to dimension values}}
-
-// -----
-#hello_world = (i, j) -> (i, j) size (10) // expected-error {{fewer range sizes than range expressions}}
-
-// -----
-#hello_world = (i, j) -> (i, j) size (10, 20, 30) // expected-error {{more range sizes than range expressions}}
-
// TODO(bondhugula): Add more tests; coverage of error messages emitted not complete
// -----