diff --git a/mlir/include/mlir/IR/OpBase.td b/mlir/include/mlir/IR/OpBase.td --- a/mlir/include/mlir/IR/OpBase.td +++ b/mlir/include/mlir/IR/OpBase.td @@ -2024,11 +2024,31 @@ //===----------------------------------------------------------------------===// // These classes are used to define operation specific traits. -class NativeOpTrait : NativeTrait; -class ParamNativeOpTrait - : ParamNativeTrait; -class GenInternalOpTrait : GenInternalTrait; -class PredOpTrait : PredTrait; +class NativeOpTrait traits = []> + : NativeTrait { + // Specify the list of traits that need to be verified before the verification + // of this NativeOpTrait. + list dependentTraits = traits; +} +class ParamNativeOpTrait traits = []> + : ParamNativeTrait { + // Specify the list of traits that need to be verified before the verification + // of this ParamNativeOpTrait. + list dependentTraits = traits; +} +class GenInternalOpTrait traits = []> + : GenInternalTrait { + // Specify the list of traits that need to be verified before the verification + // of this GenInternalOpTrait. + list dependentTraits = traits; +} +class PredOpTrait traits = []> + : PredTrait { + // Specify the list of traits that need to be verified before the verification + // of this PredOpTrait. + list dependentTraits = traits; +} // Op defines an affine scope. def AffineScope : NativeOpTrait<"AffineScope">; @@ -2164,11 +2184,16 @@ // 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 +class OpInterfaceTrait traits = []> : InterfaceTrait { // 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 dependentTraits = traits; } // This class represents a single, optionally static, interface method. diff --git a/mlir/lib/TableGen/Operator.cpp b/mlir/lib/TableGen/Operator.cpp --- a/mlir/lib/TableGen/Operator.cpp +++ b/mlir/lib/TableGen/Operator.cpp @@ -548,6 +548,23 @@ SmallPtrSet 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(traitInit)->getDef()->getValueAsString( + "trait") + + " to precede it in traits list"); + }; + std::function insert; insert = [&](llvm::ListInit *traitList) { for (auto *traitInit : *traitList) { @@ -556,6 +573,11 @@ 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)); diff --git a/mlir/test/mlir-tblgen/op-error.td b/mlir/test/mlir-tblgen/op-error.td --- a/mlir/test/mlir-tblgen/op-error.td +++ b/mlir/test/mlir-tblgen/op-error.td @@ -9,6 +9,8 @@ // 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" @@ -104,3 +106,21 @@ 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 {} +#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 {} +#endif