Move makeNormalizedAffineApply
authorNicolas Vasilache <ntv@google.com>
Tue, 8 Jan 2019 04:14:30 +0000 (20:14 -0800)
committerjpienaar <jpienaar@google.com>
Fri, 29 Mar 2019 22:04:38 +0000 (15:04 -0700)
This CL is the 3rd on the path to simplifying AffineMap composition.
This CL just moves `makeNormalizedAffineApply` from VectorAnalysis to
AffineAnalysis where it more naturally belongs.

PiperOrigin-RevId: 228277182

mlir/include/mlir/Analysis/AffineAnalysis.h
mlir/include/mlir/Analysis/VectorAnalysis.h
mlir/lib/Analysis/AffineAnalysis.cpp
mlir/lib/Analysis/VectorAnalysis.cpp

index ba6cb58111b4aaaf273f9f3aecf4c9a5dc32a98b..0f165c967c0b3dba07f7a1efc0922d0a145ac49d 100644 (file)
 
 namespace mlir {
 
+class AffineApplyOp;
 class AffineExpr;
 class AffineMap;
 class AffineValueMap;
-class ForInst;
-class MLIRContext;
 class FlatAffineConstraints;
+class ForInst;
+class FuncBuilder;
+class Instruction;
 class IntegerSet;
+class Location;
+class MLIRContext;
 class OperationInst;
-class Instruction;
+template <typename OpType> class OpPointer;
 class Value;
 
 /// Simplify an affine expression by flattening and some amount of
@@ -52,6 +56,23 @@ AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims,
 /// and sizes.
 AffineMap simplifyAffineMap(AffineMap map);
 
+/// Creates an AffineApplyOp that is normalized for super-vectorization. That is
+/// an AffineApplyOp with a single result and an unbounded AffineMap. The
+/// operands of the AffineApplyOp are either dims, symbols or constants but can
+/// never be obtained from other AffineApplyOp.
+/// This is achieved by performing a composition at the single-result AffineMap
+/// level.
+///
+/// Prerequisite:
+/// 1. `map` is a single result, unbounded, AffineMap;
+/// 2. `operands` can involve at most a length-1 chain of AffineApplyOp. The
+///   affine map for each of these AffineApplyOp is itself single result and
+///   unbounded. Essentially, all ancestor AffineApplyOp must have been
+///   constructed as single-result, unbounded, AffineMaps.
+OpPointer<AffineApplyOp>
+makeNormalizedAffineApply(FuncBuilder *b, Location loc, AffineMap map,
+                          llvm::ArrayRef<Value *> operands);
+
 /// Returns the sequence of AffineApplyOp OperationInsts operation in
 /// 'affineApplyOps', which are reachable via a search starting from 'operands',
 /// and ending at operands which are not defined by AffineApplyOps.
index 001bb4f993486b132d460187fc1a43a158af9243..e34e3433f2feac742415be4b5651df2533931c22 100644 (file)
@@ -32,8 +32,6 @@ class Instruction;
 class Location;
 class MemRefType;
 class OperationInst;
-template <typename ObjectType, typename ElementType> class OperandIterator;
-template <typename OpType> class OpPointer;
 class Value;
 class VectorType;
 
@@ -128,23 +126,6 @@ AffineMap
 makePermutationMap(OperationInst *opInst,
                    const llvm::DenseMap<ForInst *, unsigned> &loopToVectorDim);
 
-/// Creates an AffineApplyOp that is normalized for super-vectorization. That is
-/// an AffineApplyOp with a single result and an unbounded AffineMap. The
-/// operands of the AffineApplyOp are either dims, symbols or constants but can
-/// never be obtained from other AffineApplyOp.
-/// This is achieved by performing a composition at the single-result AffineMap
-/// level.
-///
-/// Prerequisite:
-/// 1. `map` is a single result, unbounded, AffineMap;
-/// 2. `operands` can involve at most a length-1 chain of AffineApplyOp. The
-///   affine map for each of these AffineApplyOp is itself single result and
-///   unbounded. Essentially, all ancestor AffineApplyOp must have been
-///   constructed as single-result, unbounded, AffineMaps.
-OpPointer<AffineApplyOp> makeNormalizedAffineApply(FuncBuilder *b, Location loc,
-                                                   AffineMap map,
-                                                   ArrayRef<Value *> operands);
-
 namespace matcher {
 
 /// Matches vector_transfer_read, vector_transfer_write and ops that return a
index 7d31bdae387eb34dd1c9ec7e50c051fcd169d328..28551fc6f4a0332126effa236c99f62160f58efe 100644 (file)
@@ -24,6 +24,7 @@
 #include "mlir/Analysis/AffineStructures.h"
 #include "mlir/Analysis/Utils.h"
 #include "mlir/IR/AffineExprVisitor.h"
+#include "mlir/IR/Builders.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/Instructions.h"
 #include "mlir/StandardOps/StandardOps.h"
@@ -36,6 +37,8 @@
 
 using namespace mlir;
 
+using llvm::dbgs;
+
 /// Constructs an affine expression from a flat ArrayRef. If there are local
 /// identifiers (neither dimensional nor symbolic) that appear in the sum of
 /// products expression, 'localExprs' is expected to have the AffineExpr
@@ -1352,3 +1355,204 @@ bool mlir::checkMemrefAccessDependence(
   LLVM_DEBUG(dependenceConstraints->dump());
   return true;
 }
+
+namespace {
+
+/// A `SingleResultAffineNormalizer` is a helper class that is not visible to
+/// the user and supports renumbering operands of single-result AffineApplyOp.
+/// This operates on the assumption that only single-result unbounded AffineMap
+/// are used for all operands.
+/// 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 SingleResultAffineNormalizer {
+  SingleResultAffineNormalizer(AffineMap map, ArrayRef<Value *> operands);
+
+  /// Returns the single result, unbounded, AffineMap resulting from
+  /// normalization.
+  AffineMap getAffineMap() {
+    return AffineMap::get(reorderedDims.size(), reorderedSymbols.size(), {expr},
+                          {});
+  }
+
+  SmallVector<Value *, 8> getOperands() {
+    SmallVector<Value *, 8> res(reorderedDims);
+    res.append(reorderedSymbols.begin(), reorderedSymbols.end());
+    return res;
+  }
+
+private:
+  /// Helper function to insert `v` into the coordinate system of the current
+  /// SingleResultAffineNormalizer (i.e. in the proper `xxxValueToPosition` and
+  /// the proper `reorderedXXX`).
+  /// Returns the AffineDimExpr or AffineSymbolExpr with the correponding
+  /// renumbered position.
+  template <typename DimOrSymbol> DimOrSymbol renumberOneIndex(Value *v);
+
+  /// Given an `other` normalizer, this rewrites `other.expr` in the coordinate
+  /// system of the current SingleResultAffineNormalizer.
+  /// Returns the rewritten AffineExpr.
+  AffineExpr renumber(const SingleResultAffineNormalizer &other);
+
+  /// Given an `app` with single result and unbounded AffineMap, this rewrites
+  /// the app's map single result AffineExpr in the coordinate system of the
+  /// current SingleResultAffineNormalizer.
+  /// Returns the rewritten AffineExpr.
+  AffineExpr renumber(AffineApplyOp *app);
+
+  /// Maps of Value* to position in the `expr`.
+  DenseMap<Value *, unsigned> dimValueToPosition;
+  DenseMap<Value *, unsigned> symValueToPosition;
+
+  /// Ordered dims and symbols matching positional dims and symbols in `expr`.
+  SmallVector<Value *, 8> reorderedDims;
+  SmallVector<Value *, 8> reorderedSymbols;
+
+  AffineExpr expr;
+};
+
+} // namespace
+
+template <typename DimOrSymbol>
+static DimOrSymbol make(unsigned position, MLIRContext *context);
+
+template <> AffineDimExpr make(unsigned position, MLIRContext *context) {
+  return getAffineDimExpr(position, context).cast<AffineDimExpr>();
+}
+
+template <> AffineSymbolExpr make(unsigned position, MLIRContext *context) {
+  return getAffineSymbolExpr(position, context).cast<AffineSymbolExpr>();
+}
+
+template <typename DimOrSymbol>
+DimOrSymbol SingleResultAffineNormalizer::renumberOneIndex(Value *v) {
+  static_assert(std::is_same<DimOrSymbol, AffineDimExpr>::value ||
+                    std::is_same<DimOrSymbol, AffineSymbolExpr>::value,
+                "renumber<AffineDimExpr>(...) or renumber<AffineDimExpr>(...) "
+                "required");
+  DenseMap<Value *, unsigned> &pos =
+      std::is_same<DimOrSymbol, AffineSymbolExpr>::value ? symValueToPosition
+                                                         : dimValueToPosition;
+  DenseMap<Value *, unsigned>::iterator iterPos;
+  bool inserted = false;
+  std::tie(iterPos, inserted) = pos.insert(std::make_pair(v, pos.size()));
+  if (inserted) {
+    std::is_same<DimOrSymbol, AffineDimExpr>::value
+        ? reorderedDims.push_back(v)
+        : reorderedSymbols.push_back(v);
+  }
+  return make<DimOrSymbol>(iterPos->second, v->getFunction()->getContext());
+}
+
+AffineExpr SingleResultAffineNormalizer::renumber(
+    const SingleResultAffineNormalizer &other) {
+  SmallVector<AffineExpr, 8> dimRemapping, symRemapping;
+  for (auto *v : other.reorderedDims) {
+    auto kvp = other.dimValueToPosition.find(v);
+    if (dimRemapping.size() <= kvp->second)
+      dimRemapping.resize(kvp->second + 1);
+    dimRemapping[kvp->second] = renumberOneIndex<AffineDimExpr>(kvp->first);
+  }
+  for (auto *v : other.reorderedSymbols) {
+    auto kvp = other.symValueToPosition.find(v);
+    if (symRemapping.size() <= kvp->second)
+      symRemapping.resize(kvp->second + 1);
+    symRemapping[kvp->second] = renumberOneIndex<AffineSymbolExpr>(kvp->first);
+  }
+  return other.expr.replaceDimsAndSymbols(dimRemapping, symRemapping);
+}
+
+AffineExpr SingleResultAffineNormalizer::renumber(AffineApplyOp *app) {
+  // Sanity check, single result AffineApplyOp if one wants to use this.
+  assert(app->getNumResults() == 1 && "Not a single result AffineApplyOp");
+  assert(app->getAffineMap().getRangeSizes().empty() &&
+         "Non-empty range sizes");
+
+  // Create the SingleResultAffineNormalizer for the operands of this
+  // AffineApplyOp and combine it with the current SingleResultAffineNormalizer.
+  using ValueTy = decltype(*(app->getOperands().begin()));
+  SingleResultAffineNormalizer normalizer(
+      app->getAffineMap(),
+      functional::map([](ValueTy v) { return static_cast<Value *>(v); },
+                      app->getOperands()));
+
+  // We know this is a single result AffineMap, we need to append a
+  // renumbered AffineExpr.
+  return renumber(normalizer);
+}
+
+SingleResultAffineNormalizer::SingleResultAffineNormalizer(
+    AffineMap map, ArrayRef<Value *> operands) {
+  assert(map.getNumResults() == 1 && "Single-result map expected");
+  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;
+  }
+
+  auto *context = operands[0]->getFunction()->getContext();
+  SmallVector<AffineExpr, 8> exprs;
+  for (auto en : llvm::enumerate(operands)) {
+    auto *t = en.value();
+    assert(t->getType().isIndex());
+    if (auto inst = t->getDefiningInst()) {
+      if (auto app = inst->dyn_cast<AffineApplyOp>()) {
+        // Sanity check, AffineApplyOp must always be composed by construction
+        // and there can only ever be a dependence chain of 1 AffineApply. So we
+        // can never get a second AffineApplyOp.
+        // This also guarantees we can build another
+        // SingleResultAffineNormalizer here that does not recurse a second
+        // time.
+        for (auto *pred : app->getOperands()) {
+          assert(!pred->getDefiningInst() ||
+                 !pred->getDefiningInst()->isa<AffineApplyOp>() &&
+                     "AffineApplyOp chain of length > 1");
+          (void)pred;
+        }
+        exprs.push_back(renumber(app));
+      } else if (auto constant = inst->dyn_cast<ConstantOp>()) {
+        // Constants remain constants.
+        auto affineConstant = inst->cast<ConstantIndexOp>();
+        exprs.push_back(
+            getAffineConstantExpr(affineConstant->getValue(), context));
+      } else {
+        // DimOp, top of the function symbols are all symbols.
+        exprs.push_back(renumberOneIndex<AffineSymbolExpr>(t));
+      }
+    } else if (en.index() < map.getNumDims()) {
+      assert(isa<ForInst>(t) && "ForInst expected for AffineDimExpr");
+      exprs.push_back(renumberOneIndex<AffineDimExpr>(t));
+    } else {
+      assert(!isa<ForInst>(t) && "unexpectd ForInst for a AffineSymbolExpr");
+      exprs.push_back(renumberOneIndex<AffineSymbolExpr>(t));
+    }
+  }
+  auto exprsMap = AffineMap::get(dimValueToPosition.size(),
+                                 symValueToPosition.size(), exprs, {});
+
+  expr = simplifyAffineExpr(map.getResult(0).compose(exprsMap),
+                            exprsMap.getNumDims(), exprsMap.getNumSymbols());
+
+  LLVM_DEBUG(map.getResult(0).print(dbgs() << "\nCompose expr: "));
+  LLVM_DEBUG(exprsMap.print(dbgs() << "\nWith map: "));
+  LLVM_DEBUG(expr.print(dbgs() << "\nResult: "));
+}
+
+OpPointer<AffineApplyOp>
+mlir::makeNormalizedAffineApply(FuncBuilder *b, Location loc, AffineMap map,
+                                ArrayRef<Value *> operands) {
+  SingleResultAffineNormalizer normalizer(map, operands);
+  return b->create<AffineApplyOp>(loc, normalizer.getAffineMap(),
+                                  normalizer.getOperands());
+}
index cd74fc0c01c4edbc6043e409e679ddb64def99ec..bc43e2ca5eb2bf5efde88664f8686c2c2cf51073 100644 (file)
@@ -18,7 +18,6 @@
 #include "mlir/Analysis/VectorAnalysis.h"
 #include "mlir/Analysis/AffineAnalysis.h"
 #include "mlir/Analysis/LoopAnalysis.h"
