[MLIR] Modify HasParent trait to allow one of several op's as a parent

- Modify HasParent trait to allow one of several op's as a parent -
- Expose this trait in the ODS framework using the ParentOneOf<> trait.

Differential Revision: https://reviews.llvm.org/D81880
This commit is contained in:
Rahul Joshi 2020-06-16 04:50:48 +00:00 committed by Mehdi Amini
parent 388afd8406
commit e81bf67e8c
4 changed files with 57 additions and 7 deletions

View File

@ -1684,6 +1684,9 @@ class SingleBlockImplicitTerminator<string op>
class HasParent<string op>
: ParamNativeOpTrait<"HasParent", op>;
class ParentOneOf<list<string> ops>
: ParamNativeOpTrait<"HasParent", StrJoin<ops>.result>;
// Op result type is derived from the first attribute. If the attribute is an
// subclass of `TypeAttrBase`, its value is used, otherwise, the type of the
// attribute content is used.

View File

@ -1145,16 +1145,22 @@ template <typename TerminatorOpType> struct SingleBlockImplicitTerminator {
};
};
/// This class provides a verifier for ops that are expecting a specific parent.
template <typename ParentOpType> struct HasParent {
/// This class provides a verifier for ops that are expecting their parent
/// to be one of the given parent ops
template <typename... ParentOpTypes>
struct HasParent {
template <typename ConcreteType>
class Impl : public TraitBase<ConcreteType, Impl> {
public:
static LogicalResult verifyTrait(Operation *op) {
if (isa<ParentOpType>(op->getParentOp()))
if (llvm::isa<ParentOpTypes...>(op->getParentOp()))
return success();
return op->emitOpError() << "expects parent op '"
<< ParentOpType::getOperationName() << "'";
return op->emitOpError()
<< "expects parent op "
<< (sizeof...(ParentOpTypes) != 1 ? "to be one of '" : "'")
<< llvm::makeArrayRef({ParentOpTypes::getOperationName()...})
<< "'";
}
};
};

View File

@ -173,6 +173,39 @@ func @failedHasParent_wrong_parent() {
}) : () -> ()
}
// -----
// CHECK: succeededParentOneOf
func @succeededParentOneOf() {
"test.parent"() ({
"test.child_with_parent_one_of"() : () -> ()
"test.finish"() : () -> ()
}) : () -> ()
return
}
// -----
// CHECK: succeededParent1OneOf
func @succeededParent1OneOf() {
"test.parent1"() ({
"test.child_with_parent_one_of"() : () -> ()
"test.finish"() : () -> ()
}) : () -> ()
return
}
// -----
func @failedParentOneOf_wrong_parent1() {
"some.otherop"() ({
// expected-error@+1 {{'test.child_with_parent_one_of' op expects parent op to be one of 'test.parent, test.parent1'}}
"test.child_with_parent_one_of"() : () -> ()
"test.finish"() : () -> ()
}) : () -> ()
}
// -----
func @failedSingleBlockImplicitTerminator_empty_block() {

View File

@ -439,10 +439,18 @@ def BroadcastableOp : TEST_Op<"broadcastable", [ResultsBroadcastableShape]> {
let results = (outs AnyTensor);
}
// There the "HasParent" trait.
def ParentOp : TEST_Op<"parent">;
// HasParent trait
def ParentOp : TEST_Op<"parent"> {
let regions = (region AnyRegion);
}
def ChildOp : TEST_Op<"child", [HasParent<"ParentOp">]>;
// ParentOneOf trait
def ParentOp1 : TEST_Op<"parent1"> {
let regions = (region AnyRegion);
}
def ChildWithParentOneOf : TEST_Op<"child_with_parent_one_of",
[ParentOneOf<["ParentOp", "ParentOp1"]>]>;
def TerminatorOp : TEST_Op<"finish", [Terminator]>;
def SingleBlockImplicitTerminatorOp : TEST_Op<"SingleBlockImplicitTerminator",