[Mlir-commits] [mlir] e5e1bc0 - Revert "[mlir][SCF][NFC] `ValueBoundsConstraintSet`: Simplify `scf.for` implementation (#86239)"

Mehdi Amini llvmlistbot at llvm.org
Fri Apr 5 03:01:02 PDT 2024


Author: Mehdi Amini
Date: 2024-04-05T03:00:29-07:00
New Revision: e5e1bc0ad815647baeca67d7d47b71f792b5dde8

URL: https://github.com/llvm/llvm-project/commit/e5e1bc0ad815647baeca67d7d47b71f792b5dde8
DIFF: https://github.com/llvm/llvm-project/commit/e5e1bc0ad815647baeca67d7d47b71f792b5dde8.diff

LOG: Revert "[mlir][SCF][NFC] `ValueBoundsConstraintSet`: Simplify `scf.for` implementation (#86239)"

This reverts commit 24e4429980b3df039166c1ee6a9e530cc6f054c9.

gcc7 bot is broken

Added: 
    

Modified: 
    mlir/lib/Dialect/SCF/IR/ValueBoundsOpInterfaceImpl.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Dialect/SCF/IR/ValueBoundsOpInterfaceImpl.cpp b/mlir/lib/Dialect/SCF/IR/ValueBoundsOpInterfaceImpl.cpp
index 72c5aaa2306783..8e9d1021f93e4b 100644
--- a/mlir/lib/Dialect/SCF/IR/ValueBoundsOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/SCF/IR/ValueBoundsOpInterfaceImpl.cpp
@@ -12,6 +12,7 @@
 #include "mlir/Interfaces/ValueBoundsOpInterface.h"
 
 using namespace mlir;
+using presburger::BoundType;
 
 namespace mlir {
 namespace scf {
@@ -20,28 +21,7 @@ namespace {
 struct ForOpInterface
     : public ValueBoundsOpInterface::ExternalModel<ForOpInterface, ForOp> {
 
-  /// Populate bounds of values/dimensions for iter_args/OpResults. If the
-  /// value/dimension size does not change in an iteration, we can deduce that
-  /// it the same as the initial value/dimension.
-  ///
-  /// Example 1:
-  /// %0 = scf.for ... iter_args(%arg0 = %t) -> tensor<?xf32> {
-  ///   ...
-  ///   %1 = tensor.insert %f into %arg0[...] : tensor<?xf32>
-  ///   scf.yield %1 : tensor<?xf32>
-  /// }
-  /// --> bound(%0)[0] == bound(%t)[0]
-  /// --> bound(%arg0)[0] == bound(%t)[0]
-  ///
-  /// Example 2:
-  /// %0 = scf.for ... iter_args(%arg0 = %t) -> tensor<?xf32> {
-  ///   %sz = tensor.dim %arg0 : tensor<?xf32>
-  ///   %incr = arith.addi %sz, %c1 : index
-  ///   %1 = tensor.empty(%incr) : tensor<?xf32>
-  ///   scf.yield %1 : tensor<?xf32>
-  /// }
-  /// --> The yielded tensor dimension size changes with each iteration. Such
-  ///     loops are not supported and no constraints are added.
+  /// Populate bounds of values/dimensions for iter_args/OpResults.
   static void populateIterArgBounds(scf::ForOp forOp, Value value,
                                     std::optional<int64_t> dim,
                                     ValueBoundsConstraintSet &cstr) {
@@ -53,31 +33,59 @@ struct ForOpInterface
       iterArgIdx = llvm::cast<OpResult>(value).getResultNumber();
     }
 
+    // An EQ constraint can be added if the yielded value (dimension size)
+    // equals the corresponding block argument (dimension size).
     Value yieldedValue = cast<scf::YieldOp>(forOp.getBody()->getTerminator())
                              .getOperand(iterArgIdx);
     Value iterArg = forOp.getRegionIterArg(iterArgIdx);
     Value initArg = forOp.getInitArgs()[iterArgIdx];
 
-    // Populate constraints for the yielded value.
-    cstr.populateConstraints(yieldedValue, dim);
-    // Populate constraints for the iter_arg. This is just to ensure that the
-    // iter_arg is mapped in the constraint set, which is a prerequisite for
-    // `compare`. It may lead to a recursive call to this function in case the
-    // iter_arg was not visited when the constraints for the yielded value were
-    // populated, but no additional work is done.
-    cstr.populateConstraints(iterArg, dim);
-
-    // An EQ constraint can be added if the yielded value (dimension size)
-    // equals the corresponding block argument (dimension size).
-    if (cstr.compare(yieldedValue, dim,
-                     ValueBoundsConstraintSet::ComparisonOperator::EQ, iterArg,
-                     dim)) {
+    auto addEqBound = [&]() {
       if (dim.has_value()) {
         cstr.bound(value)[*dim] == cstr.getExpr(initArg, dim);
       } else {
         cstr.bound(value) == initArg;
       }
+    };
+
+    if (yieldedValue == iterArg) {
+      addEqBound();
+      return;
+    }
+
+    // Compute EQ bound for yielded value.
+    AffineMap bound;
+    ValueDimList boundOperands;
+    LogicalResult status = ValueBoundsConstraintSet::computeBound(
+        bound, boundOperands, BoundType::EQ, yieldedValue, dim,
+        [&](Value v, std::optional<int64_t> d, ValueBoundsConstraintSet &cstr) {
+          // Stop when reaching a block argument of the loop body.
+          if (auto bbArg = llvm::dyn_cast<BlockArgument>(v))
+            return bbArg.getOwner()->getParentOp() == forOp;
+          // Stop when reaching a value that is defined outside of the loop. It
+          // is impossible to reach an iter_arg from there.
+          Operation *op = v.getDefiningOp();
+          return forOp.getRegion().findAncestorOpInRegion(*op) == nullptr;
+        });
+    if (failed(status))
+      return;
+    if (bound.getNumResults() != 1)
+      return;
+
+    // Check if computed bound equals the corresponding iter_arg.
+    Value singleValue = nullptr;
+    std::optional<int64_t> singleDim;
+    if (auto dimExpr = dyn_cast<AffineDimExpr>(bound.getResult(0))) {
+      int64_t idx = dimExpr.getPosition();
+      singleValue = boundOperands[idx].first;
+      singleDim = boundOperands[idx].second;
+    } else if (auto symExpr = dyn_cast<AffineSymbolExpr>(bound.getResult(0))) {
+      int64_t idx = symExpr.getPosition() + bound.getNumDims();
+      singleValue = boundOperands[idx].first;
+      singleDim = boundOperands[idx].second;
     }
+    if (singleValue == iterArg && singleDim == dim)
+      addEqBound();
   }
 
   void populateBoundsForIndexValue(Operation *op, Value value,


        


More information about the Mlir-commits mailing list