[MLIR] Allow recovering from semi-affine sets in FlatLinearValueConst… (#212346)

…raints

The IntegerSet constructor of FlatLinearValueConstraints asserts when
flattening fails, which happens for semi-affine integer sets. Since the
failure is signalled from inside a constructor, callers have no way to
detect the unsupported case ahead of time and no way to work around it;
they simply crash.

Add an optional `bool *error` parameter to the constructor. When it is
non-null, hitting the unimplemented case sets `*error` to true and
returns instead of asserting, letting callers bail out gracefully.
`*error` is set to false on success. When the pointer is null the
previous assert behavior is retained, so existing callers are
unaffected.
This commit is contained in:
William Moses 2026-07-27 17:26:34 -05:00 committed by GitHub
parent 61225df551
commit d8d33abac0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 59 additions and 12 deletions

View file

@ -334,8 +334,10 @@ public:
setValue(i, *valArgs[i]);
}
/// Creates an affine constraint system from an IntegerSet.
explicit FlatLinearValueConstraints(IntegerSet set, ValueRange operands = {});
/// Creates an affine constraint system from an IntegerSet. Returns failure
/// if `set` is semi-affine, as flattening is not implemented for those.
static FailureOr<FlatLinearValueConstraints>
create(IntegerSet set, ValueRange operands = {});
/// Return the kind of this object.
Kind getKind() const override { return Kind::FlatLinearValueConstraints; }
@ -517,6 +519,12 @@ public:
/// output = {0 <= d0 <= 6, 1 <= d1 <= 15}
LogicalResult unionBoundingBox(const FlatLinearValueConstraints &other);
using IntegerPolyhedron::unionBoundingBox;
protected:
/// Creates an affine constraint system from an IntegerSet. `error` is set to
/// true if `set` could not be flattened, in which case the constraint system
/// is left without the constraints of `set`. Use `create` instead.
FlatLinearValueConstraints(IntegerSet set, ValueRange operands, bool *error);
};
/// Flattens 'expr' into 'flattenedExpr', which contains the coefficients of the

View file

@ -45,6 +45,11 @@ class FlatAffineValueConstraints : public FlatLinearValueConstraints {
public:
using FlatLinearValueConstraints::FlatLinearValueConstraints;
/// Creates an affine constraint system from an IntegerSet. Returns failure
/// if `set` is semi-affine, as flattening is not implemented for those.
static FailureOr<FlatAffineValueConstraints>
create(IntegerSet set, ValueRange operands = {});
/// Return the kind of this object.
Kind getKind() const override { return Kind::FlatAffineValueConstraints; }

View file

@ -1145,13 +1145,16 @@ IntegerSet FlatLinearConstraints::getAsIntegerSet(MLIRContext *context) const {
// Construct from an IntegerSet.
FlatLinearValueConstraints::FlatLinearValueConstraints(IntegerSet set,
ValueRange operands)
ValueRange operands,
bool *error)
: FlatLinearConstraints(set.getNumInequalities(), set.getNumEqualities(),
set.getNumDims() + set.getNumSymbols() + 1,
set.getNumDims(), set.getNumSymbols(),
/*numLocals=*/0) {
assert(error && "expected a valid error flag");
assert((operands.empty() || set.getNumInputs() == operands.size()) &&
"operand count mismatch");
*error = false;
// Set the values for the non-local variables.
for (unsigned i = 0, e = operands.size(); i < e; ++i)
setValue(i, operands[i]);
@ -1160,7 +1163,8 @@ FlatLinearValueConstraints::FlatLinearValueConstraints(IntegerSet set,
std::vector<SmallVector<int64_t, 8>> flatExprs;
FlatLinearConstraints localVarCst;
if (failed(getFlattenedAffineExprs(set, &flatExprs, &localVarCst))) {
assert(false && "flattening unimplemented for semi-affine integer sets");
// Flattening is unimplemented for semi-affine integer sets.
*error = true;
return;
}
assert(flatExprs.size() == set.getNumConstraints());
@ -1180,6 +1184,15 @@ FlatLinearValueConstraints::FlatLinearValueConstraints(IntegerSet set,
append(localVarCst);
}
FailureOr<FlatLinearValueConstraints>
FlatLinearValueConstraints::create(IntegerSet set, ValueRange operands) {
bool error = false;
FlatLinearValueConstraints cst(set, operands, &error);
if (error)
return failure();
return cst;
}
unsigned FlatLinearValueConstraints::appendDimVar(ValueRange vals) {
unsigned pos = getNumDimVars();
return insertVar(VarKind::SetDim, pos, vals);

View file

@ -29,6 +29,15 @@ using namespace mlir;
using namespace affine;
using namespace presburger;
FailureOr<FlatAffineValueConstraints>
FlatAffineValueConstraints::create(IntegerSet set, ValueRange operands) {
bool error = false;
FlatAffineValueConstraints cst(set, operands, &error);
if (error)
return failure();
return cst;
}
LogicalResult
FlatAffineValueConstraints::addInductionVarOrTerminalSymbol(Value val) {
if (containsVar(val))
@ -208,13 +217,18 @@ void FlatAffineValueConstraints::addAffineIfOpDomain(AffineIfOp ifOp) {
canonicalizeSetAndOperands(&set, &operands);
// Create the base constraints from the integer set attached to ifOp.
FlatAffineValueConstraints cst(set, operands);
FailureOr<FlatAffineValueConstraints> cst =
FlatAffineValueConstraints::create(set, operands);
if (failed(cst)) {
assert(false && "semi-affine integer sets are unsupported here");
return;
}
// Merge the constraints from ifOp to the current domain. We need first merge
// and align the IDs from both constraints, and then append the constraints
// from the ifOp into the current one.
mergeAndAlignVarsWithOther(0, &cst);
append(cst);
mergeAndAlignVarsWithOther(0, &*cst);
append(*cst);
}
LogicalResult FlatAffineValueConstraints::addBound(BoundType type, unsigned pos,

View file

@ -2195,13 +2195,17 @@ void mlir::affine::getSequentialLoops(
}
IntegerSet mlir::affine::simplifyIntegerSet(IntegerSet set) {
FlatAffineValueConstraints fac(set);
if (fac.isEmpty())
FailureOr<FlatAffineValueConstraints> fac =
FlatAffineValueConstraints::create(set);
// Semi-affine sets can't be flattened; return them as is.
if (failed(fac))
return set;
if (fac->isEmpty())
return IntegerSet::getEmptySet(set.getNumDims(), set.getNumSymbols(),
set.getContext());
fac.removeTrivialRedundancy();
fac->removeTrivialRedundancy();
auto simplifiedSet = fac.getAsIntegerSet(set.getContext());
auto simplifiedSet = fac->getAsIntegerSet(set.getContext());
assert(simplifiedSet && "guaranteed to succeed while roundtripping");
return simplifiedSet;
}

View file

@ -30,7 +30,10 @@ namespace presburger {
/// represents a valid IntegerSet.
inline IntegerPolyhedron parseIntegerPolyhedron(StringRef str) {
MLIRContext context(MLIRContext::Threading::DISABLED);
return affine::FlatAffineValueConstraints(parseIntegerSet(str, &context));
FailureOr<affine::FlatAffineValueConstraints> cst =
affine::FlatAffineValueConstraints::create(parseIntegerSet(str, &context));
assert(succeeded(cst) && "expected a valid IntegerSet");
return *cst;
}
/// Parse a list of StringRefs to IntegerRelation and combine them into a