diff --git a/mlir/include/mlir/Analysis/AffineStructures.h b/mlir/include/mlir/Analysis/AffineStructures.h --- a/mlir/include/mlir/Analysis/AffineStructures.h +++ b/mlir/include/mlir/Analysis/AffineStructures.h @@ -491,18 +491,19 @@ /// Returns the smallest known constant bound for the extent of the specified /// identifier (pos^th), i.e., the smallest known constant that is greater /// than or equal to 'exclusive upper bound' - 'lower bound' of the - /// identifier. Returns None if it's not a constant. This method employs - /// trivial (low complexity / cost) checks and detection. Symbolic identifiers - /// are treated specially, i.e., it looks for constant differences between - /// affine expressions involving only the symbolic identifiers. `lb` and - /// `ub` (along with the `boundFloorDivisor`) are set to represent the lower - /// and upper bound associated with the constant difference: `lb`, `ub` have - /// the coefficients, and boundFloorDivisor, their divisor. `minLbPos` and - /// `minUbPos` if non-null are set to the position of the constant lower bound - /// and upper bound respectively (to the same if they are from an equality). - /// Ex: if the lower bound is [(s0 + s2 - 1) floordiv 32] for a system with - /// three symbolic identifiers, *lb = [1, 0, 1], lbDivisor = 32. See comments - /// at function definition for examples. + /// identifier. This constant bound is guaranteed to be non-negative. Returns + /// None if it's not a constant. This method employs trivial (low complexity / + /// cost) checks and detection. Symbolic identifiers are treated specially, + /// i.e., it looks for constant differences between affine expressions + /// involving only the symbolic identifiers. `lb` and `ub` (along with the + /// `boundFloorDivisor`) are set to represent the lower and upper bound + /// associated with the constant difference: `lb`, `ub` have the coefficients, + /// and boundFloorDivisor, their divisor. `minLbPos` and `minUbPos` if + /// non-null are set to the position of the constant lower bound and upper + /// bound respectively (to the same if they are from an equality). Ex: if the + /// lower bound is [(s0 + s2 - 1) floordiv 32] for a system with three + /// symbolic identifiers, *lb = [1, 0, 1], lbDivisor = 32. See comments at + /// function definition for examples. Optional getConstantBoundOnDimSize( unsigned pos, SmallVectorImpl *lb = nullptr, int64_t *boundFloorDivisor = nullptr, diff --git a/mlir/include/mlir/Analysis/Utils.h b/mlir/include/mlir/Analysis/Utils.h --- a/mlir/include/mlir/Analysis/Utils.h +++ b/mlir/include/mlir/Analysis/Utils.h @@ -279,10 +279,11 @@ /// otherwise. Note that the symbols of the region are treated specially, /// i.e., the returned bounding constant holds for *any given* value of the /// symbol identifiers. The 'shape' vector is set to the corresponding - /// dimension-wise bounds major to minor. We use int64_t instead of uint64_t - /// since index types can be at most int64_t. `lbs` are set to the lower - /// bounds for each of the rank dimensions, and lbDivisors contains the - /// corresponding denominators for floorDivs. + /// dimension-wise bounds major to minor. The number of elements and all the + /// dimension-wise bounds are guaranteed to be non-negative. We use int64_t + /// instead of uint64_t since index types can be at most int64_t. `lbs` are + /// set to the lower bounds for each of the rank dimensions, and lbDivisors + /// contains the corresponding denominators for floorDivs. Optional getConstantBoundingSizeAndShape( SmallVectorImpl *shape = nullptr, std::vector> *lbs = nullptr, diff --git a/mlir/lib/Analysis/AffineStructures.cpp b/mlir/lib/Analysis/AffineStructures.cpp --- a/mlir/lib/Analysis/AffineStructures.cpp +++ b/mlir/lib/Analysis/AffineStructures.cpp @@ -2285,14 +2285,15 @@ } } -/// Returns the extent (upper bound - lower bound) of the specified -/// identifier if it is found to be a constant; returns None if it's not a -/// constant. This methods treats symbolic identifiers specially, i.e., -/// it looks for constant differences between affine expressions involving -/// only the symbolic identifiers. See comments at function definition for -/// example. 'lb', if provided, is set to the lower bound associated with the -/// constant difference. Note that 'lb' is purely symbolic and thus will contain -/// the coefficients of the symbolic identifiers and the constant coefficient. +/// Returns a non-negative constant bound on the extent (upper bound - lower +/// bound) of the specified identifier if it is found to be a constant; returns +/// None if it's not a constant. This methods treats symbolic identifiers +/// specially, i.e., it looks for constant differences between affine +/// expressions involving only the symbolic identifiers. See comments at +/// function definition for example. 'lb', if provided, is set to the lower +/// bound associated with the constant difference. Note that 'lb' is purely +/// symbolic and thus will contain the coefficients of the symbolic identifiers +/// and the constant coefficient. // Egs: 0 <= i <= 15, return 16. // s0 + 2 <= i <= s0 + 17, returns 16. (s0 has to be a symbol) // s0 + s1 + 16 <= d0 <= s0 + s1 + 31, returns 16. @@ -2384,6 +2385,8 @@ int64_t diff = ceilDiv(atIneq(ubPos, getNumCols() - 1) + atIneq(lbPos, getNumCols() - 1) + 1, atIneq(lbPos, pos)); + // This bound is non-negative by definition. + diff = std::max(diff, 0); if (minDiff == None || diff < minDiff) { minDiff = diff; minLbPosition = lbPos; diff --git a/mlir/lib/Analysis/Utils.cpp b/mlir/lib/Analysis/Utils.cpp --- a/mlir/lib/Analysis/Utils.cpp +++ b/mlir/lib/Analysis/Utils.cpp @@ -374,6 +374,7 @@ cstWithShapeBounds.getConstantBoundOnDimSize(d, &lb, &lbDivisor); if (diff.hasValue()) { diffConstant = diff.getValue(); + assert(diffConstant >= 0 && "Dim size bound can't be negative"); assert(lbDivisor > 0); } else { // If no constant bound is found, then it can always be bound by the diff --git a/mlir/test/Dialect/Affine/affine-data-copy.mlir b/mlir/test/Dialect/Affine/affine-data-copy.mlir --- a/mlir/test/Dialect/Affine/affine-data-copy.mlir +++ b/mlir/test/Dialect/Affine/affine-data-copy.mlir @@ -273,12 +273,15 @@ // ----- -// CHECK-LABEL: func @empty_loop -func @empty_loop(%arg0: memref<1024x1024xf64>) { - // Empty loop - so no copy generation happens. +// CHECK-LABEL: func @empty_loops +func @empty_loops(%arg0: memref<1024x1024xf64>) { + // Empty loops - so no copy generation happens. affine.for %i = 0 to 0 { affine.load %arg0[0, %i] : memref<1024x1024xf64> } + affine.for %i = 0 to -16 { + affine.load %arg0[0, %i] : memref<1024x1024xf64> + } return // CHECK-NOT: memref.alloc // CHECK: return