Skip to content

Commit 3c94045

Browse files
committed
When writing PDLL patterns it is often assumed that some basic checks are executed before constraints are called, but this is not always the case, as operations can be reordered in PDLInterp if there is no dependency between them.
For example: Pdll pattern: ``` let someOp = op<someDialect.SomeOp>(input: Value<inputTy: Type) {axis = inputAxis: Attr } -> (resTypes: TypeRange); let someResult = someConstraint(inputAxis); ``` If SomeOp requires axis to have a valid value, it is easy to (wrongly) assume that someConstraint always gets called with a not-null inputAxis. This is not correct. The linearized PDLInterp (pseudo-code) could be the following: ``` %0 = pdl_interp.get_attribute "axis" of %arg0 %1 = pdl_interp.apply_constraint “someConstraint”(%0) pdl_interp.is_not_null(%0) pdl_interp.check_operation_name of %arg0 is "someDialect.SomeOp" ``` Note that here someConstraint can be called with a null attribute. This commit changes the prioritization of predicates, so that constraints are run after other predicates. ``` %0 = pdl_interp.get_attribute "axis" of %arg0 pdl_interp.is_not_null(%0) pdl_interp.check_operation_name of %arg0 is "someDialect.SomeOp" %1 = pdl_interp.apply_constraint “someConstraint”(%0) ``` This ensures that null or operation name checks are run before constraints. This is closer to the mental model when writing PDLL patterns and should make it less likely to run into bugs caused by assuming implicit checks for not null.
1 parent 479c8d6 commit 3c94045

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

mlir/lib/Conversion/PDLToPDLInterp/PredicateTree.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -768,17 +768,25 @@ struct OrderedPredicate {
768768
/// model.
769769
bool operator<(const OrderedPredicate &rhs) const {
770770
// Sort by:
771+
// * not being a constraint. Rational: When writing constraints, it is
772+
// sometimes assumed that checks for null or operation names are executed
773+
// before the constraint. As there is no dependency between this
774+
// operation, this is not always guaranteed, which can lead to bugs if the
775+
// constraints is not checking inputs for null itself. By ordering
776+
// constraints to the end, it is assured that implicit checks are nun
777+
// before them
771778
// * higher first and secondary order sums
772779
// * lower depth
773780
// * lower position dependency
774781
// * lower predicate dependency
775782
// * lower tie breaking ID
776783
auto *rhsPos = rhs.position;
777-
return std::make_tuple(primary, secondary, rhsPos->getOperationDepth(),
784+
return std::make_tuple(!isa<ConstraintQuestion>(question), primary,
785+
secondary, rhsPos->getOperationDepth(),
778786
rhsPos->getKind(), rhs.question->getKind(), rhs.id) >
779-
std::make_tuple(rhs.primary, rhs.secondary,
780-
position->getOperationDepth(), position->getKind(),
781-
question->getKind(), id);
787+
std::make_tuple(!isa<ConstraintQuestion>(rhs.question), rhs.primary,
788+
rhs.secondary, position->getOperationDepth(),
789+
position->getKind(), question->getKind(), id);
782790
}
783791
};
784792

mlir/test/Conversion/PDLToPDLInterp/pdl-to-pdl-interp-matcher.mlir

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,27 @@ module @predicate_ordering {
488488
}
489489
}
490490

491+
// -----
492+
493+
// CHECK-LABEL: module @predicate_ordering_attr
494+
module @predicate_ordering_attr {
495+
// Check that the result is checked for null first, before applying the
496+
// constraint.
497+
498+
// CHECK: func @matcher(%[[ROOT:.*]]: !pdl.operation)
499+
// CHECK: %[[RESULT:.*]] = pdl_interp.get_attribute "attr" of %[[ROOT]]
500+
// CHECK-NEXT: pdl_interp.is_not_null %[[RESULT]]
501+
// CHECK: pdl_interp.apply_constraint "constraint"
502+
503+
504+
pdl.pattern : benefit(1) {
505+
%attr = attribute
506+
pdl.apply_native_constraint "constraint"(%attr: !pdl.attribute)
507+
pdl.apply_native_constraint "constraint"(%attr: !pdl.attribute)
508+
%root = operation "foo.op" {"attr" = %attr}
509+
rewrite %root with "rewriter"
510+
}
511+
}
491512

492513
// -----
493514

0 commit comments

Comments
 (0)