forked from OSchip/llvm-project
Fix AffineApply corner case
This CL adds a test reported by andydavis@ and fixes the corner case that appears when operands do not come from an AffineApply and no Dim composition is needed. In such cases, we would need to create an empty map which is disallowed. The composition in such cases becomes trivial: there is no composition. This CL also updates the name AffineNormalizer to AffineApplyNormalizer. PiperOrigin-RevId: 229819234
This commit is contained in:
parent
0e81d7c420
commit
24e5a72dac
|
@ -389,16 +389,19 @@ private:
|
|||
explicit ReturnOp(const OperationInst *state) : Op(state) {}
|
||||
};
|
||||
|
||||
// Prints dimension and symbol list.
|
||||
/// Prints dimension and symbol list.
|
||||
void printDimAndSymbolList(OperationInst::const_operand_iterator begin,
|
||||
OperationInst::const_operand_iterator end,
|
||||
unsigned numDims, OpAsmPrinter *p);
|
||||
|
||||
// Parses dimension and symbol list and returns true if parsing failed.
|
||||
/// Parses dimension and symbol list and returns true if parsing failed.
|
||||
bool parseDimAndSymbolList(OpAsmParser *parser,
|
||||
SmallVector<Value *, 4> &operands,
|
||||
unsigned &numDims);
|
||||
|
||||
/// Modifies both `map` and `operands` in-place so as to:
|
||||
/// 1. drop duplicate operands
|
||||
/// 2. drop unused dims and symbols from map
|
||||
void canonicalizeMapAndOperands(AffineMap *map,
|
||||
llvm::SmallVectorImpl<Value *> *operands);
|
||||
|
||||
|
|
|
@ -1353,10 +1353,10 @@ bool mlir::checkMemrefAccessDependence(
|
|||
|
||||
namespace {
|
||||
|
||||
/// An `AffineNormalizer` is a helper class that is not visible to the user and
|
||||
/// supports renumbering operands of AffineApplyOp.
|
||||
/// This acts as a reindexing map of Value* to positional dims or symbols and
|
||||
/// allows simplifications such as:
|
||||
/// An `AffineApplyNormalizer` is a helper class that is not visible to the user
|
||||
/// and 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)
|
||||
|
@ -1367,8 +1367,8 @@ namespace {
|
|||
/// ```mlir
|
||||
/// %1 = affine_apply () -> (0)
|
||||
/// ```
|
||||
struct AffineNormalizer {
|
||||
AffineNormalizer(AffineMap map, ArrayRef<Value *> operands);
|
||||
struct AffineApplyNormalizer {
|
||||
AffineApplyNormalizer(AffineMap map, ArrayRef<Value *> operands);
|
||||
|
||||
/// Returns the AffineMap resulting from normalization.
|
||||
AffineMap getAffineMap() { return affineMap; }
|
||||
|
@ -1381,18 +1381,18 @@ struct AffineNormalizer {
|
|||
|
||||
private:
|
||||
/// Helper function to insert `v` into the coordinate system of the current
|
||||
/// AffineNormalizer. Returns the AffineDimExpr with the corresponding
|
||||
/// AffineApplyNormalizer. Returns the AffineDimExpr with the corresponding
|
||||
/// renumbered position.
|
||||
AffineDimExpr applyOneDim(Value *v);
|
||||
|
||||
/// Given an `other` normalizer, this rewrites `other.affineMap` in the
|
||||
/// coordinate system of the current AffineNormalizer.
|
||||
/// coordinate system of the current AffineApplyNormalizer.
|
||||
/// Returns the rewritten AffineMap and updates the dims and symbols of
|
||||
/// `this`.
|
||||
AffineMap renumber(const AffineNormalizer &other);
|
||||
AffineMap renumber(const AffineApplyNormalizer &other);
|
||||
|
||||
/// Given an `app`, rewrites `app.getAffineMap()` in the coordinate system of
|
||||
/// the current AffineNormalizer.
|
||||
/// the current AffineApplyNormalizer.
|
||||
/// Returns the rewritten AffineMap and updates the dims and symbols of
|
||||
/// `this`.
|
||||
AffineMap renumber(const AffineApplyOp &app);
|
||||
|
@ -1418,15 +1418,15 @@ private:
|
|||
}
|
||||
static constexpr unsigned kMaxAffineApplyDepth = 1;
|
||||
|
||||
AffineNormalizer() { affineApplyDepth()++; }
|
||||
AffineApplyNormalizer() { affineApplyDepth()++; }
|
||||
|
||||
public:
|
||||
~AffineNormalizer() { affineApplyDepth()--; }
|
||||
~AffineApplyNormalizer() { affineApplyDepth()--; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
AffineDimExpr AffineNormalizer::applyOneDim(Value *v) {
|
||||
AffineDimExpr AffineApplyNormalizer::applyOneDim(Value *v) {
|
||||
DenseMap<Value *, unsigned>::iterator iterPos;
|
||||
bool inserted = false;
|
||||
std::tie(iterPos, inserted) =
|
||||
|
@ -1438,7 +1438,7 @@ AffineDimExpr AffineNormalizer::applyOneDim(Value *v) {
|
|||
.cast<AffineDimExpr>();
|
||||
}
|
||||
|
||||
AffineMap AffineNormalizer::renumber(const AffineNormalizer &other) {
|
||||
AffineMap AffineApplyNormalizer::renumber(const AffineApplyNormalizer &other) {
|
||||
SmallVector<AffineExpr, 8> dimRemapping;
|
||||
for (auto *v : other.reorderedDims) {
|
||||
auto kvp = other.dimValueToPosition.find(v);
|
||||
|
@ -1461,15 +1461,15 @@ AffineMap AffineNormalizer::renumber(const AffineNormalizer &other) {
|
|||
dimRemapping.size(), symRemapping.size());
|
||||
}
|
||||
|
||||
AffineMap AffineNormalizer::renumber(const AffineApplyOp &app) {
|
||||
AffineMap AffineApplyNormalizer::renumber(const AffineApplyOp &app) {
|
||||
assert(app.getAffineMap().getRangeSizes().empty() && "Non-empty range sizes");
|
||||
|
||||
// Create the AffineNormalizer for the operands of this
|
||||
// AffineApplyOp and combine it with the current AffineNormalizer.
|
||||
// Create the AffineApplyNormalizer for the operands of this
|
||||
// AffineApplyOp and combine it with the current AffineApplyNormalizer.
|
||||
SmallVector<Value *, 8> operands(
|
||||
const_cast<AffineApplyOp &>(app).getOperands().begin(),
|
||||
const_cast<AffineApplyOp &>(app).getOperands().end());
|
||||
AffineNormalizer normalizer(app.getAffineMap(), operands);
|
||||
AffineApplyNormalizer normalizer(app.getAffineMap(), operands);
|
||||
return renumber(normalizer);
|
||||
}
|
||||
|
||||
|
@ -1484,16 +1484,13 @@ static unsigned getIndexOf(Value *v, const AffineApplyOp &op) {
|
|||
return static_cast<unsigned>(-1);
|
||||
}
|
||||
|
||||
AffineNormalizer::AffineNormalizer(AffineMap map, ArrayRef<Value *> operands)
|
||||
: AffineNormalizer() {
|
||||
AffineApplyNormalizer::AffineApplyNormalizer(AffineMap map,
|
||||
ArrayRef<Value *> operands)
|
||||
: AffineApplyNormalizer() {
|
||||
assert(map.getRangeSizes().empty() && "Unbounded map expected");
|
||||
assert(map.getNumInputs() == operands.size() &&
|
||||
"number of operands does not match the number of map inputs");
|
||||
|
||||
if (operands.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SmallVector<AffineExpr, 8> exprs;
|
||||
for (auto en : llvm::enumerate(operands)) {
|
||||
auto *t = en.value();
|
||||
|
@ -1505,6 +1502,9 @@ AffineNormalizer::AffineNormalizer(AffineMap map, ArrayRef<Value *> operands)
|
|||
if (en.index() < map.getNumDims()) {
|
||||
exprs.push_back(applyOneDim(t));
|
||||
} else {
|
||||
// Composition of mathematical symbols must occur by concatenation.
|
||||
// A subsequent canonicalization will drop duplicates. Duplicates are
|
||||
// not dropped here because it would just amount to code duplication.
|
||||
concatenatedSymbols.push_back(t);
|
||||
}
|
||||
} else {
|
||||
|
@ -1516,14 +1516,21 @@ AffineNormalizer::AffineNormalizer(AffineMap map, ArrayRef<Value *> operands)
|
|||
}
|
||||
}
|
||||
|
||||
// Map is already composed.
|
||||
if (exprs.empty()) {
|
||||
affineMap = map;
|
||||
return;
|
||||
}
|
||||
|
||||
auto numDims = dimValueToPosition.size();
|
||||
auto numSymbols = concatenatedSymbols.size() - map.getNumSymbols();
|
||||
auto exprsMap = AffineMap::get(numDims, numSymbols, exprs, {});
|
||||
LLVM_DEBUG(map.print(dbgs() << "\nCompose map: "));
|
||||
LLVM_DEBUG(exprsMap.print(dbgs() << "\nWith map: "));
|
||||
LLVM_DEBUG(map.compose(exprsMap).print(dbgs() << "\nResult: "));
|
||||
|
||||
affineMap = simplifyAffineMap(map.compose(exprsMap));
|
||||
LLVM_DEBUG(affineMap.print(dbgs() << "\nResult: "));
|
||||
LLVM_DEBUG(affineMap.print(dbgs() << "\nSimplified result: "));
|
||||
}
|
||||
|
||||
/// Implements `map` and `operands` composition and simplification to support
|
||||
|
@ -1532,7 +1539,7 @@ AffineNormalizer::AffineNormalizer(AffineMap map, ArrayRef<Value *> operands)
|
|||
/// immediately deleted.
|
||||
static void composeAffineMapAndOperands(AffineMap *map,
|
||||
SmallVectorImpl<Value *> *operands) {
|
||||
AffineNormalizer normalizer(*map, *operands);
|
||||
AffineApplyNormalizer normalizer(*map, *operands);
|
||||
auto normalizedMap = normalizer.getAffineMap();
|
||||
auto normalizedOperands = normalizer.getOperands();
|
||||
canonicalizeMapAndOperands(&normalizedMap, &normalizedOperands);
|
||||
|
|
|
@ -27,6 +27,12 @@
|
|||
// Affine maps for test case: arg_used_as_dim_and_symbol
|
||||
// CHECK: [[MAP14:#map[0-9]+]] = (d0, d1, d2, d3)[s0, s1] -> (d2, d0 * -1 - d1 + d3 + s0 + s1)
|
||||
|
||||
// Affine maps for test case: zero_map
|
||||
// CHECK: [[MAP15:#map[0-9]+]] = ()[s0] -> (s0)
|
||||
|
||||
// Affine maps for test case: zero_map
|
||||
// CHECK: [[MAP16:#map[0-9]+]] = () -> (0)
|
||||
|
||||
// CHECK-LABEL: func @compose_affine_maps_1dto2d_no_symbols() {
|
||||
func @compose_affine_maps_1dto2d_no_symbols() {
|
||||
%0 = alloc() : memref<4x4xf32>
|
||||
|
@ -213,3 +219,22 @@ func @arg_used_as_dim_and_symbol(%arg0: memref<100x100xf32>, %arg1: index) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: func @trivial_maps
|
||||
func @trivial_maps() {
|
||||
%0 = alloc() : memref<10xf32>
|
||||
%c0 = constant 0 : index
|
||||
%cst = constant 0.000000e+00 : f32
|
||||
for %i1 = 0 to 10 {
|
||||
%1 = affine_apply ()[s0] -> (s0)()[%c0]
|
||||
// CHECK: {{.*}} = affine_apply [[MAP15]]()[%c0]
|
||||
store %cst, %0[%1] : memref<10xf32>
|
||||
%2 = load %0[%c0] : memref<10xf32>
|
||||
|
||||
%3 = affine_apply ()[] -> (0)()[]
|
||||
// CHECK: {{.*}} = affine_apply [[MAP16]]()
|
||||
store %cst, %0[%3] : memref<10xf32>
|
||||
%4 = load %0[%c0] : memref<10xf32>
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue