//===----------------------------------------------------------------------===//
// These classes are used to define operation specific traits.
-class NativeOpTrait<string name> : NativeTrait<name, "Op">;
-class ParamNativeOpTrait<string prop, string params>
- : ParamNativeTrait<prop, params, "Op">;
-class GenInternalOpTrait<string prop> : GenInternalTrait<prop, "Op">;
-class PredOpTrait<string descr, Pred pred> : PredTrait<descr, pred>;
+class NativeOpTrait<string name, list<Trait> traits = []>
+ : NativeTrait<name, "Op"> {
+ // Specify the list of traits that need to be verified before the verification
+ // of this NativeOpTrait.
+ list<Trait> dependentTraits = traits;
+}
+class ParamNativeOpTrait<string prop, string params,
+ list<Trait> traits = []>
+ : ParamNativeTrait<prop, params, "Op"> {
+ // Specify the list of traits that need to be verified before the verification
+ // of this ParamNativeOpTrait.
+ list<Trait> dependentTraits = traits;
+}
+class GenInternalOpTrait<string prop, list<Trait> traits = []>
+ : GenInternalTrait<prop, "Op"> {
+ // Specify the list of traits that need to be verified before the verification
+ // of this GenInternalOpTrait.
+ list<Trait> dependentTraits = traits;
+}
+class PredOpTrait<string descr, Pred pred, list<Trait> traits = []>
+ : PredTrait<descr, pred> {
+ // Specify the list of traits that need to be verified before the verification
+ // of this PredOpTrait.
+ list<Trait> dependentTraits = traits;
+}
// Op defines an affine scope.
def AffineScope : NativeOpTrait<"AffineScope">;
// OpInterfaceTrait corresponds to a specific 'OpInterface' class defined in
// C++. The purpose to wrap around C++ symbol string with this class is to make
// interfaces specified for ops in TableGen less alien and more integrated.
-class OpInterfaceTrait<string name, code verifyBody = [{}]>
+class OpInterfaceTrait<string name, code verifyBody = [{}],
+ list<Trait> traits = []>
: InterfaceTrait<name> {
// Specify the body of the verification function. `$_op` will be replaced with
// the operation being verified.
code verify = verifyBody;
+
+ // Specify the list of traits that need to be verified before the verification
+ // of this OpInterfaceTrait.
+ list<Trait> dependentTraits = traits;
}
// This class represents a single, optionally static, interface method.
SmallPtrSet<const llvm::Init *, 32> traitSet;
traits.reserve(traitSet.size());
+ // The declaration order of traits imply the verification order of traits.
+ // Some traits may require other traits to be verified first then they can
+ // do further verification based on those verified facts. If you see this
+ // error, fix the traits declaration order by checking the `dependentTraits`
+ // field.
+ auto verifyTraitValidity = [&](Record *trait) {
+ auto *dependentTraits = trait->getValueAsListInit("dependentTraits");
+ for (auto *traitInit : *dependentTraits)
+ if (traitSet.find(traitInit) == traitSet.end())
+ PrintFatalError(
+ def.getLoc(),
+ trait->getValueAsString("trait") + " requires " +
+ cast<DefInit>(traitInit)->getDef()->getValueAsString(
+ "trait") +
+ " to precede it in traits list");
+ };
+
std::function<void(llvm::ListInit *)> insert;
insert = [&](llvm::ListInit *traitList) {
for (auto *traitInit : *traitList) {
insert(def->getValueAsListInit("traits"));
continue;
}
+
+ // Verify if the trait has all the dependent traits declared before
+ // itself.
+ verifyTraitValidity(def);
+
// Keep traits in the same order while skipping over duplicates.
if (traitSet.insert(traitInit).second)
traits.push_back(Trait::create(traitInit));
// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR9 %s 2>&1 | FileCheck --check-prefix=ERROR9 %s
// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR10 %s 2>&1 | FileCheck --check-prefix=ERROR10 %s
// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR11 %s 2>&1 | FileCheck --check-prefix=ERROR11 %s
+// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR12 %s 2>&1 | FileCheck --check-prefix=ERROR12 %s
+// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR13 %s 2>&1 | FileCheck --check-prefix=ERROR13 %s
include "mlir/IR/OpBase.td"
let regions = (region AnyRegion:$target);
}
#endif
+
+#ifdef ERROR12
+def OpTraitA : NativeOpTrait<"OpTraitA"> {}
+def OpTraitB : NativeOpTrait<"OpTraitB", [OpTraitA]> {}
+
+// ERROR12: error: OpTraitB requires OpTraitA to precede it in traits list
+def OpTraitWithoutDependentTrait : Op<Test_Dialect, "default_value", [OpTraitB]> {}
+#endif
+
+#ifdef ERROR13
+def OpTraitA : NativeOpTrait<"OpTraitA"> {}
+def OpInterfaceB : OpInterface<"OpInterfaceB"> {
+ let dependentTraits = [OpTraitA];
+}
+
+// ERROR13: error: OpInterfaceB::Trait requires OpTraitA to precede it in traits list
+def OpInterfaceWithoutDependentTrait : Op<Test_Dialect, "default_value", [OpInterfaceB]> {}
+#endif