-#include "mlir/IR/Builders.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/Instructions.h"
 #include "mlir/StandardOps/StandardOps.h"
@@ -28,8 +27,6 @@
 
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SetVector.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
 
 ///
 /// Implements Analysis functions specific to vectors which support
@@ -38,9 +35,6 @@
 
 using namespace mlir;
 
-#define DEBUG_TYPE "vector-analysis"
-
-using llvm::dbgs;
 using llvm::SetVector;
 
 Optional<SmallVector<unsigned, 4>> mlir::shapeRatio(ArrayRef<int> superShape,
@@ -243,204 +237,3 @@ bool mlir::matcher::operatesOnSuperVectors(const OperationInst &opInst,
 
   return true;
 }
-
-namespace {
-
-/// A `SingleResultAffineNormalizer` is a helper class that is not visible to
-/// the user and supports renumbering operands of single-result AffineApplyOp.
-/// This operates on the assumption that only single-result unbounded AffineMap
-/// are used for all operands.
-/// 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 SingleResultAffineNormalizer {
-  SingleResultAffineNormalizer(AffineMap map, ArrayRef<Value *> operands);
-
-  /// Returns the single result, unbounded, AffineMap resulting from
-  /// normalization.
-  AffineMap getAffineMap() {
-    return AffineMap::get(reorderedDims.size(), reorderedSymbols.size(), {expr},
-                          {});
-  }
-
-  SmallVector<Value *, 8> getOperands() {
-    SmallVector<Value *, 8> res(reorderedDims);
-    res.append(reorderedSymbols.begin(), reorderedSymbols.end());
-    return res;
-  }
-
-private:
-  /// Helper function to insert `v` into the coordinate system of the current
-  /// SingleResultAffineNormalizer (i.e. in the proper `xxxValueToPosition` and
-  /// the proper `reorderedXXX`).
-  /// Returns the AffineDimExpr or AffineSymbolExpr with the correponding
-  /// renumbered position.
-  template <typename DimOrSymbol> DimOrSymbol renumberOneIndex(Value *v);
-
-  /// Given an `other` normalizer, this rewrites `other.expr` in the coordinate
-  /// system of the current SingleResultAffineNormalizer.
-  /// Returns the rewritten AffineExpr.
-  AffineExpr renumber(const SingleResultAffineNormalizer &other);
-
-  /// Given an `app` with single result and unbounded AffineMap, this rewrites
-  /// the app's map single result AffineExpr in the coordinate system of the
-  /// current SingleResultAffineNormalizer.
-  /// Returns the rewritten AffineExpr.
-  AffineExpr renumber(AffineApplyOp *app);
-
-  /// Maps of Value* to position in the `expr`.
-  DenseMap<Value *, unsigned> dimValueToPosition;
-  DenseMap<Value *, unsigned> symValueToPosition;
-
-  /// Ordered dims and symbols matching positional dims and symbols in `expr`.
-  SmallVector<Value *, 8> reorderedDims;
-  SmallVector<Value *, 8> reorderedSymbols;
-
-  AffineExpr expr;
-};
-
-} // namespace
-
-template <typename DimOrSymbol>
-static DimOrSymbol make(unsigned position, MLIRContext *context);
-
-template <> AffineDimExpr make(unsigned position, MLIRContext *context) {
-  return getAffineDimExpr(position, context).cast<AffineDimExpr>();
-}
-
-template <> AffineSymbolExpr make(unsigned position, MLIRContext *context) {
-  return getAffineSymbolExpr(position, context).cast<AffineSymbolExpr>();
-}
-
-template <typename DimOrSymbol>
-DimOrSymbol SingleResultAffineNormalizer::renumberOneIndex(Value *v) {
-  static_assert(std::is_same<DimOrSymbol, AffineDimExpr>::value ||
-                    std::is_same<DimOrSymbol, AffineSymbolExpr>::value,
-                "renumber<AffineDimExpr>(...) or renumber<AffineDimExpr>(...) "
-                "required");
-  DenseMap<Value *, unsigned> &pos =
-      std::is_same<DimOrSymbol, AffineSymbolExpr>::value ? symValueToPosition
-                                                         : dimValueToPosition;
-  DenseMap<Value *, unsigned>::iterator iterPos;
-  bool inserted = false;
-  std::tie(iterPos, inserted) = pos.insert(std::make_pair(v, pos.size()));
-  if (inserted) {
-    std::is_same<DimOrSymbol, AffineDimExpr>::value
-        ? reorderedDims.push_back(v)
-        : reorderedSymbols.push_back(v);
-  }
-  return make<DimOrSymbol>(iterPos->second, v->getFunction()->getContext());
-}
-
-AffineExpr SingleResultAffineNormalizer::renumber(
-    const SingleResultAffineNormalizer &other) {
-  SmallVector<AffineExpr, 8> dimRemapping, symRemapping;
-  for (auto *v : other.reorderedDims) {
-    auto kvp = other.dimValueToPosition.find(v);
-    if (dimRemapping.size() <= kvp->second)
-      dimRemapping.resize(kvp->second + 1);
-    dimRemapping[kvp->second] = renumberOneIndex<AffineDimExpr>(kvp->first);
-  }
-  for (auto *v : other.reorderedSymbols) {
-    auto kvp = other.symValueToPosition.find(v);
-    if (symRemapping.size() <= kvp->second)
-      symRemapping.resize(kvp->second + 1);
-    symRemapping[kvp->second] = renumberOneIndex<AffineSymbolExpr>(kvp->first);
-  }
-  return other.expr.replaceDimsAndSymbols(dimRemapping, symRemapping);
-}
-
-AffineExpr SingleResultAffineNormalizer::renumber(AffineApplyOp *app) {
-  // Sanity check, single result AffineApplyOp if one wants to use this.
-  assert(app->getNumResults() == 1 && "Not a single result AffineApplyOp");
-  assert(app->getAffineMap().getRangeSizes().empty() &&
-         "Non-empty range sizes");
-
-  // Create the SingleResultAffineNormalizer for the operands of this
-  // AffineApplyOp and combine it with the current SingleResultAffineNormalizer.
-  using ValueTy = decltype(*(app->getOperands().begin()));
-  SingleResultAffineNormalizer normalizer(
-      app->getAffineMap(),
-      functional::map([](ValueTy v) { return static_cast<Value *>(v); },
-                      app->getOperands()));
-
-  // We know this is a single result AffineMap, we need to append a
-  // renumbered AffineExpr.
-  return renumber(normalizer);
-}
-
-SingleResultAffineNormalizer::SingleResultAffineNormalizer(
-    AffineMap map, ArrayRef<Value *> operands) {
-  assert(map.getNumResults() == 1 && "Single-result map expected");
-  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;
-  }
-
-  auto *context = operands[0]->getFunction()->getContext();
-  SmallVector<AffineExpr, 8> exprs;
-  for (auto en : llvm::enumerate(operands)) {
-    auto *t = en.value();
-    assert(t->getType().isIndex());
-    if (auto inst = t->getDefiningInst()) {
-      if (auto app = inst->dyn_cast<AffineApplyOp>()) {
-        // Sanity check, AffineApplyOp must always be composed by construction
-        // and there can only ever be a dependence chain of 1 AffineApply. So we
-        // can never get a second AffineApplyOp.
-        // This also guarantees we can build another
-        // SingleResultAffineNormalizer here that does not recurse a second
-        // time.
-        for (auto *pred : app->getOperands()) {
-          assert(!pred->getDefiningInst() ||
-                 !pred->getDefiningInst()->isa<AffineApplyOp>() &&
-                     "AffineApplyOp chain of length > 1");
-          (void)pred;
-        }
-        exprs.push_back(renumber(app));
-      } else if (auto constant = inst->dyn_cast<ConstantOp>()) {
-        // Constants remain constants.
-        auto affineConstant = inst->cast<ConstantIndexOp>();
-        exprs.push_back(
-            getAffineConstantExpr(affineConstant->getValue(), context));
-      } else {
-        // DimOp, top of the function symbols are all symbols.
-        exprs.push_back(renumberOneIndex<AffineSymbolExpr>(t));
-      }
-    } else if (en.index() < map.getNumDims()) {
-      assert(isa<ForInst>(t) && "ForInst expected for AffineDimExpr");
-      exprs.push_back(renumberOneIndex<AffineDimExpr>(t));
-    } else {
-      assert(!isa<ForInst>(t) && "unexpectd ForInst for a AffineSymbolExpr");
-      exprs.push_back(renumberOneIndex<AffineSymbolExpr>(t));
-    }
-  }
-  auto exprsMap = AffineMap::get(dimValueToPosition.size(),
-                                 symValueToPosition.size(), exprs, {});
-
-  expr = simplifyAffineExpr(map.getResult(0).compose(exprsMap),
-                            exprsMap.getNumDims(), exprsMap.getNumSymbols());
-
-  LLVM_DEBUG(map.getResult(0).print(dbgs() << "\nCompose expr: "));
-  LLVM_DEBUG(exprsMap.print(dbgs() << "\nWith map: "));
-  LLVM_DEBUG(expr.print(dbgs() << "\nResult: "));
-}
-
-OpPointer<AffineApplyOp>
-mlir::makeNormalizedAffineApply(FuncBuilder *b, Location loc, AffineMap map,
-                                ArrayRef<Value *> operands) {
-  SingleResultAffineNormalizer normalizer(map, operands);
-  return b->create<AffineApplyOp>(loc, normalizer.getAffineMap(),
-                                  normalizer.getOperands());
-}