一.从这个问题说起
如果我们使用了一个库,这个库的代码是无法修改的,其中包含一个类class A。
我们在代码中定义了一个类B,如何让A继承自我的写的B呢?
二.奇怪的代码 :
class Conv2dOp : public ::mlir::Op<Conv2dOp, ::mlir::OpTrait::ZeroRegions> |
在mlir中,当我们定义了一个Op,如Conv2d。通过tablegen,可以生成以上的代码。
上面的代码看上去比较奇怪,父类mlir::Op<>中有很多模板。
template < typename ConcreteType, template < typename T> class ... Traits> class Op : public OpState, public Traits<ConcreteType>... { |
我们追溯一下,看看mlir::Op的定义。在Op的定义中,我们在子类(Conv2dOp中定义的Trait就变成了Op的父类)
通过这种模板的方式 , 我们将自己定义的类,传递到了mlir库中。
三.mlir中的interface
在了解了这个前置知识后, 我们来看一个更复杂的内容,mlir中的interface的实现
1.使用interface
td定义: class Ka_Op<string mnemonic, list<Trait> traits = []> : Ka_BaseOp<mnemonic, !listconcat(traits, [DeclareOpInterfaceMethods<BackinferInterface>] )>; 使用: if (auto bk = llvm::dyn_cast<BackinferInterface>(innerOp)) { bk.backinfer() } |
如上面所示, 当我们在td中定义一个Backinterface后,然后在op中”DeclareOpInterfaceMethods“在Op中,则可以在C++代码中将op转成BackinferInterface,并调用基接口
那么背后,mlir库为我们做了什么呢
2.Conv2d与Trait
class Conv2dOp : public ::mlir::Op<Conv2dOp, 省略很多, ::ka_compiler::BackinferInterface::Trait> |
在”奇怪的代码“中我们讲过, 通过这种方式,Op可以继承自BackinferInterface::Trait
3.BackinferInterface::Trait的定义
class BackinferInterface : public ::mlir::OpInterface<BackinferInterface, detail::BackinferInterfaceInterfaceTraits> { public : 看这里---> struct Trait : public detail::BackinferInterfaceTrait<ConcreteOp> {}; bool backinfer(llvm::DenseMap<mlir::Value, ka_compiler::RankedAxisData> & inputs, const llvm::DenseMap<mlir::Value, ka_compiler::RankedAxisData> & outputs); }; |
可以看到Trait 继承自BackinferInterfaceTrait<ConcreteOp> 。我们再看BackinferInterfaceTrait<ConcreteOp> 的定义
4.BackinferInterfaceTraint<ConcreteOp>
struct BackinferInterfaceTrait : public ::mlir::OpInterface<BackinferInterface, detail::BackinferInterfaceInterfaceTraits>::Trait<ConcreteOp> { }; |
可以看到BackinferInterfaceTrait 继承自OpInterface,并将BackinferInterface和通过模板的形式传递给了父类OpInterface
接下来看OpInterface
5.OpInterface
class OpInterface : public detail::Interface<ConcreteType, Operation *, Traits, Op<ConcreteType>, OpTrait::TraitBase> { |
OpInterface继承自Interface,并将Op和Traint传递给了父类Interface
我们再看Interface
6.Interface
template < typename ConcreteType, typename ValueT, typename Traits, typename BaseType, template < typename , template < typename > class > class BaseTrait> class Interface : public BaseType { |
可以看到Interface继承自BaseType ,而BaseType 则是由OpInterface的定义中传递 的Op<ConcreteType>,
ConcreteType也就是BackinferInterface 也就是说Interface最终继承了BackinferInterface 类
四。结论
以上追溯过程十分复杂,那么能不能简单理解 一下呢?
一个类,如果拥有了某种trait(继承),最终的结果是这个类将通过继承此Trait的方式获得Trait的能力