diff --git a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h index b097f18e8cea34..9b30c9b160b75e 100644 --- a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h +++ b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h @@ -439,81 +439,6 @@ class AffineBound { friend class AffineForOp; }; -/// An `AffineApplyNormalizer` is a helper class that supports renumbering -/// operands of AffineApplyOp. This acts as a reindexing map of Value to -/// positional dims or symbols and allows simplifications such as: -/// -/// ```mlir -/// %1 = affine.apply (d0, d1) -> (d0 - d1) (%0, %0) -/// ``` -/// -/// into: -/// -/// ```mlir -/// %1 = affine.apply () -> (0) -/// ``` -struct AffineApplyNormalizer { - AffineApplyNormalizer(AffineMap map, ArrayRef operands); - - /// Returns the AffineMap resulting from normalization. - AffineMap getAffineMap() { return affineMap; } - - SmallVector getOperands() { - SmallVector res(reorderedDims); - res.append(concatenatedSymbols.begin(), concatenatedSymbols.end()); - return res; - } - - unsigned getNumSymbols() { return concatenatedSymbols.size(); } - unsigned getNumDims() { return reorderedDims.size(); } - - /// Normalizes 'otherMap' and its operands 'otherOperands' to map to this - /// normalizer's coordinate space. - void normalize(AffineMap *otherMap, SmallVectorImpl *otherOperands); - -private: - /// Helper function to insert `v` into the coordinate system of the current - /// AffineApplyNormalizer. Returns the AffineDimExpr with the corresponding - /// renumbered position. - AffineDimExpr renumberOneDim(Value v); - - /// Given an `other` normalizer, this rewrites `other.affineMap` in the - /// coordinate system of the current AffineApplyNormalizer. - /// Returns the rewritten AffineMap and updates the dims and symbols of - /// `this`. - AffineMap renumber(const AffineApplyNormalizer &other); - - /// Maps of Value to position in `affineMap`. - DenseMap dimValueToPosition; - - /// Ordered dims and symbols matching positional dims and symbols in - /// `affineMap`. - SmallVector reorderedDims; - SmallVector concatenatedSymbols; - - /// The number of symbols in concatenated symbols that belong to the original - /// map as opposed to those concatendated during map composition. - unsigned numProperSymbols; - - AffineMap affineMap; - - /// Used with RAII to control the depth at which AffineApply are composed - /// recursively. Only accepts depth 1 for now to allow a behavior where a - /// newly composed AffineApplyOp does not increase the length of the chain of - /// AffineApplyOps. Full composition is implemented iteratively on top of - /// this behavior. - static unsigned &affineApplyDepth() { - static thread_local unsigned depth = 0; - return depth; - } - static constexpr unsigned kMaxAffineApplyDepth = 1; - - AffineApplyNormalizer() : numProperSymbols(0) { affineApplyDepth()++; } - -public: - ~AffineApplyNormalizer() { affineApplyDepth()--; } -}; - } // end namespace mlir #endif diff --git a/mlir/include/mlir/IR/AffineExpr.h b/mlir/include/mlir/IR/AffineExpr.h index d4f7de501a9576..3e4e1c014b5875 100644 --- a/mlir/include/mlir/IR/AffineExpr.h +++ b/mlir/include/mlir/IR/AffineExpr.h @@ -110,6 +110,9 @@ class AffineExpr { /// Return true if the affine expression involves AffineDimExpr `position`. bool isFunctionOfDim(unsigned position) const; + /// Return true if the affine expression involves AffineSymbolExpr `position`. + bool isFunctionOfSymbol(unsigned position) const; + /// Walk all of the AffineExpr's in this expression in postorder. void walk(std::function callback) const; @@ -129,8 +132,11 @@ class AffineExpr { /// `*this` and apply replace with `map` on its subexpressions. AffineExpr replace(const DenseMap &map) const; - /// Replace symbols[0 .. numDims - 1] by - /// symbols[shift .. shift + numDims - 1]. + /// Replace dims[0 .. numDims - 1] by dims[shift .. shift + numDims - 1]. + AffineExpr shiftDims(unsigned numDims, unsigned shift) const; + + /// Replace symbols[0 .. numSymbols - 1] by + /// symbols[shift .. shift + numSymbols - 1]. AffineExpr shiftSymbols(unsigned numSymbols, unsigned shift) const; AffineExpr operator+(int64_t v) const; diff --git a/mlir/include/mlir/IR/AffineMap.h b/mlir/include/mlir/IR/AffineMap.h index 4e50a9599767c1..bf87bcf55a7f8e 100644 --- a/mlir/include/mlir/IR/AffineMap.h +++ b/mlir/include/mlir/IR/AffineMap.h @@ -129,6 +129,20 @@ class AffineMap { /// when the caller knows it is safe to do so. unsigned getDimPosition(unsigned idx) const; + /// Return true if any affine expression involves AffineDimExpr `position`. + bool isFunctionOfDim(unsigned position) const { + return llvm::any_of(getResults(), [&](AffineExpr e) { + return e.isFunctionOfDim(position); + }); + } + + /// Return true if any affine expression involves AffineSymbolExpr `position`. + bool isFunctionOfSymbol(unsigned position) const { + return llvm::any_of(getResults(), [&](AffineExpr e) { + return e.isFunctionOfSymbol(position); + }); + } + /// Walk all of the AffineExpr's in this mapping. Each node in an expression /// tree is visited in postorder. void walkExprs(std::function callback) const; @@ -143,6 +157,40 @@ class AffineMap { unsigned numResultDims, unsigned numResultSyms) const; + /// Sparse replace method. Apply AffineExpr::replace(`expr`, `replacement`) to + /// each of the results and return a new AffineMap with the new results and + /// with the specified number of dims and symbols. + AffineMap replace(AffineExpr expr, AffineExpr replacement, + unsigned numResultDims, unsigned numResultSyms) const; + + /// Sparse replace method. Apply AffineExpr::replace(`map`) to each of the + /// results and return a new AffineMap with the new results and with the + /// specified number of dims and symbols. + AffineMap replace(const DenseMap &map, + unsigned numResultDims, unsigned numResultSyms) const; + + /// Replace dims[0 .. numDims - 1] by dims[shift .. shift + numDims - 1]. + AffineMap shiftDims(unsigned shift) const { + return AffineMap::get( + getNumDims() + shift, getNumSymbols(), + llvm::to_vector<4>(llvm::map_range( + getResults(), + [&](AffineExpr e) { return e.shiftDims(getNumDims(), shift); })), + getContext()); + } + + /// Replace symbols[0 .. numSymbols - 1] by + /// symbols[shift .. shift + numSymbols - 1]. + AffineMap shiftSymbols(unsigned shift) const { + return AffineMap::get(getNumDims(), getNumSymbols() + shift, + llvm::to_vector<4>(llvm::map_range( + getResults(), + [&](AffineExpr e) { + return e.shiftSymbols(getNumSymbols(), shift); + })), + getContext()); + } + /// Folds the results of the application of an affine map on the provided /// operands to a constant if possible. LogicalResult constantFold(ArrayRef operandConstants, diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp index 2e75cd07ed839a..7cb6bcced29225 100644 --- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp +++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp @@ -570,264 +570,119 @@ OpFoldResult AffineApplyOp::fold(ArrayRef operands) { return result[0]; } -AffineDimExpr AffineApplyNormalizer::renumberOneDim(Value v) { - DenseMap::iterator iterPos; - bool inserted = false; - std::tie(iterPos, inserted) = - dimValueToPosition.insert(std::make_pair(v, dimValueToPosition.size())); - if (inserted) { - reorderedDims.push_back(v); - } - return getAffineDimExpr(iterPos->second, v.getContext()) - .cast(); -} - -AffineMap AffineApplyNormalizer::renumber(const AffineApplyNormalizer &other) { - SmallVector dimRemapping; - for (auto v : other.reorderedDims) { - auto kvp = other.dimValueToPosition.find(v); - if (dimRemapping.size() <= kvp->second) - dimRemapping.resize(kvp->second + 1); - dimRemapping[kvp->second] = renumberOneDim(kvp->first); - } - unsigned numSymbols = concatenatedSymbols.size(); - unsigned numOtherSymbols = other.concatenatedSymbols.size(); - SmallVector symRemapping(numOtherSymbols); - for (unsigned idx = 0; idx < numOtherSymbols; ++idx) { - symRemapping[idx] = - getAffineSymbolExpr(idx + numSymbols, other.affineMap.getContext()); - } - concatenatedSymbols.insert(concatenatedSymbols.end(), - other.concatenatedSymbols.begin(), - other.concatenatedSymbols.end()); - auto map = other.affineMap; - return map.replaceDimsAndSymbols(dimRemapping, symRemapping, - reorderedDims.size(), - concatenatedSymbols.size()); -} - -// Gather the positions of the operands that are produced by an AffineApplyOp. -static llvm::SetVector -indicesFromAffineApplyOp(ArrayRef operands) { - llvm::SetVector res; - for (auto en : llvm::enumerate(operands)) - if (isa_and_nonnull(en.value().getDefiningOp())) - res.insert(en.index()); - return res; -} - -// Support the special case of a symbol coming from an AffineApplyOp that needs -// to be composed into the current AffineApplyOp. -// This case is handled by rewriting all such symbols into dims for the purpose -// of allowing mathematical AffineMap composition. -// Returns an AffineMap where symbols that come from an AffineApplyOp have been -// rewritten as dims and are ordered after the original dims. -// TODO: This promotion makes AffineMap lose track of which -// symbols are represented as dims. This loss is static but can still be -// recovered dynamically (with `isValidSymbol`). Still this is annoying for the -// semi-affine map case. A dynamic canonicalization of all dims that are valid -// symbols (a.k.a `canonicalizePromotedSymbols`) into symbols helps and even -// results in better simplifications and foldings. But we should evaluate -// whether this behavior is what we really want after using more. -static AffineMap promoteComposedSymbolsAsDims(AffineMap map, - ArrayRef symbols) { - if (symbols.empty()) { - return map; - } +/// Replace all occurrences of AffineExpr at position `pos` in `map` by the +/// defining AffineApplyOp expression and operands. +/// When `dimOrSymbolPosition < dims.size()`, AffineDimExpr@[pos] is replaced. +/// When `dimOrSymbolPosition >= dims.size()`, +/// AffineSymbolExpr@[pos - dims.size()] is replaced. +/// Mutate `map`,`dims` and `syms` in place as follows: +/// 1. `dims` and `syms` are only appended to. +/// 2. `map` dim and symbols are gradually shifted to higer positions. +/// 3. Old `dim` and `sym` entries are replaced by nullptr +/// This avoids the need for any bookkeeping. +static LogicalResult replaceDimOrSym(AffineMap *map, + unsigned dimOrSymbolPosition, + SmallVectorImpl &dims, + SmallVectorImpl &syms) { + bool isDimReplacement = (dimOrSymbolPosition < dims.size()); + unsigned pos = isDimReplacement ? dimOrSymbolPosition + : dimOrSymbolPosition - dims.size(); + Value &v = isDimReplacement ? dims[pos] : syms[pos]; + if (!v) + return failure(); - // Extract the symbol positions that come from an AffineApplyOp and - // needs to be rewritten as dims. - auto symPositions = indicesFromAffineApplyOp(symbols); - if (symPositions.empty()) { - return map; - } + auto affineApply = v.getDefiningOp(); + if (!affineApply) + return failure(); - // Create the new map by replacing each symbol at pos by the next new dim. - unsigned numDims = map.getNumDims(); - unsigned numSymbols = map.getNumSymbols(); - unsigned numNewDims = 0; - unsigned numNewSymbols = 0; - SmallVector symReplacements(numSymbols); - for (unsigned i = 0; i < numSymbols; ++i) { - symReplacements[i] = - symPositions.count(i) > 0 - ? getAffineDimExpr(numDims + numNewDims++, map.getContext()) - : getAffineSymbolExpr(numNewSymbols++, map.getContext()); - } - assert(numSymbols >= numNewDims); - AffineMap newMap = map.replaceDimsAndSymbols( - {}, symReplacements, numDims + numNewDims, numNewSymbols); + // At this point we will perform a replacement of `v`, set the entry in `dim` + // or `sym` to nullptr immediately. + v = nullptr; + + // Compute the map, dims and symbols coming from the AffineApplyOp. + AffineMap composeMap = affineApply.getAffineMap(); + assert(composeMap.getNumResults() == 1 && "affine.apply with >1 results"); + AffineExpr composeExpr = + composeMap.shiftDims(dims.size()).shiftSymbols(syms.size()).getResult(0); + ValueRange composeDims = + affineApply.getMapOperands().take_front(composeMap.getNumDims()); + ValueRange composeSyms = + affineApply.getMapOperands().take_back(composeMap.getNumSymbols()); + + // Perform the replacement and append the dims and symbols where relevant. + MLIRContext *ctx = map->getContext(); + AffineExpr toReplace = isDimReplacement ? getAffineDimExpr(pos, ctx) + : getAffineSymbolExpr(pos, ctx); + *map = map->replace(toReplace, composeExpr, dims.size(), syms.size()); + dims.append(composeDims.begin(), composeDims.end()); + syms.append(composeSyms.begin(), composeSyms.end()); - return newMap; + return success(); } -/// The AffineNormalizer composes AffineApplyOp recursively. Its purpose is to -/// keep a correspondence between the mathematical `map` and the `operands` of -/// a given AffineApplyOp. This correspondence is maintained by iterating over -/// the operands and forming an `auxiliaryMap` that can be composed -/// mathematically with `map`. To keep this correspondence in cases where -/// symbols are produced by affine.apply operations, we perform a local rewrite -/// of symbols as dims. -/// -/// Rationale for locally rewriting symbols as dims: -/// ================================================ -/// The mathematical composition of AffineMap must always concatenate symbols -/// because it does not have enough information to do otherwise. For example, -/// composing `(d0)[s0] -> (d0 + s0)` with itself must produce -/// `(d0)[s0, s1] -> (d0 + s0 + s1)`. -/// -/// The result is only equivalent to `(d0)[s0] -> (d0 + 2 * s0)` when -/// applied to the same mlir::Value for both s0 and s1. -/// As a consequence mathematical composition of AffineMap always concatenates -/// symbols. -/// -/// When AffineMaps are used in AffineApplyOp however, they may specify -/// composition via symbols, which is ambiguous mathematically. This corner case -/// is handled by locally rewriting such symbols that come from AffineApplyOp -/// into dims and composing through dims. -/// TODO: Composition via symbols comes at a significant code -/// complexity. Alternatively we should investigate whether we want to -/// explicitly disallow symbols coming from affine.apply and instead force the -/// user to compose symbols beforehand. The annoyances may be small (i.e. 1 or 2 -/// extra API calls for such uses, which haven't popped up until now) and the -/// benefit potentially big: simpler and more maintainable code for a -/// non-trivial, recursive, procedure. -AffineApplyNormalizer::AffineApplyNormalizer(AffineMap map, - ArrayRef operands) - : AffineApplyNormalizer() { - static_assert(kMaxAffineApplyDepth > 0, "kMaxAffineApplyDepth must be > 0"); - assert(map.getNumInputs() == operands.size() && - "number of operands does not match the number of map inputs"); - - LLVM_DEBUG(map.print(dbgs() << "\nInput map: ")); - - // Promote symbols that come from an AffineApplyOp to dims by rewriting the - // map to always refer to: - // (dims, symbols coming from AffineApplyOp, other symbols). - // The order of operands can remain unchanged. - // This is a simplification that relies on 2 ordering properties: - // 1. rewritten symbols always appear after the original dims in the map; - // 2. operands are traversed in order and either dispatched to: - // a. auxiliaryExprs (dims and symbols rewritten as dims); - // b. concatenatedSymbols (all other symbols) - // This allows operand order to remain unchanged. - unsigned numDimsBeforeRewrite = map.getNumDims(); - map = promoteComposedSymbolsAsDims(map, - operands.take_back(map.getNumSymbols())); - - LLVM_DEBUG(map.print(dbgs() << "\nRewritten map: ")); - - SmallVector auxiliaryExprs; - bool furtherCompose = (affineApplyDepth() <= kMaxAffineApplyDepth); - // We fully spell out the 2 cases below. In this particular instance a little - // code duplication greatly improves readability. - // Note that the first branch would disappear if we only supported full - // composition (i.e. infinite kMaxAffineApplyDepth). - if (!furtherCompose) { - // 1. Only dispatch dims or symbols. - for (auto en : llvm::enumerate(operands)) { - auto t = en.value(); - assert(t.getType().isIndex()); - bool isDim = (en.index() < map.getNumDims()); - if (isDim) { - // a. The mathematical composition of AffineMap composes dims. - auxiliaryExprs.push_back(renumberOneDim(t)); - } else { - // b. The mathematical composition of AffineMap concatenates symbols. - // We do the same for symbol operands. - concatenatedSymbols.push_back(t); - } - } - } else { - assert(numDimsBeforeRewrite <= operands.size()); - // 2. Compose AffineApplyOps and dispatch dims or symbols. - for (unsigned i = 0, e = operands.size(); i < e; ++i) { - auto t = operands[i]; - auto affineApply = t.getDefiningOp(); - if (affineApply) { - // a. Compose affine.apply operations. - LLVM_DEBUG(affineApply->print( - dbgs() << "\nCompose AffineApplyOp recursively: ")); - AffineMap affineApplyMap = affineApply.getAffineMap(); - SmallVector affineApplyOperands( - affineApply.getOperands().begin(), affineApply.getOperands().end()); - AffineApplyNormalizer normalizer(affineApplyMap, affineApplyOperands); - - LLVM_DEBUG(normalizer.affineMap.print( - dbgs() << "\nRenumber into current normalizer: ")); - - auto renumberedMap = renumber(normalizer); - - LLVM_DEBUG( - renumberedMap.print(dbgs() << "\nRecursive composition yields: ")); - - auxiliaryExprs.push_back(renumberedMap.getResult(0)); - } else { - if (i < numDimsBeforeRewrite) { - // b. The mathematical composition of AffineMap composes dims. - auxiliaryExprs.push_back(renumberOneDim(t)); - } else { - // c. The mathematical composition of AffineMap concatenates symbols. - // Note that the map composition will put symbols already present - // in the map before any symbols coming from the auxiliary map, so - // we insert them before any symbols that are due to renumbering, - // and after the proper symbols we have seen already. - concatenatedSymbols.insert( - std::next(concatenatedSymbols.begin(), numProperSymbols++), t); - } - } - } - } - - // Early exit if `map` is already composed. - if (auxiliaryExprs.empty()) { - affineMap = map; +/// Iterate over `operands` and fold away all those produced by an AffineApplyOp +/// iteratively. Perform canonicalization of map and operands as well as +/// AffineMap simplification. `map` and `operands` are mutated in place. +static void composeAffineMapAndOperands(AffineMap *map, + SmallVectorImpl *operands) { + if (map->getNumResults() == 0) { + canonicalizeMapAndOperands(map, operands); + *map = simplifyAffineMap(*map); return; } - assert(concatenatedSymbols.size() >= map.getNumSymbols() && - "Unexpected number of concatenated symbols"); - auto numDims = dimValueToPosition.size(); - auto numSymbols = concatenatedSymbols.size() - map.getNumSymbols(); - auto auxiliaryMap = - AffineMap::get(numDims, numSymbols, auxiliaryExprs, map.getContext()); - - LLVM_DEBUG(map.print(dbgs() << "\nCompose map: ")); - LLVM_DEBUG(auxiliaryMap.print(dbgs() << "\nWith map: ")); - LLVM_DEBUG(map.compose(auxiliaryMap).print(dbgs() << "\nResult: ")); - - // TODO: Disabling simplification results in major speed gains. - // Another option is to cache the results as it is expected a lot of redundant - // work is performed in practice. - affineMap = simplifyAffineMap(map.compose(auxiliaryMap)); - - LLVM_DEBUG(affineMap.print(dbgs() << "\nSimplified result: ")); - LLVM_DEBUG(dbgs() << "\n"); -} - -void AffineApplyNormalizer::normalize(AffineMap *otherMap, - SmallVectorImpl *otherOperands) { - AffineApplyNormalizer other(*otherMap, *otherOperands); - *otherMap = renumber(other); - - otherOperands->reserve(reorderedDims.size() + concatenatedSymbols.size()); - otherOperands->assign(reorderedDims.begin(), reorderedDims.end()); - otherOperands->append(concatenatedSymbols.begin(), concatenatedSymbols.end()); -} + MLIRContext *ctx = map->getContext(); + SmallVector dims(operands->begin(), + operands->begin() + map->getNumDims()); + SmallVector syms(operands->begin() + map->getNumDims(), + operands->end()); + + // Iterate over dims and symbols coming from AffineApplyOp and replace until + // exhaustion. This iteratively mutates `map`, `dims` and `syms`. Both `dims` + // and `syms` can only increase by construction. + // The implementation uses a `while` loop to support the case of symbols + // that may be constructed from dims ;this may be overkill. + while (true) { + bool changed = false; + for (unsigned pos = 0; pos != dims.size() + syms.size(); ++pos) + if ((changed |= succeeded(replaceDimOrSym(map, pos, dims, syms)))) + break; + if (!changed) + break; + } + + // Clear operands so we can fill them anew. + operands->clear(); + + // At this point we may have introduced null operands, prune them out before + // canonicalizing map and operands. + unsigned nDims = 0, nSyms = 0; + SmallVector dimReplacements, symReplacements; + dimReplacements.reserve(dims.size()); + symReplacements.reserve(syms.size()); + for (auto *container : {&dims, &syms}) { + bool isDim = (container == &dims); + auto &repls = isDim ? dimReplacements : symReplacements; + for (auto en : llvm::enumerate(*container)) { + Value v = en.value(); + if (!v) { + assert(isDim ? !map->isFunctionOfDim(en.index()) + : !map->isFunctionOfSymbol(en.index()) && + "map is function of unexpected expr@pos"); + repls.push_back(getAffineConstantExpr(0, ctx)); + continue; + } + repls.push_back(isDim ? getAffineDimExpr(nDims++, ctx) + : getAffineSymbolExpr(nSyms++, ctx)); + operands->push_back(v); + } + } + *map = map->replaceDimsAndSymbols(dimReplacements, symReplacements, nDims, + nSyms); -/// Implements `map` and `operands` composition and simplification to support -/// `makeComposedAffineApply`. This can be called to achieve the same effects -/// on `map` and `operands` without creating an AffineApplyOp that needs to be -/// immediately deleted. -static void composeAffineMapAndOperands(AffineMap *map, - SmallVectorImpl *operands) { - AffineApplyNormalizer normalizer(*map, *operands); - auto normalizedMap = normalizer.getAffineMap(); - auto normalizedOperands = normalizer.getOperands(); - canonicalizeMapAndOperands(&normalizedMap, &normalizedOperands); - *map = normalizedMap; - *operands = normalizedOperands; - assert(*map); + // Canonicalize and simplify before returning. + canonicalizeMapAndOperands(map, operands); + *map = simplifyAffineMap(*map); } void mlir::fullyComposeAffineMapAndOperands(AffineMap *map, diff --git a/mlir/lib/Dialect/Affine/IR/AffineValueMap.cpp b/mlir/lib/Dialect/Affine/IR/AffineValueMap.cpp index 6f7c2fbc56ff2e..a17eb411acc890 100644 --- a/mlir/lib/Dialect/Affine/IR/AffineValueMap.cpp +++ b/mlir/lib/Dialect/Affine/IR/AffineValueMap.cpp @@ -27,36 +27,35 @@ void AffineValueMap::difference(const AffineValueMap &a, const AffineValueMap &b, AffineValueMap *res) { assert(a.getNumResults() == b.getNumResults() && "invalid inputs"); - // Fully compose A's map + operands. - auto aMap = a.getAffineMap(); - SmallVector aOperands(a.getOperands().begin(), - a.getOperands().end()); - fullyComposeAffineMapAndOperands(&aMap, &aOperands); - - // Use the affine apply normalizer to get B's map into A's coordinate space. - AffineApplyNormalizer normalizer(aMap, aOperands); - SmallVector bOperands(b.getOperands().begin(), - b.getOperands().end()); - auto bMap = b.getAffineMap(); - normalizer.normalize(&bMap, &bOperands); - - assert(std::equal(bOperands.begin(), bOperands.end(), - normalizer.getOperands().begin()) && - "operands are expected to be the same after normalization"); + SmallVector allOperands; + allOperands.reserve(a.getNumOperands() + b.getNumOperands()); + auto aDims = a.getOperands().take_front(a.getNumDims()); + auto bDims = b.getOperands().take_front(b.getNumDims()); + auto aSyms = a.getOperands().take_back(a.getNumSymbols()); + auto bSyms = b.getOperands().take_back(b.getNumSymbols()); + allOperands.append(aDims.begin(), aDims.end()); + allOperands.append(bDims.begin(), bDims.end()); + allOperands.append(aSyms.begin(), aSyms.end()); + allOperands.append(bSyms.begin(), bSyms.end()); + + // Shift dims and symbols of b's map. + auto bMap = b.getAffineMap() + .shiftDims(a.getNumDims()) + .shiftSymbols(a.getNumSymbols()); // Construct the difference expressions. + auto aMap = a.getAffineMap(); SmallVector diffExprs; diffExprs.reserve(a.getNumResults()); for (unsigned i = 0, e = bMap.getNumResults(); i < e; ++i) - diffExprs.push_back(normalizer.getAffineMap().getResult(i) - - bMap.getResult(i)); + diffExprs.push_back(aMap.getResult(i) - bMap.getResult(i)); - auto diffMap = - AffineMap::get(normalizer.getNumDims(), normalizer.getNumSymbols(), - diffExprs, aMap.getContext()); - canonicalizeMapAndOperands(&diffMap, &bOperands); + auto diffMap = AffineMap::get(bMap.getNumDims(), bMap.getNumSymbols(), + diffExprs, bMap.getContext()); + fullyComposeAffineMapAndOperands(&diffMap, &allOperands); + canonicalizeMapAndOperands(&diffMap, &allOperands); diffMap = simplifyAffineMap(diffMap); - res->reset(diffMap, bOperands); + res->reset(diffMap, allOperands); } // Returns true and sets 'indexOfMatch' if 'valueToMatch' is found in diff --git a/mlir/lib/IR/AffineExpr.cpp b/mlir/lib/IR/AffineExpr.cpp index fdecdc6c7168a9..da1ba6d7539864 100644 --- a/mlir/lib/IR/AffineExpr.cpp +++ b/mlir/lib/IR/AffineExpr.cpp @@ -93,6 +93,15 @@ AffineExpr::replaceDimsAndSymbols(ArrayRef dimReplacements, } /// Replace symbols[0 .. numDims - 1] by symbols[shift .. shift + numDims - 1]. +AffineExpr AffineExpr::shiftDims(unsigned numDims, unsigned shift) const { + SmallVector dims; + for (unsigned idx = 0; idx < numDims; ++idx) + dims.push_back(getAffineDimExpr(idx + shift, getContext())); + return replaceDimsAndSymbols(dims, {}); +} + +/// Replace symbols[0 .. numSymbols - 1] by +/// symbols[shift .. shift + numSymbols - 1]. AffineExpr AffineExpr::shiftSymbols(unsigned numSymbols, unsigned shift) const { SmallVector symbols; for (unsigned idx = 0; idx < numSymbols; ++idx) @@ -261,6 +270,17 @@ bool AffineExpr::isFunctionOfDim(unsigned position) const { return false; } +bool AffineExpr::isFunctionOfSymbol(unsigned position) const { + if (getKind() == AffineExprKind::SymbolId) { + return *this == mlir::getAffineSymbolExpr(position, getContext()); + } + if (auto expr = this->dyn_cast()) { + return expr.getLHS().isFunctionOfSymbol(position) || + expr.getRHS().isFunctionOfSymbol(position); + } + return false; +} + AffineBinaryOpExpr::AffineBinaryOpExpr(AffineExpr::ImplType *ptr) : AffineExpr(ptr) {} AffineExpr AffineBinaryOpExpr::getLHS() const { diff --git a/mlir/lib/IR/AffineMap.cpp b/mlir/lib/IR/AffineMap.cpp index b51636091aad15..9455b9de31996e 100644 --- a/mlir/lib/IR/AffineMap.cpp +++ b/mlir/lib/IR/AffineMap.cpp @@ -305,10 +305,35 @@ AffineMap AffineMap::replaceDimsAndSymbols(ArrayRef dimReplacements, for (auto expr : getResults()) results.push_back( expr.replaceDimsAndSymbols(dimReplacements, symReplacements)); - return get(numResultDims, numResultSyms, results, getContext()); } +/// Sparse replace method. Apply AffineExpr::replace(`expr`, `replacement`) to +/// each of the results and return a new AffineMap with the new results and +/// with the specified number of dims and symbols. +AffineMap AffineMap::replace(AffineExpr expr, AffineExpr replacement, + unsigned numResultDims, + unsigned numResultSyms) const { + SmallVector newResults; + newResults.reserve(getNumResults()); + for (AffineExpr e : getResults()) + newResults.push_back(e.replace(expr, replacement)); + return AffineMap::get(numResultDims, numResultSyms, newResults, getContext()); +} + +/// Sparse replace method. Apply AffineExpr::replace(`map`) to each of the +/// results and return a new AffineMap with the new results and with the +/// specified number of dims and symbols. +AffineMap AffineMap::replace(const DenseMap &map, + unsigned numResultDims, + unsigned numResultSyms) const { + SmallVector newResults; + newResults.reserve(getNumResults()); + for (AffineExpr e : getResults()) + newResults.push_back(e.replace(map)); + return AffineMap::get(numResultDims, numResultSyms, newResults, getContext()); +} + AffineMap AffineMap::compose(AffineMap map) { assert(getNumDims() == map.getNumResults() && "Number of results mismatch"); // Prepare `map` by concatenating the symbols and rewriting its exprs. diff --git a/mlir/test/Dialect/Affine/SuperVectorize/normalize_maps.mlir b/mlir/test/Dialect/Affine/SuperVectorize/normalize_maps.mlir deleted file mode 100644 index 0c01899133ff6f..00000000000000 --- a/mlir/test/Dialect/Affine/SuperVectorize/normalize_maps.mlir +++ /dev/null @@ -1,58 +0,0 @@ -// RUN: mlir-opt %s -affine-super-vectorizer-test -normalize-maps | FileCheck %s - -// CHECK-DAG: #[[$ZERO:[a-zA-Z0-9]+]] = affine_map<() -> (0)> -// CHECK-DAG: #[[$ID1:[a-zA-Z0-9]+]] = affine_map<(d0) -> (d0)> -// CHECK-DAG: #[[$D0TIMES2:[a-zA-Z0-9]+]] = affine_map<(d0) -> (d0 * 2)> -// CHECK-DAG: #[[$D0PLUSD1:[a-zA-Z0-9]+]] = affine_map<(d0, d1) -> (d0 + d1)> -// CHECK-DAG: #[[$MINSD0PLUSD1:[a-zA-Z0-9]+]] = affine_map<(d0, d1) -> (-d0 + d1)> -// CHECK-DAG: #[[$D0MINUSD1:[a-zA-Z0-9]+]] = affine_map<(d0, d1) -> (d0 - d1)> - -// CHECK-LABEL: func @simple() -func @simple() { - affine.for %i0 = 0 to 7 { - %0 = affine.apply affine_map<(d0) -> (d0)> (%i0) - %1 = affine.apply affine_map<(d0) -> (d0)> (%0) - %2 = affine.apply affine_map<(d0, d1) -> (d0 + d1)> (%0, %0) - %3 = affine.apply affine_map<(d0, d1) -> (d0 - d1)> (%0, %0) - } - // CHECK-NEXT: affine.for %{{.*}} = 0 to 7 - // CHECK-NEXT: {{.*}} affine.apply #[[$ID1]](%{{.*}}) - // CHECK-NEXT: {{.*}} affine.apply #[[$D0TIMES2]](%{{.*}}) - // CHECK-NEXT: {{.*}} affine.apply #[[$ZERO]]() - - affine.for %i1 = 0 to 7 { - affine.for %i2 = 0 to 42 { - %20 = affine.apply affine_map<(d0, d1) -> (d1)> (%i1, %i2) - %21 = affine.apply affine_map<(d0, d1) -> (d0)> (%i1, %i2) - %22 = affine.apply affine_map<(d0, d1) -> (d0 + d1)> (%20, %21) - %23 = affine.apply affine_map<(d0, d1) -> (d0 - d1)> (%20, %21) - %24 = affine.apply affine_map<(d0, d1) -> (-d0 + d1)> (%20, %21) - } - } - // CHECK: affine.for %{{.*}} = 0 to 7 - // CHECK-NEXT: affine.for %{{.*}} = 0 to 42 - // CHECK-NEXT: {{.*}} affine.apply #[[$D0PLUSD1]](%{{.*}}, %{{.*}}) - // CHECK-NEXT: {{.*}} affine.apply #[[$MINSD0PLUSD1]](%{{.*}}, %{{.*}}) - // CHECK-NEXT: {{.*}} affine.apply #[[$D0MINUSD1]](%{{.*}}, %{{.*}}) - - affine.for %i3 = 0 to 16 { - affine.for %i4 = 0 to 47 step 2 { - affine.for %i5 = 0 to 78 step 16 { - %50 = affine.apply affine_map<(d0) -> (d0)> (%i3) - %51 = affine.apply affine_map<(d0) -> (d0)> (%i4) - %52 = affine.apply affine_map<(d0) -> (d0)> (%i5) - %53 = affine.apply affine_map<(d0, d1, d2) -> (d0)> (%50, %51, %52) - %54 = affine.apply affine_map<(d0, d1, d2) -> (d1)> (%50, %51, %52) - %55 = affine.apply affine_map<(d0, d1, d2) -> (d2)> (%50, %51, %52) - } - } - } - // CHECK: affine.for %{{.*}} = 0 to 16 - // CHECK-NEXT: affine.for %{{.*}} = 0 to 47 step 2 - // CHECK-NEXT: affine.for %{{.*}} = 0 to 78 step 16 - // CHECK-NEXT: {{.*}} affine.apply #[[$ID1]](%{{.*}}) - // CHECK-NEXT: {{.*}} affine.apply #[[$ID1]](%{{.*}}) - // CHECK-NEXT: {{.*}} affine.apply #[[$ID1]](%{{.*}}) - - return -} diff --git a/mlir/test/Dialect/Affine/affine-data-copy.mlir b/mlir/test/Dialect/Affine/affine-data-copy.mlir index 694615ecb1c257..697196561b159d 100644 --- a/mlir/test/Dialect/Affine/affine-data-copy.mlir +++ b/mlir/test/Dialect/Affine/affine-data-copy.mlir @@ -55,7 +55,7 @@ func @matmul(%A: memref<4096x4096xf32>, %B: memref<4096x4096xf32>, %C: memref<40 // CHECK: affine.for %[[II:.*]] = #[[$MAP_IDENTITY]](%{{.*}}) to #[[$MAP_PLUS_128]](%{{.*}}) { // CHECK: affine.for %[[JJ:.*]] = #[[$MAP_IDENTITY]](%{{.*}}) to #[[$MAP_PLUS_128]](%{{.*}}) { // CHECK: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<4096x4096xf32> -// CHECK: affine.store %{{.*}}, [[BUFC]][-%[[I]] + %[[II]], -%[[J]] + %[[JJ]]] : memref<128x128xf32> +// CHECK: affine.store %{{.*}}, [[BUFC]][%[[II]] - %[[I]], %[[JJ]] - %[[J]]] : memref<128x128xf32> // CHECK: } // CHECK: } @@ -65,7 +65,7 @@ func @matmul(%A: memref<4096x4096xf32>, %B: memref<4096x4096xf32>, %C: memref<40 // CHECK: affine.for %[[II:.*]] = #[[$MAP_IDENTITY]](%{{.*}}) to #[[$MAP_PLUS_128]](%{{.*}}) { // CHECK: affine.for %[[KK:.*]] = #[[$MAP_IDENTITY]](%{{.*}}) to #[[$MAP_PLUS_128]](%{{.*}}) { // CHECK: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<4096x4096xf32> -// CHECK: affine.store %{{.*}}, [[BUFA]][-%[[I]] + %[[II]], -%[[K]] + %[[KK]]] : memref<128x128xf32> +// CHECK: affine.store %{{.*}}, [[BUFA]][%[[II]] - %[[I]], %[[KK]] - %[[K]]] : memref<128x128xf32> // CHECK: } // CHECK: } @@ -74,7 +74,7 @@ func @matmul(%A: memref<4096x4096xf32>, %B: memref<4096x4096xf32>, %C: memref<40 // CHECK: affine.for %[[KK:.*]] = #[[$MAP_IDENTITY]](%{{.*}}) to #[[$MAP_PLUS_128]](%{{.*}}) { // CHECK: affine.for %[[JJ:.*]] = #[[$MAP_IDENTITY]](%{{.*}}) to #[[$MAP_PLUS_128]](%{{.*}}) { // CHECK: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<4096x4096xf32> -// CHECK: affine.store %{{.*}}, [[BUFB]][-%[[K]] + %[[KK]], -%[[J]] + %[[JJ]]] : memref<128x128xf32> +// CHECK: affine.store %{{.*}}, [[BUFB]][%[[KK]] - %[[K]], %[[JJ]] - %[[J]]] : memref<128x128xf32> // CHECK: } // CHECK: } @@ -98,7 +98,7 @@ func @matmul(%A: memref<4096x4096xf32>, %B: memref<4096x4096xf32>, %C: memref<40 // Result matrix copy out. // CHECK: affine.for %{{.*}} = #[[$MAP_IDENTITY]](%{{.*}}) to #[[$MAP_PLUS_128]](%{{.*}}) { // CHECK: affine.for %{{.*}} = #[[$MAP_IDENTITY]](%{{.*}}) to #[[$MAP_PLUS_128]](%{{.*}}) { -// CHECK: affine.load [[BUFC]][-%{{.*}} + %{{.*}}, -%{{.*}} + %{{.*}}] : memref<128x128xf32> +// CHECK: affine.load [[BUFC]][%{{.*}} - %{{.*}}, %{{.*}} - %{{.*}}] : memref<128x128xf32> // CHECK: store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<4096x4096xf32> // CHECK: } // CHECK: } @@ -219,7 +219,7 @@ func @min_upper_bound(%A: memref<4096xf32>) -> memref<4096xf32> { // CHECK: %[[BUF:.*]] = alloc() : memref<100xf32> // CHECK-NEXT: affine.for %[[IV2:.*]] = #[[$MAP_IDENTITY]](%[[IV1]]) to min #[[$MAP_MIN_UB1]](%[[IV1]]) { // CHECK-NEXT: affine.load %{{.*}}[%[[IV2]]] : memref<4096xf32> -// CHECK-NEXT: affine.store %{{.*}}, %[[BUF]][-%[[IV1]] + %[[IV2]]] : memref<100xf32> +// CHECK-NEXT: affine.store %{{.*}}, %[[BUF]][%[[IV2]] - %[[IV1]]] : memref<100xf32> // CHECK-NEXT: } // CHECK-NEXT: affine.for %[[IV2:.*]] = #[[$MAP_IDENTITY]](%[[IV1]]) to min #[[$MAP_MIN_UB2]](%[[IV1]]) { // CHECK-NEXT: affine.load %[[BUF]][-%[[IV1]] + %[[IV2]]] : memref<100xf32> @@ -227,7 +227,7 @@ func @min_upper_bound(%A: memref<4096xf32>) -> memref<4096xf32> { // CHECK-NEXT: affine.store %{{.*}}, %[[BUF]][-%[[IV1]] + %[[IV2]]] : memref<100xf32> // CHECK-NEXT: } // CHECK: affine.for %[[IV2:.*]] = #[[$MAP_IDENTITY]](%[[IV1]]) to min #[[$MAP_MIN_UB1]](%[[IV1]]) { -// CHECK-NEXT: affine.load %[[BUF]][-%[[IV1]] + %[[IV2]]] : memref<100xf32> +// CHECK-NEXT: affine.load %[[BUF]][%[[IV2]] - %[[IV1]]] : memref<100xf32> // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%[[IV2]]] : memref<4096xf32> // CHECK-NEXT: } // CHECK-NEXT: dealloc %[[BUF]] : memref<100xf32> diff --git a/mlir/test/Dialect/Affine/canonicalize.mlir b/mlir/test/Dialect/Affine/canonicalize.mlir index b185e1c8b70740..352066adbbd81b 100644 --- a/mlir/test/Dialect/Affine/canonicalize.mlir +++ b/mlir/test/Dialect/Affine/canonicalize.mlir @@ -1,49 +1,9 @@ // RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -pass-pipeline='func(canonicalize)' | FileCheck %s -// Affine maps for test case: compose_affine_maps_1dto2d_no_symbols -// CHECK-DAG: [[$MAP0:#map[0-9]+]] = affine_map<(d0) -> (d0 - 1)> -// CHECK-DAG: [[$MAP1:#map[0-9]+]] = affine_map<(d0) -> (d0 + 1)> - -// Affine maps for test case: compose_affine_maps_1dto2d_with_symbols -// CHECK-DAG: [[$MAP4:#map[0-9]+]] = affine_map<(d0) -> (d0 - 4)> -// CHECK-DAG: [[$MAP4b:#map[0-9]+]] = affine_map<(d0) -> (d0 - 7)> -// CHECK-DAG: [[$MAP7:#map[0-9]+]] = affine_map<(d0) -> (d0 * 2 - 3)> -// CHECK-DAG: [[$MAP7a:#map[0-9]+]] = affine_map<(d0) -> (d0 * 2 + 1)> - -// Affine map for test case: compose_affine_maps_d2_tile -// CHECK-DAG: [[$MAP8:#map[0-9]+]] = affine_map<(d0, d1) -> (d1 + (d0 ceildiv 4) * 4 - (d1 floordiv 4) * 4)> -// CHECK-DAG: [[$MAP8a:#map[0-9]+]] = affine_map<(d0, d1) -> (d1 + (d0 ceildiv 8) * 8 - (d1 floordiv 8) * 8)> - -// Affine maps for test case: compose_affine_maps_dependent_loads -// CHECK-DAG: [[$MAP9:#map[0-9]+]] = affine_map<(d0) -> (d0 + 3)> -// CHECK-DAG: [[$MAP10:#map[0-9]+]] = affine_map<(d0) -> (d0 * 3)> -// CHECK-DAG: [[$MAP11:#map[0-9]+]] = affine_map<(d0) -> ((d0 + 3) ceildiv 3)> -// CHECK-DAG: [[$MAP12:#map[0-9]+]] = affine_map<(d0) -> (d0 * 7 - 49)> - -// Affine maps for test case: compose_affine_maps_diamond_dependency -// CHECK-DAG: [[$MAP13A:#map[0-9]+]] = affine_map<(d0) -> ((d0 + 6) ceildiv 8)> -// CHECK-DAG: [[$MAP13B:#map[0-9]+]] = affine_map<(d0) -> ((d0 * 4 - 4) floordiv 3)> - -// Affine maps for test case: compose_affine_maps_multiple_symbols -// CHECK-DAG: [[$MAP14:#map[0-9]+]] = affine_map<()[s0, s1] -> (((s1 + s0) * 4) floordiv s0)> - -// Affine maps for test case: partial_fold_map -// CHECK-DAG: [[$MAP15:#map[0-9]+]] = affine_map<()[s0] -> (s0 - 42)> - -// Affine maps for test cases: symbolic_composition_* -// CHECK-DAG: [[$MAP_symbolic_composition_a:#map[0-9]+]] = affine_map<()[s0] -> (s0 * 512)> -// CHECK-DAG: [[$MAP_symbolic_composition_b:#map[0-9]+]] = affine_map<()[s0] -> (s0 * 4)> -// CHECK-DAG: [[$MAP_symbolic_composition_c:#map[0-9]+]] = affine_map<()[s0, s1] -> (s0 * 3 + s1)> -// CHECK-DAG: [[$MAP_symbolic_composition_d:#map[0-9]+]] = affine_map<()[s0, s1] -> (s1 * 3 + s0)> - -// Affine maps for test cases: map_mix_dims_and_symbols_* -// CHECK-DAG: [[$MAP_mix_dims_and_symbols_b:#map[0-9]+]] = affine_map<()[s0, s1] -> (s1 + s0 * 42 + 6)> -// CHECK-DAG: [[$MAP_mix_dims_and_symbols_c:#map[0-9]+]] = affine_map<()[s0, s1] -> (s1 * 4 + s0 * 168 - 4)> -// CHECK-DAG: [[$MAP_mix_dims_and_symbols_d:#map[0-9]+]] = affine_map<()[s0, s1] -> ((s1 + s0 * 42 + 6) ceildiv 8)> -// CHECK-DAG: [[$MAP_mix_dims_and_symbols_e:#map[0-9]+]] = affine_map<()[s0, s1] -> ((s1 * 4 + s0 * 168 - 4) floordiv 3)> - -// Affine maps for test case: $symbolic_semi_affine -// CHECK-DAG: [[$symbolic_semi_affine:#map[0-9]+]] = affine_map<(d0)[s0] -> (d0 floordiv (s0 + 1))> +// ----- + +// CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0) -> (d0 - 1)> +// CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0) -> (d0 + 1)> // CHECK-LABEL: func @compose_affine_maps_1dto2d_no_symbols() { func @compose_affine_maps_1dto2d_no_symbols() { @@ -56,8 +16,8 @@ func @compose_affine_maps_1dto2d_no_symbols() { %x1_0 = affine.apply affine_map<(d0, d1) -> (d0)> (%x0, %x0) %x1_1 = affine.apply affine_map<(d0, d1) -> (d1)> (%x0, %x0) - // CHECK: [[I0A:%[0-9]+]] = affine.apply [[$MAP0]](%{{.*}}) - // CHECK-NEXT: [[V0:%[0-9]+]] = load %0{{\[}}[[I0A]], [[I0A]]{{\]}} + // CHECK: %[[I0A:.*]] = affine.apply #[[$MAP0]](%{{.*}}) + // CHECK-NEXT: %[[V0:.*]] = load %0[%[[I0A]], %[[I0A]]] %v0 = load %0[%x1_0, %x1_1] : memref<4x4xf32> // Test store[%y, %y] @@ -65,26 +25,32 @@ func @compose_affine_maps_1dto2d_no_symbols() { %y1_0 = affine.apply affine_map<(d0, d1) -> (d0)> (%y0, %y0) %y1_1 = affine.apply affine_map<(d0, d1) -> (d1)> (%y0, %y0) - // CHECK-NEXT: [[I1A:%[0-9]+]] = affine.apply [[$MAP1]](%{{.*}}) - // CHECK-NEXT: store [[V0]], %0{{\[}}[[I1A]], [[I1A]]{{\]}} + // CHECK-NEXT: %[[I1A:.*]] = affine.apply #[[$MAP1]](%{{.*}}) + // CHECK-NEXT: store %[[V0]], %0[%[[I1A]], %[[I1A]]] store %v0, %0[%y1_0, %y1_1] : memref<4x4xf32> // Test store[%x, %y] %xy_0 = affine.apply affine_map<(d0, d1) -> (d0)> (%x0, %y0) %xy_1 = affine.apply affine_map<(d0, d1) -> (d1)> (%x0, %y0) - // CHECK-NEXT: store [[V0]], %0{{\[}}[[I0A]], [[I1A]]{{\]}} + // CHECK-NEXT: store %[[V0]], %0[%[[I0A]], %[[I1A]]] store %v0, %0[%xy_0, %xy_1] : memref<4x4xf32> // Test store[%y, %x] %yx_0 = affine.apply affine_map<(d0, d1) -> (d0)> (%y0, %x0) %yx_1 = affine.apply affine_map<(d0, d1) -> (d1)> (%y0, %x0) - // CHECK-NEXT: store [[V0]], %0{{\[}}[[I1A]], [[I0A]]{{\]}} + // CHECK-NEXT: store %[[V0]], %0[%[[I1A]], %[[I0A]]] store %v0, %0[%yx_0, %yx_1] : memref<4x4xf32> } return } +// ----- + +// CHECK-DAG: #[[$MAP4:.*]] = affine_map<(d0) -> (d0 - 4)> +// CHECK-DAG: #[[$MAP7:.*]] = affine_map<(d0) -> (d0 * 2 - 3)> +// CHECK-DAG: #[[$MAP7a:.*]] = affine_map<(d0) -> (d0 * 2 + 1)> + // CHECK-LABEL: func @compose_affine_maps_1dto2d_with_symbols() { func @compose_affine_maps_1dto2d_with_symbols() { %0 = alloc() : memref<4x4xf32> @@ -94,34 +60,39 @@ func @compose_affine_maps_1dto2d_with_symbols() { %c4 = constant 4 : index %x0 = affine.apply affine_map<(d0)[s0] -> (d0 - s0)> (%i0)[%c4] - // CHECK: [[I0:%[0-9]+]] = affine.apply [[$MAP4]](%{{.*}}) - // CHECK-NEXT: [[V0:%[0-9]+]] = load %{{[0-9]+}}{{\[}}[[I0]], [[I0]]{{\]}} + // CHECK: %[[I0:.*]] = affine.apply #[[$MAP4]](%{{.*}}) + // CHECK-NEXT: %[[V0:.*]] = load %{{.*}}[%[[I0]], %[[I0]]] %v0 = load %0[%x0, %x0] : memref<4x4xf32> // Test load[%x0, %x1] with symbol %c4 captured by '%x0' map. %x1 = affine.apply affine_map<(d0) -> (d0 + 1)> (%i0) %y1 = affine.apply affine_map<(d0, d1) -> (d0+d1)> (%x0, %x1) - // CHECK-NEXT: [[I1:%[0-9]+]] = affine.apply [[$MAP7]](%{{.*}}) - // CHECK-NEXT: store [[V0]], %{{[0-9]+}}{{\[}}[[I1]], [[I1]]{{\]}} + // CHECK-NEXT: %[[I1:.*]] = affine.apply #[[$MAP7]](%{{.*}}) + // CHECK-NEXT: store %[[V0]], %{{.*}}[%[[I1]], %[[I1]]] store %v0, %0[%y1, %y1] : memref<4x4xf32> // Test store[%x1, %x0] with symbol %c4 captured by '%x0' map. %y2 = affine.apply affine_map<(d0, d1) -> (d0 + d1)> (%x1, %x0) - // CHECK-NEXT: [[I2:%[0-9]+]] = affine.apply [[$MAP7]](%{{.*}}) - // CHECK-NEXT: store [[V0]], %{{[0-9]+}}{{\[}}[[I2]], [[I2]]{{\]}} + // CHECK-NEXT: %[[I2:.*]] = affine.apply #[[$MAP7]](%{{.*}}) + // CHECK-NEXT: store %[[V0]], %{{.*}}[%[[I2]], %[[I2]]] store %v0, %0[%y2, %y2] : memref<4x4xf32> // Test store[%x2, %x0] with symbol %c4 from '%x0' and %c5 from '%x2' %c5 = constant 5 : index %x2 = affine.apply affine_map<(d0)[s0] -> (d0 + s0)> (%i0)[%c5] %y3 = affine.apply affine_map<(d0, d1) -> (d0 + d1)> (%x2, %x0) - // CHECK: [[I3:%[0-9]+]] = affine.apply [[$MAP7a]](%{{.*}}) - // CHECK-NEXT: store [[V0]], %{{[0-9]+}}{{\[}}[[I3]], [[I3]]{{\]}} + // CHECK: %[[I3:.*]] = affine.apply #[[$MAP7a]](%{{.*}}) + // CHECK-NEXT: store %[[V0]], %{{.*}}[%[[I3]], %[[I3]]] store %v0, %0[%y3, %y3] : memref<4x4xf32> } return } +// ----- + +// CHECK-DAG: #[[$MAP8:.*]] = affine_map<(d0, d1) -> (d1 + (d0 ceildiv 4) * 4 - (d1 floordiv 4) * 4)> +// CHECK-DAG: #[[$MAP8a:.*]] = affine_map<(d0, d1) -> (d1 + (d0 ceildiv 8) * 8 - (d1 floordiv 8) * 8)> + // CHECK-LABEL: func @compose_affine_maps_2d_tile() { func @compose_affine_maps_2d_tile() { %0 = alloc() : memref<16x32xf32> @@ -143,12 +114,12 @@ func @compose_affine_maps_2d_tile() { ((d0 * s0) + d2)> (%x0, %x1, %x2, %x3)[%c4, %c8] %x41 = affine.apply affine_map<(d0, d1, d2, d3)[s0, s1] -> ((d1 * s1) + d3)> (%x0, %x1, %x2, %x3)[%c4, %c8] - // CHECK: [[I0:%[0-9]+]] = affine.apply [[$MAP8]](%{{.*}}, %{{.*}}) - // CHECK: [[I1:%[0-9]+]] = affine.apply [[$MAP8a]](%{{.*}}, %{{.*}}) - // CHECK-NEXT: [[L0:%[0-9]+]] = load %{{[0-9]+}}{{\[}}[[I0]], [[I1]]{{\]}} + // CHECK: %[[I0:.*]] = affine.apply #[[$MAP8]](%{{.*}}, %{{.*}}) + // CHECK: %[[I1:.*]] = affine.apply #[[$MAP8a]](%{{.*}}, %{{.*}}) + // CHECK-NEXT: %[[L0:.*]] = load %{{.*}}[%[[I0]], %[[I1]]] %v0 = load %0[%x40, %x41] : memref<16x32xf32> - // CHECK-NEXT: store [[L0]], %{{[0-9]+}}{{\[}}[[I0]], [[I1]]{{\]}} + // CHECK-NEXT: store %[[L0]], %{{.*}}[%[[I0]], %[[I1]]] store %v0, %1[%x40, %x41] : memref<16x32xf32> } } @@ -157,6 +128,14 @@ func @compose_affine_maps_2d_tile() { return } +// ----- + +// CHECK-DAG: #[[$MAP4b:.*]] = affine_map<(d0) -> (d0 - 7)> +// CHECK-DAG: #[[$MAP9:.*]] = affine_map<(d0) -> (d0 + 3)> +// CHECK-DAG: #[[$MAP10:.*]] = affine_map<(d0) -> (d0 * 3)> +// CHECK-DAG: #[[$MAP11:.*]] = affine_map<(d0) -> ((d0 + 3) ceildiv 3)> +// CHECK-DAG: #[[$MAP12:.*]] = affine_map<(d0) -> (d0 * 7 - 49)> + // CHECK-LABEL: func @compose_affine_maps_dependent_loads() { func @compose_affine_maps_dependent_loads() { %0 = alloc() : memref<16x32xf32> @@ -175,17 +154,17 @@ func @compose_affine_maps_dependent_loads() { %x02 = affine.apply affine_map<(d0, d1, d2)[s0, s1] -> (d2 * s0)> (%i0, %i1, %i2)[%c3, %c7] - // CHECK: [[I0:%[0-9]+]] = affine.apply [[$MAP9]](%{{.*}}) - // CHECK: [[I1:%[0-9]+]] = affine.apply [[$MAP4b]](%{{.*}}) - // CHECK: [[I2:%[0-9]+]] = affine.apply [[$MAP10]](%{{.*}}) - // CHECK-NEXT: [[V0:%[0-9]+]] = load %{{[0-9]+}}{{\[}}[[I0]], [[I1]]{{\]}} + // CHECK: %[[I0:.*]] = affine.apply #[[$MAP9]](%{{.*}}) + // CHECK: %[[I1:.*]] = affine.apply #[[$MAP4b]](%{{.*}}) + // CHECK: %[[I2:.*]] = affine.apply #[[$MAP10]](%{{.*}}) + // CHECK-NEXT: %[[V0:.*]] = load %{{.*}}[%[[I0]], %[[I1]]] %v0 = load %0[%x00, %x01] : memref<16x32xf32> - // CHECK-NEXT: store [[V0]], %{{[0-9]+}}{{\[}}[[I0]], [[I2]]{{\]}} + // CHECK-NEXT: store %[[V0]], %{{.*}}[%[[I0]], %[[I2]]] store %v0, %0[%x00, %x02] : memref<16x32xf32> // Swizzle %i0, %i1 - // CHECK-NEXT: store [[V0]], %{{[0-9]+}}{{\[}}[[I1]], [[I0]]{{\]}} + // CHECK-NEXT: store %[[V0]], %{{.*}}[%[[I1]], %[[I0]]] store %v0, %0[%x01, %x00] : memref<16x32xf32> // Swizzle %x00, %x01 and %c3, %c7 @@ -194,9 +173,9 @@ func @compose_affine_maps_dependent_loads() { %x11 = affine.apply affine_map<(d0, d1)[s0, s1] -> (d1 ceildiv s0)> (%x01, %x00)[%c3, %c7] - // CHECK-NEXT: [[I2A:%[0-9]+]] = affine.apply [[$MAP12]](%{{.*}}) - // CHECK-NEXT: [[I2B:%[0-9]+]] = affine.apply [[$MAP11]](%{{.*}}) - // CHECK-NEXT: store [[V0]], %{{[0-9]+}}{{\[}}[[I2A]], [[I2B]]{{\]}} + // CHECK-NEXT: %[[I2A:.*]] = affine.apply #[[$MAP12]](%{{.*}}) + // CHECK-NEXT: %[[I2B:.*]] = affine.apply #[[$MAP11]](%{{.*}}) + // CHECK-NEXT: store %[[V0]], %{{.*}}[%[[I2A]], %[[I2B]]] store %v0, %0[%x10, %x11] : memref<16x32xf32> } } @@ -204,6 +183,11 @@ func @compose_affine_maps_dependent_loads() { return } +// ----- + +// CHECK-DAG: #[[$MAP13A:.*]] = affine_map<(d0) -> ((d0 + 6) ceildiv 8)> +// CHECK-DAG: #[[$MAP13B:.*]] = affine_map<(d0) -> ((d0 * 4 - 4) floordiv 3)> + // CHECK-LABEL: func @compose_affine_maps_diamond_dependency func @compose_affine_maps_diamond_dependency(%arg0: f32, %arg1: memref<4x4xf32>) { affine.for %i0 = 0 to 15 { @@ -212,24 +196,30 @@ func @compose_affine_maps_diamond_dependency(%arg0: f32, %arg1: memref<4x4xf32>) %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a) %d0 = affine.apply affine_map<(d0, d1) -> (d0 ceildiv 8)> (%b, %c) %d1 = affine.apply affine_map<(d0, d1) -> (d1 floordiv 3)> (%b, %c) - // CHECK: [[I0:%[0-9]+]] = affine.apply [[$MAP13A]](%{{.*}}) - // CHECK: [[I1:%[0-9]+]] = affine.apply [[$MAP13B]](%{{.*}}) - // CHECK-NEXT: store %arg0, %arg1{{\[}}[[I0]], [[I1]]{{\]}} + // CHECK: %[[I0:.*]] = affine.apply #[[$MAP13A]](%{{.*}}) + // CHECK: %[[I1:.*]] = affine.apply #[[$MAP13B]](%{{.*}}) + // CHECK-NEXT: store %arg0, %arg1[%[[I0]], %[[I1]]] store %arg0, %arg1[%d0, %d1] : memref<4x4xf32> } return } +// ----- + +// CHECK-DAG: #[[$MAP14:.*]] = affine_map<()[s0, s1] -> (((s1 + s0) * 4) floordiv s0)> + // CHECK-LABEL: func @compose_affine_maps_multiple_symbols func @compose_affine_maps_multiple_symbols(%arg0: index, %arg1: index) -> index { %a = affine.apply affine_map<(d0)[s0] -> (s0 + d0)> (%arg0)[%arg1] %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a) %e = affine.apply affine_map<(d0)[s0] -> (d0 floordiv s0)> (%c)[%arg1] - // CHECK: [[I0:%[0-9]+]] = affine.apply [[$MAP14]]()[%{{.*}}, %{{.*}}] + // CHECK: [[I0:.*]] = affine.apply #[[$MAP14]]()[%{{.*}}, %{{.*}}] return %e : index } +// ----- + // CHECK-LABEL: func @arg_used_as_dim_and_symbol func @arg_used_as_dim_and_symbol(%arg0: memref<100x100xf32>, %arg1: index, %arg2: f32) { %c9 = constant 9 : index @@ -241,13 +231,15 @@ func @arg_used_as_dim_and_symbol(%arg0: memref<100x100xf32>, %arg1: index, %arg2 (%i0, %i1)[%arg1, %c9] %4 = affine.apply affine_map<(d0, d1, d3) -> (d3 - (d0 + d1))> (%arg1, %c9, %3) - // CHECK: store %arg2, %{{[0-9]+}}{{\[}}%{{.*}}, %{{.*}}{{\]}} + // CHECK: store %arg2, %{{.*}}[%{{.*}}, %{{.*}}] store %arg2, %1[%4, %arg1] : memref<100x100xf32, 1> } } return } +// ----- + // CHECK-LABEL: func @trivial_maps func @trivial_maps() { // CHECK-NOT: affine.apply @@ -267,79 +259,116 @@ func @trivial_maps() { return } +// ----- + +// CHECK-DAG: #[[$MAP15:.*]] = affine_map<()[s0] -> (s0 - 42)> + // CHECK-LABEL: func @partial_fold_map func @partial_fold_map(%arg1: index, %arg2: index) -> index { // TODO: Constant fold one index into affine.apply %c42 = constant 42 : index %2 = affine.apply affine_map<(d0, d1) -> (d0 - d1)> (%arg1, %c42) - // CHECK: [[X:%[0-9]+]] = affine.apply [[$MAP15]]()[%{{.*}}] + // CHECK: [[X:.*]] = affine.apply #[[$MAP15]]()[%{{.*}}] return %2 : index } +// ----- + +// CHECK-DAG: #[[$MAP_symbolic_composition_a:.*]] = affine_map<()[s0] -> (s0 * 512)> + // CHECK-LABEL: func @symbolic_composition_a(%{{.*}}: index, %{{.*}}: index) -> index { func @symbolic_composition_a(%arg0: index, %arg1: index) -> index { %0 = affine.apply affine_map<(d0) -> (d0 * 4)>(%arg0) %1 = affine.apply affine_map<()[s0, s1] -> (8 * s0)>()[%0, %arg0] %2 = affine.apply affine_map<()[s0, s1] -> (16 * s1)>()[%arg1, %1] - // CHECK: %{{.*}} = affine.apply [[$MAP_symbolic_composition_a]]()[%{{.*}}] + // CHECK: %{{.*}} = affine.apply #[[$MAP_symbolic_composition_a]]()[%{{.*}}] return %2 : index } +// ----- + +// CHECK-DAG: #[[$MAP_symbolic_composition_b:.*]] = affine_map<()[s0] -> (s0 * 4)> + // CHECK-LABEL: func @symbolic_composition_b(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index { func @symbolic_composition_b(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index { %0 = affine.apply affine_map<(d0) -> (d0)>(%arg0) %1 = affine.apply affine_map<()[s0, s1, s2, s3] -> (s0 + s1 + s2 + s3)>()[%0, %0, %0, %0] - // CHECK: %{{.*}} = affine.apply [[$MAP_symbolic_composition_b]]()[%{{.*}}] + // CHECK: %{{.*}} = affine.apply #[[$MAP_symbolic_composition_b]]()[%{{.*}}] return %1 : index } +// ----- + +// CHECK-DAG: #[[$MAP_symbolic_composition_c:.*]] = affine_map<()[s0, s1] -> (s0 * 3 + s1)> + // CHECK-LABEL: func @symbolic_composition_c(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index { func @symbolic_composition_c(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index { %0 = affine.apply affine_map<(d0) -> (d0)>(%arg0) %1 = affine.apply affine_map<(d0) -> (d0)>(%arg1) %2 = affine.apply affine_map<()[s0, s1, s2, s3] -> (s0 + s1 + s2 + s3)>()[%0, %0, %0, %1] - // CHECK: %{{.*}} = affine.apply [[$MAP_symbolic_composition_c]]()[%{{.*}}, %{{.*}}] + // CHECK: %{{.*}} = affine.apply #[[$MAP_symbolic_composition_c]]()[%{{.*}}, %{{.*}}] return %2 : index } -// CHECK-LABEL: func @symbolic_composition_d(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index { +// ----- + +// CHECK-DAG: #[[$MAP_symbolic_composition_d:.*]] = affine_map<()[s0, s1] -> (s0 + s1 * 3)> + +// CHECK-LABEL: func @symbolic_composition_d( +// CHECK-SAME: %[[ARG0:[0-9a-zA-Z]+]]: index +// CHECK-SAME: %[[ARG1:[0-9a-zA-Z]+]]: index func @symbolic_composition_d(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index { %0 = affine.apply affine_map<(d0) -> (d0)>(%arg0) %1 = affine.apply affine_map<()[s0] -> (s0)>()[%arg1] %2 = affine.apply affine_map<()[s0, s1, s2, s3] -> (s0 + s1 + s2 + s3)>()[%0, %0, %0, %1] - // CHECK: %{{.*}} = affine.apply [[$MAP_symbolic_composition_d]]()[%{{.*}}, %{{.*}}] + // CHECK: %{{.*}} = affine.apply #[[$MAP_symbolic_composition_d]]()[%[[ARG1]], %[[ARG0]]] return %2 : index } +// ----- + +// CHECK-DAG: #[[$MAP_mix_dims_and_symbols_b:.*]] = affine_map<()[s0, s1] -> (s0 * 42 + s1 + 6)> // CHECK-LABEL: func @mix_dims_and_symbols_b(%arg0: index, %arg1: index) -> index { func @mix_dims_and_symbols_b(%arg0: index, %arg1: index) -> index { %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1] %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a) - // CHECK: {{.*}} = affine.apply [[$MAP_mix_dims_and_symbols_b]]()[%{{.*}}, %{{.*}}] + // CHECK: {{.*}} = affine.apply #[[$MAP_mix_dims_and_symbols_b]]()[%{{.*}}, %{{.*}}] return %b : index } +// ----- + +// CHECK-DAG: #[[$MAP_mix_dims_and_symbols_c:.*]] = affine_map<()[s0, s1] -> (s0 * 168 + s1 * 4 - 4)> + // CHECK-LABEL: func @mix_dims_and_symbols_c(%arg0: index, %arg1: index) -> index { func @mix_dims_and_symbols_c(%arg0: index, %arg1: index) -> index { %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1] %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a) %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a) - // CHECK: {{.*}} = affine.apply [[$MAP_mix_dims_and_symbols_c]]()[%{{.*}}, %{{.*}}] + // CHECK: {{.*}} = affine.apply #[[$MAP_mix_dims_and_symbols_c]]()[%{{.*}}, %{{.*}}] return %c : index } +// ----- + +// CHECK-DAG: #[[$MAP_mix_dims_and_symbols_d:.*]] = affine_map<()[s0, s1] -> ((s0 * 42 + s1 + 6) ceildiv 8)> + // CHECK-LABEL: func @mix_dims_and_symbols_d(%arg0: index, %arg1: index) -> index { func @mix_dims_and_symbols_d(%arg0: index, %arg1: index) -> index { %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1] %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a) %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a) %d = affine.apply affine_map<()[s0] -> (s0 ceildiv 8)> ()[%b] - // CHECK: {{.*}} = affine.apply [[$MAP_mix_dims_and_symbols_d]]()[%{{.*}}, %{{.*}}] + // CHECK: {{.*}} = affine.apply #[[$MAP_mix_dims_and_symbols_d]]()[%{{.*}}, %{{.*}}] return %d : index } +// ----- + +// CHECK-DAG: #[[$MAP_mix_dims_and_symbols_e:.*]] = affine_map<()[s0, s1] -> ((s0 * 168 + s1 * 4 - 4) floordiv 3)> + // CHECK-LABEL: func @mix_dims_and_symbols_e(%arg0: index, %arg1: index) -> index { func @mix_dims_and_symbols_e(%arg0: index, %arg1: index) -> index { %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1] @@ -347,10 +376,12 @@ func @mix_dims_and_symbols_e(%arg0: index, %arg1: index) -> index { %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a) %d = affine.apply affine_map<()[s0] -> (s0 ceildiv 8)> ()[%b] %e = affine.apply affine_map<(d0) -> (d0 floordiv 3)> (%c) - // CHECK: {{.*}} = affine.apply [[$MAP_mix_dims_and_symbols_e]]()[%{{.*}}, %{{.*}}] + // CHECK: {{.*}} = affine.apply #[[$MAP_mix_dims_and_symbols_e]]()[%{{.*}}, %{{.*}}] return %e : index } +// ----- + // CHECK-LABEL: func @mix_dims_and_symbols_f(%arg0: index, %arg1: index) -> index { func @mix_dims_and_symbols_f(%arg0: index, %arg1: index) -> index { %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1] @@ -364,6 +395,10 @@ func @mix_dims_and_symbols_f(%arg0: index, %arg1: index) -> index { return %f : index } +// ----- + +// CHECK-DAG: #[[$MAP_symbolic_composition_b:.*]] = affine_map<()[s0] -> (s0 * 4)> + // CHECK-LABEL: func @mix_dims_and_symbols_g(%arg0: index, %arg1: index) -> (index, index, index) { func @mix_dims_and_symbols_g(%M: index, %N: index) -> (index, index, index) { %K = affine.apply affine_map<(d0) -> (4*d0)> (%M) @@ -371,18 +406,22 @@ func @mix_dims_and_symbols_g(%M: index, %N: index) -> (index, index, index) { %res2 = affine.apply affine_map<()[s0, s1] -> (s1)>()[%N, %K] %res3 = affine.apply affine_map<()[s0, s1] -> (1024)>()[%N, %K] // CHECK-DAG: {{.*}} = constant 1024 : index - // CHECK-DAG: {{.*}} = affine.apply [[$MAP_symbolic_composition_b]]()[%{{.*}}] - // CHECK-DAG: {{.*}} = affine.apply [[$MAP_symbolic_composition_b]]()[%{{.*}}] + // CHECK-DAG: {{.*}} = affine.apply #[[$MAP_symbolic_composition_b]]()[%{{.*}}] + // CHECK-DAG: {{.*}} = affine.apply #[[$MAP_symbolic_composition_b]]()[%{{.*}}] return %res1, %res2, %res3 : index, index, index } +// ----- + +// CHECK-DAG: #[[$symbolic_semi_affine:.*]] = affine_map<(d0)[s0] -> (d0 floordiv (s0 + 1))> + // CHECK-LABEL: func @symbolic_semi_affine(%arg0: index, %arg1: index, %arg2: memref) { func @symbolic_semi_affine(%M: index, %N: index, %A: memref) { %f1 = constant 1.0 : f32 affine.for %i0 = 1 to 100 { %1 = affine.apply affine_map<()[s0] -> (s0 + 1)> ()[%M] %2 = affine.apply affine_map<(d0)[s0] -> (d0 floordiv s0)> (%i0)[%1] - // CHECK-DAG: {{.*}} = affine.apply [[$symbolic_semi_affine]](%{{.*}})[%{{.*}}] + // CHECK-DAG: {{.*}} = affine.apply #[[$symbolic_semi_affine]](%{{.*}})[%{{.*}}] store %f1, %A[%2] : memref } return @@ -390,8 +429,8 @@ func @symbolic_semi_affine(%M: index, %N: index, %A: memref) { // ----- -// CHECK: [[$MAP0:#map[0-9]+]] = affine_map<()[s0] -> (0, s0)> -// CHECK: [[$MAP1:#map[0-9]+]] = affine_map<()[s0] -> (100, s0)> +// CHECK: #[[$MAP0:.*]] = affine_map<()[s0] -> (0, s0)> +// CHECK: #[[$MAP1:.*]] = affine_map<()[s0] -> (100, s0)> // CHECK-LABEL: func @constant_fold_bounds(%arg0: index) { func @constant_fold_bounds(%N : index) { @@ -415,7 +454,7 @@ func @constant_fold_bounds(%N : index) { } // None of the bounds can be folded. - // CHECK: affine.for %{{.*}} = max [[$MAP0]]()[%{{.*}}] to min [[$MAP1]]()[%{{.*}}] { + // CHECK: affine.for %{{.*}} = max #[[$MAP0]]()[%{{.*}}] to min #[[$MAP1]]()[%{{.*}}] { affine.for %k = max affine_map<()[s0] -> (0, s0)> ()[%l] to min affine_map<()[s0] -> (100, s0)> ()[%N] { "foo"(%k, %c3) : (index, index) -> () } @@ -433,20 +472,22 @@ func @fold_empty_loop() { } // CHECK: return + // ----- -// CHECK-DAG: [[$SET:#set[0-9]*]] = affine_set<(d0, d1)[s0] : (d0 >= 0, -d0 + 1022 >= 0, d1 >= 0, -d1 + s0 - 2 >= 0)> +// CHECK-DAG: #[[$SET:.*]] = affine_set<(d0, d1)[s0] : (d0 >= 0, -d0 + 1022 >= 0, d1 >= 0, -d1 + s0 - 2 >= 0)> // CHECK-LABEL: func @canonicalize_affine_if -// CHECK-SAME: [[M:%.*]]: index, -// CHECK-SAME: [[N:%.*]]: index) +// CHECK-SAME: %[[M:[0-9a-zA-Z]*]]: index, +// CHECK-SAME: %[[N:[0-9a-zA-Z]*]]: index) func @canonicalize_affine_if(%M : index, %N : index) { %c1022 = constant 1022 : index // Drop unused operand %M, propagate %c1022, and promote %N to symbolic. affine.for %i = 0 to 1024 { affine.for %j = 0 to %N { - // CHECK: affine.if [[$SET]](%{{.*}}, %{{.*}}){{\[}}[[N]]{{\]}} - affine.if affine_set<(d0, d1, d2, d3)[s0] : (d1 >= 0, d0 - d1 >= 0, d2 >= 0, d3 - d2 - 2 >= 0)> (%c1022, %i, %j, %N)[%M] { + // CHECK: affine.if #[[$SET]](%{{.*}}, %{{.*}})[%[[N]]] + affine.if affine_set<(d0, d1, d2, d3)[s0] : (d1 >= 0, d0 - d1 >= 0, d2 >= 0, d3 - d2 - 2 >= 0)> + (%c1022, %i, %j, %N)[%M] { "foo"() : () -> () } "bar"() : () -> () @@ -457,28 +498,28 @@ func @canonicalize_affine_if(%M : index, %N : index) { // ----- -// CHECK-DAG: [[$LBMAP:#map[0-9]+]] = affine_map<()[s0] -> (0, s0)> -// CHECK-DAG: [[$UBMAP:#map[0-9]+]] = affine_map<()[s0] -> (1024, s0 * 2)> +// CHECK-DAG: #[[$LBMAP:.*]] = affine_map<()[s0] -> (0, s0)> +// CHECK-DAG: #[[$UBMAP:.*]] = affine_map<()[s0] -> (1024, s0 * 2)> // CHECK-LABEL: func @canonicalize_bounds -// CHECK-SAME: [[M:%.*]]: index, -// CHECK-SAME: [[N:%.*]]: index) +// CHECK-SAME: %[[M:.*]]: index, +// CHECK-SAME: %[[N:.*]]: index) func @canonicalize_bounds(%M : index, %N : index) { %c0 = constant 0 : index %c1024 = constant 1024 : index // Drop unused operand %N, drop duplicate operand %M, propagate %c1024, and // promote %M to a symbolic one. - // CHECK: affine.for %{{.*}} = 0 to min [[$UBMAP]](){{\[}}[[M]]{{\]}} + // CHECK: affine.for %{{.*}} = 0 to min #[[$UBMAP]]()[%[[M]]] affine.for %i = 0 to min affine_map<(d0, d1, d2, d3) -> (d0, d1 + d2)> (%c1024, %M, %M, %N) { "foo"() : () -> () } // Promote %M to symbolic position. - // CHECK: affine.for %{{.*}} = 0 to #map{{[0-9]+}}(){{\[}}[[M]]{{\]}} + // CHECK: affine.for %{{.*}} = 0 to #{{.*}}()[%[[M]]] affine.for %i = 0 to affine_map<(d0) -> (4 * d0)> (%M) { "foo"() : () -> () } // Lower bound canonicalize. - // CHECK: affine.for %{{.*}} = max [[$LBMAP]](){{\[}}[[N]]{{\]}} to [[M]] + // CHECK: affine.for %{{.*}} = max #[[$LBMAP]]()[%[[N]]] to %[[M]] affine.for %i = max affine_map<(d0, d1) -> (d0, d1)> (%c0, %N) to %M { "foo"() : () -> () } @@ -588,7 +629,7 @@ func @affine_min(%arg0: index) { #map1 = affine_map<(d0)[s0, s1] -> (d0 * s0 + s1)> #map2 = affine_map<(d0)[s0] -> (1024, -d0 + s0)> -// CHECK: #[[$MAP:.*]] = affine_map<()[s0, s1] -> (1024, s1 * -1024 + s0)> +// CHECK: #[[$MAP:.*]] = affine_map<()[s0, s1] -> (1024, s0 - s1 * 1024)> // CHECK: func @rep(%[[ARG0:.*]]: index, %[[ARG1:.*]]: index) func @rep(%arg0 : index, %arg1 : index) -> index { @@ -637,3 +678,19 @@ func @affine_parallel_const_bounds() { } return } + +// ----- + +func @compose_affine_maps_div_symbol(%A : memref, %i0 : index, %i1 : index) { + %0 = affine.apply affine_map<()[s0] -> (2 * s0)> ()[%i0] + %1 = affine.apply affine_map<()[s0] -> (3 * s0)> ()[%i0] + %2 = affine.apply affine_map<(d0)[s0, s1] -> (d0 mod s1 + s0 * s1 + s0 * 4)> (%i1)[%0, %1] + %3 = index_cast %2: index to i64 + store %3, %A[]: memref + affine.for %i2 = 0 to 3 { + %4 = affine.apply affine_map<(d0)[s0, s1] -> (d0 ceildiv s1 + s0 + s0 * 3)> (%i2)[%0, %1] + %5 = index_cast %4: index to i64 + store %5, %A[]: memref + } + return +} diff --git a/mlir/test/Dialect/Linalg/reshape_fusion.mlir b/mlir/test/Dialect/Linalg/reshape_fusion.mlir index c8c3c12a3ea4e9..447917548c5cbf 100644 --- a/mlir/test/Dialect/Linalg/reshape_fusion.mlir +++ b/mlir/test/Dialect/Linalg/reshape_fusion.mlir @@ -254,7 +254,7 @@ func @indexed_generic_op_reshape_producer_fusion(%arg0 : tensor, // The generic op version of the test check for the op structure. Only // checking the op body here. -// CHECK: #[[MAP:.+]] = affine_map<(d0, d1) -> (d0 * 4 + d1)> +// CHECK: #[[MAP:.+]] = affine_map<(d0, d1) -> (d0 + d1 * 4)> // CHECK: func @indexed_generic_op_reshape_producer_fusion // CHECK: linalg.indexed_generic // CHECK: ^{{.*}}( @@ -262,7 +262,7 @@ func @indexed_generic_op_reshape_producer_fusion(%arg0 : tensor, // CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index, %[[ARG5:[a-zA-Z0-9]+]]: index, // CHECK-SAME: %[[ARG6:[a-zA-Z0-9]+]]: i32, %[[ARG7:[a-zA-Z0-9]+]]: i32, // CHECK-SAME: %[[ARG8:[a-zA-Z0-9]+]]: i32) -// CHECK: %[[T3:.+]] = affine.apply #[[MAP]](%[[ARG2]], %[[ARG3]]) +// CHECK: %[[T3:.+]] = affine.apply #[[MAP]](%[[ARG3]], %[[ARG2]]) // CHECK: %[[T4:.+]] = muli %[[ARG6]], %[[ARG7]] // CHECK: %[[T5:.+]] = index_cast %[[T3]] // CHECK: %[[T6:.+]] = addi %[[T4]], %[[T5]] @@ -299,7 +299,7 @@ func @indexed_generic_op_reshape_consumer_fusion(%arg0 : tensor, } // The generic op version of the test check for the op structure. Only // checking the op body here. -// CHECK: #[[MAP:.+]] = affine_map<(d0, d1, d2) -> (d0 * 20 + d1 * 5 + d2)> +// CHECK: #[[MAP:.+]] = affine_map<(d0, d1, d2) -> (d0 + d1 * 5 + d2 * 20)> // CHECK: func @indexed_generic_op_reshape_consumer_fusion // CHECK: linalg.indexed_generic // CHECK: ^{{.*}}( @@ -307,7 +307,7 @@ func @indexed_generic_op_reshape_consumer_fusion(%arg0 : tensor, // CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index, %[[ARG5:[a-zA-Z0-9]+]]: index, // CHECK-SAME: %[[ARG6:[a-zA-Z0-9]+]]: i32, %[[ARG7:[a-zA-Z0-9]+]]: i32, // CHECK-SAME: %[[ARG8:[a-zA-Z0-9]+]]: i32) -// CHECK: %[[T3:.+]] = affine.apply #[[MAP]](%[[ARG3]], %[[ARG4]], %[[ARG5]]) +// CHECK: %[[T3:.+]] = affine.apply #[[MAP]](%[[ARG5]], %[[ARG4]], %[[ARG3]]) // CHECK: %[[T4:.+]] = muli %[[ARG6]], %[[ARG7]] // CHECK: %[[T5:.+]] = index_cast %[[ARG2]] // CHECK: %[[T6:.+]] = addi %[[T4]], %[[T5]] @@ -336,7 +336,7 @@ func @reshape_as_consumer_permutation %5 = addi %3, %4 : i32 %6 = index_cast %arg2 : index to i32 %7 = addi %5, %6 : i32 - linalg.yield %7 : i32 + linalg.yield %7 : i32 } -> tensor<6x4x210xi32> %d = linalg.tensor_reshape %c [affine_map<(d0, d1, d2, d3, d4, d5) -> (d0, d1)>, @@ -358,8 +358,8 @@ func @reshape_as_consumer_permutation // CHECK-DAG: #[[MAP8:.+]] = affine_map<(d0, d1, d2, d3, d4, d5) -> (d2, d3, d4, d0, d1, d5)> // CHECK-DAG: #[[MAP9:.+]] = affine_map<(d0, d1, d2, d3, d4, d5) -> (d2, d3, d4, d5)> // CHECK-DAG: #[[MAP10:.+]] = affine_map<(d0, d1, d2, d3, d4, d5) -> (d0, d1, d5, d2, d3, d4)> -// CHECK-DAG: #[[MAP11:.+]] = affine_map<(d0, d1) -> (d0 * 3 + d1)> -// CHECK-DAG: #[[MAP12:.+]] = affine_map<(d0, d1, d2) -> (d0 * 42 + d1 * 7 + d2)> +// CHECK-DAG: #[[MAP11:.+]] = affine_map<(d0, d1) -> (d0 + d1 * 3)> +// CHECK-DAG: #[[MAP12:.+]] = affine_map<(d0, d1, d2) -> (d0 + d1 * 7 + d2 * 42)> // CHECK: func @reshape_as_consumer_permutation // CHECK-SAME: %[[ARG0:.+]]: tensor<210x6x4xi32> // CHECK-SAME: %[[ARG1:.+]]: tensor<210x4xi32> @@ -380,8 +380,8 @@ func @reshape_as_consumer_permutation // CHECK-SAME: %[[ARG6:[a-zA-Z0-9]+]]: index, %[[ARG7:[a-zA-Z0-9]+]]: index, // CHECK-SAME: %[[ARG8:[a-zA-Z0-9]+]]: i32, %[[ARG9:[a-zA-Z0-9]+]]: i32, // CHECK-SAME: %[[ARG10:[a-zA-Z0-9]+]]: i32) -// CHECK-DAG: %[[T5:.+]] = affine.apply #[[MAP11]](%[[ARG2]], %[[ARG3]]) -// CHECK-DAG: %[[T6:.+]] = affine.apply #[[MAP12]](%[[ARG4]], %[[ARG5]], %[[ARG6]]) +// CHECK-DAG: %[[T5:.+]] = affine.apply #[[MAP11]](%[[ARG3]], %[[ARG2]]) +// CHECK-DAG: %[[T6:.+]] = affine.apply #[[MAP12]](%[[ARG6]], %[[ARG5]], %[[ARG4]]) // CHECK-DAG: %[[T7:.+]] = addi %[[ARG8]], %[[ARG9]] // CHECK: %[[T8:.+]] = index_cast %[[T5]] // CHECK: %[[T9:.+]] = addi %[[T7]], %[[T8]] @@ -418,7 +418,7 @@ func @reshape_as_producer_projected_permutation( // CHECK-DAG: #[[MAP0:.+]] = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2)> // CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> -// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1) -> (d0 * 8 + d1)> +// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1) -> (d0 + d1 * 8)> // CHECK-DAG: #[[MAP3:.+]] = affine_map<(d0, d1, d2, d3) -> (d0, d1)> // CHECK-DAG: #[[MAP4:.+]] = affine_map<(d0, d1, d2, d3) -> (d2)> // CHECK-DAG: #[[MAP5:.+]] = affine_map<(d0, d1, d2, d3) -> (d3)> @@ -434,7 +434,7 @@ func @reshape_as_producer_projected_permutation( // CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index, // CHECK-SAME: %[[ARG5:[a-zA-Z0-9]+]]: i32, // CHECK-SAME: %[[ARG7:[a-zA-Z0-9]+]]: i32) -// CHECK: %[[T0:.+]] = affine.apply #[[MAP2]](%[[ARG1]], %[[ARG2]]) +// CHECK: %[[T0:.+]] = affine.apply #[[MAP2]](%[[ARG2]], %[[ARG1]]) // CHECK: %[[T1:.+]] = index_cast %[[T0]] : index to i32 // CHECK: %[[T2:.+]] = addi %[[ARG5]], %[[T1]] : i32 // CHECK: %[[T3:.+]] = index_cast %[[ARG3]] : index to i32 diff --git a/mlir/test/EDSC/builder-api-test.cpp b/mlir/test/EDSC/builder-api-test.cpp index 241cc1a5ebadb6..064cc59c6f5060 100644 --- a/mlir/test/EDSC/builder-api-test.cpp +++ b/mlir/test/EDSC/builder-api-test.cpp @@ -91,7 +91,7 @@ TEST_FUNC(builder_dynamic_for_func_args) { // CHECK-LABEL: func @builder_dynamic_for_func_args(%{{.*}}: index, %{{.*}}: index) { // CHECK: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%{{.*}}) to affine_map<(d0) -> (d0)>(%{{.*}}) step 3 { // CHECK: {{.*}} = affine.apply affine_map<()[s0] -> (s0 * 3)>()[%{{.*}}] - // CHECK: {{.*}} = affine.apply affine_map<()[s0, s1] -> (s1 + s0 * 3)>()[%{{.*}}, %{{.*}}] + // CHECK: {{.*}} = affine.apply affine_map<()[s0, s1] -> (s0 * 3 + s1)>()[%{{.*}}, %{{.*}}] // CHECK: {{.*}} = affine.apply affine_map<()[s0] -> (s0 + 3)>()[%{{.*}}] // CHECK: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%{{.*}}) to affine_map<(d0) -> (d0)>(%{{.*}}) step 2 { // CHECK: {{.*}} = affine.apply affine_map<(d0, d1) -> ((d0 + d1 * 3) floordiv 32)>(%{{.*}}, %{{.*}}) diff --git a/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp b/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp index 35de0ba404dfb2..bacf2d511111ad 100644 --- a/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp +++ b/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp @@ -62,13 +62,6 @@ static llvm::cl::opt clTestComposeMaps( "AffineMap in the composition is specified as the affine_map attribute " "in a constant op."), llvm::cl::cat(clOptionsCategory)); -static llvm::cl::opt clTestNormalizeMaps( - "normalize-maps", - llvm::cl::desc( - "Enable testing the normalization of AffineAffineApplyOp " - "where each AffineAffineApplyOp in the composition is a single output " - "operation."), - llvm::cl::cat(clOptionsCategory)); static llvm::cl::opt clTestVecAffineLoopNest( "vectorize-affine-loop-nest", llvm::cl::desc( @@ -91,7 +84,6 @@ struct VectorizerTestPass void testBackwardSlicing(llvm::raw_ostream &outs); void testSlicing(llvm::raw_ostream &outs); void testComposeMaps(llvm::raw_ostream &outs); - void testNormalizeMaps(); /// Test for 'vectorizeAffineLoopNest' utility. void testVecAffineLoopNest(); @@ -230,33 +222,6 @@ static bool singleResultAffineApplyOpWithoutUses(Operation &op) { return app && app.use_empty(); } -void VectorizerTestPass::testNormalizeMaps() { - using matcher::Op; - - auto f = getFunction(); - - // Save matched AffineApplyOp that all need to be erased in the end. - auto pattern = Op(affineApplyOp); - SmallVector toErase; - pattern.match(f, &toErase); - { - // Compose maps. - auto pattern = Op(singleResultAffineApplyOpWithoutUses); - SmallVector matches; - pattern.match(f, &matches); - for (auto m : matches) { - auto app = cast(m.getMatchedOperation()); - OpBuilder b(m.getMatchedOperation()); - SmallVector operands(app.getOperands()); - makeComposedAffineApply(b, app.getLoc(), app.getAffineMap(), operands); - } - } - // We should now be able to erase everything in reverse order in this test. - for (auto m : llvm::reverse(toErase)) { - m.getMatchedOperation()->erase(); - } -} - /// Test for 'vectorizeAffineLoopNest' utility. void VectorizerTestPass::testVecAffineLoopNest() { std::vector> loops; @@ -302,9 +267,6 @@ void VectorizerTestPass::runOnFunction() { if (clTestComposeMaps) testComposeMaps(outs); - - if (clTestNormalizeMaps) - testNormalizeMaps(); } if (clTestVecAffineLoopNest)