diff --git a/mlir/docs/Dialects/Affine.md b/mlir/docs/Dialects/Affine.md --- a/mlir/docs/Dialects/Affine.md +++ b/mlir/docs/Dialects/Affine.md @@ -63,7 +63,7 @@ identifiers to enable powerful analysis and transformation. An SSA value's use can be bound to a symbolic identifier if that SSA value is either 1. a region argument for an op with trait `AffineScope` (eg. `FuncOp`), -2. a value defined at the top level of a `AffineScope` op (i.e., immediately +2. a value defined at the top level of an `AffineScope` op (i.e., immediately enclosed by the latter), 3. a value that dominates the `AffineScope` op enclosing the value's use, 4. the result of a [`constant` operation](Standard.md#constant-operation), @@ -74,6 +74,8 @@ memref that is an argument to a `AffineScope` op or a memref where the corresponding dimension is either static or a dynamic one in turn bound to a valid symbol. +*Note:* if the use of an SSA value is not contained in any op with the +`AffineScope` trait, only the rules 4-6 can be applied. Note that as a result of rule (3) above, symbol validity is sensitive to the location of the SSA use. Dimensions may be bound not only to anything that a diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp --- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp +++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp @@ -113,7 +113,7 @@ } /// Returns the closest region enclosing `op` that is held by an operation with -/// trait `AffineScope`. +/// trait `AffineScope`; `nullptr` if there is no such region. // TODO: getAffineScope should be publicly exposed for affine passes/utilities. static Region *getAffineScope(Operation *op) { auto *curOp = op; @@ -122,7 +122,7 @@ return curOp->getParentRegion(); curOp = parentOp; } - llvm_unreachable("op doesn't have an enclosing polyhedral scope"); + return nullptr; } // A Value can be used as a dimension id iff it meets one of the following @@ -236,28 +236,31 @@ return false; } -// A value can be used as a symbol for `region` iff it meets onf of the the -// following conditions: -// *) It is a constant. -// *) It is defined at the top level of 'region' or is its argument. -// *) It dominates `region`'s parent op. -// *) It is the result of an affine apply operation with symbol arguments. -// *) It is a result of the dim op on a memref whose corresponding size is -// a valid symbol. +/// A value can be used as a symbol for `region` iff it meets onf of the the +/// following conditions: +/// *) It is a constant. +/// *) It is the result of an affine apply operation with symbol arguments. +/// *) It is a result of the dim op on a memref whose corresponding size is +/// a valid symbol. +/// *) It is defined at the top level of 'region' or is its argument. +/// *) It dominates `region`'s parent op. +/// If `region` is null, conservatively assume the symbol definition scope does +/// not exist and only accept the values that would be symbols regardless of +/// the surrounding region structure, i.e. the first three cases above. bool mlir::isValidSymbol(Value value, Region *region) { // The value must be an index type. if (!value.getType().isIndex()) return false; // A top-level value is a valid symbol. - if (::isTopLevelValue(value, region)) + if (region && ::isTopLevelValue(value, region)) return true; auto *defOp = value.getDefiningOp(); if (!defOp) { // A block argument that is not a top-level value is a valid symbol if it // dominates region's parent op. - if (!region->getParentOp()->isKnownIsolatedFromAbove()) + if (region && !region->getParentOp()->isKnownIsolatedFromAbove()) if (auto *parentOpRegion = region->getParentOp()->getParentRegion()) return isValidSymbol(value, parentOpRegion); return false; @@ -277,7 +280,7 @@ return isDimOpValidSymbol(dimOp, region); // Check for values dominating `region`'s parent op. - if (!region->getParentOp()->isKnownIsolatedFromAbove()) + if (region && !region->getParentOp()->isKnownIsolatedFromAbove()) if (auto *parentRegion = region->getParentOp()->getParentRegion()) return isValidSymbol(value, parentRegion);