首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >LLVM isa<>是如何实现的?

LLVM isa<>是如何实现的?
EN

Stack Overflow用户
提问于 2011-05-18 07:30:17
回答 3查看 7.1K关注 0票数 25

来自http://llvm.org/docs/CodingStandards.html#ci_rtti_exceptions

RTTI确实广泛使用了使用isa<>、cast<>和dyn_cast<>等模板的

手卷形式。这种形式的RTTI是可选的,可以添加到任何类中。它的效率也比dynamic_cast<>高得多。

isa和其他是如何实现的?

EN

回答 3

Stack Overflow用户

发布于 2011-05-20 15:45:49

首先,LLVM系统非常具体,根本不是RTTI系统的临时替代品。

Premises

  • 对于大多数类,没有必要生成RTTI information
  • When它是必需的,信息只有在给定的层次结构中才有意义
  • 我们排除了来自此系统的多重继承

标识对象类的

以一个简单的层次结构为例:

代码语言:javascript
复制
struct Base {}; /* abstract */
struct DerivedLeft: Base {}; /* abstract */
struct DerivedRight:Base {};
struct MostDerivedL1: DerivedLeft {};
struct MostDerivedL2: DerivedLeft {};
struct MostDerivedR: DerivedRight {};

我们将创建一个特定于此层次结构的枚举,为每个可以实例化的层次结构成员创建一个枚举成员(其他成员将无用)。

代码语言:javascript
复制
enum BaseId {
  DerivedRightId,
  MostDerivedL1Id,
  MostDerivedL2Id,
  MostDerivedRId
};

然后,将在Base类中添加一个返回此枚举的方法。

代码语言:javascript
复制
struct Base {
  static inline bool classof(Base const*) { return true; }

  Base(BaseId id): Id(id) {}

  BaseId getValueID() const { return Id; }

  BaseId Id;
};

并且每个具体的类也是以这种方式增加的:

代码语言:javascript
复制
struct DerivedRight: Base {
  static inline bool classof(DerivedRight const*) { return true; }

  static inline bool classof(Base const* B) {
    switch(B->getValueID()) {
    case DerivedRightId: case MostDerivedRId: return true;
    default: return false;
    }
  }

  DerivedRight(BaseId id = DerivedRightId): Base(id) {}
};

现在,可以简单地查询类型转换的确切类型。

隐藏实现详细信息

但是,让用户使用getValueID会很麻烦,所以在LLVM中,这是通过使用classof方法来隐藏的。

给定的类应该实现两个classof方法:一个用于其最深层的基础(通过测试合适的BaseId值),另一个用于自身(纯优化)。例如:

代码语言:javascript
复制
struct MostDerivedL1: DerivedLeft {
  static inline bool classof(MostDerivedL1 const*) { return true; }

  static inline bool classof(Base const* B) {
    return B->getValueID() == MostDerivedL1Id;
  }

  MostDerivedL1(): DerivedLeft(MostDerivedL1Id) {}
};

这样,我们就可以通过模板检查是否可以进行强制转换:

代码语言:javascript
复制
template <typename To, typename From>
bool isa(From const& f) {
  return To::classof(&f);
}

想象一下,ToMostDerivedL1

  • 如果FromMostDerivedL1,则我们调用classof的第一个重载,并且它工作
  • 如果From为其他任何值,则我们调用classof的第二个重载,并且检查使用枚举来确定具体类型是否匹配。<代码>H236<代码>F237

希望它能更清晰。

票数 33
EN

Stack Overflow用户

发布于 2011-05-18 14:47:04

只需在osgx的答案中添加一些东西:基本上每个类都应该实现classof()方法,它可以完成所有必要的东西。例如,值的classof()例程如下所示:

代码语言:javascript
复制
  // Methods for support type inquiry through isa, cast, and dyn_cast:
  static inline bool classof(const Value *) {
    return true; // Values are always values.
  }

为了检查我们是否有一个合适类型的类,每个类都有它唯一的ValueID。您可以在include/llvm/Value.h文件中查看ValueID的完整列表。此ValueID的用法如下(摘自函数.h):

代码语言:javascript
复制
  /// Methods for support type inquiry through isa, cast, and dyn_cast:
  static inline bool classof(const Function *) { return true; }
  static inline bool classof(const Value *V) {
    return V->getValueID() == Value::FunctionVal;
  }

因此,简而言之:每个类都应该实现执行必要决策的classof()方法。所讨论的实现由一组唯一的ValueID组成。因此,为了实现classof(),只需将参数的ValueID与自己的ValueID进行比较即可。

如果我没记错的话,isa<>和friends的第一个实现是在大约10年前从boost中采用的。现在,实现方式有很大的差异:)

票数 6
EN

Stack Overflow用户

发布于 2011-05-18 10:10:43

我应该提一下http://llvm.org/docs/ProgrammersManual.html#isa -本文档有一些额外的描述。

isa、cast和dyn_cast的源代码都放在一个单独的文件中,并且有很多注释。

http://llvm.org/doxygen/Casting_8h_source.html

代码语言:javascript
复制
00047 // isa<X> - Return true if the parameter to the template is an instance of the
00048 // template type argument.  Used like this:
00049 //
00050 //  if (isa<Type*>(myVal)) { ... }
00051 //
00052 template <typename To, typename From>
00053 struct isa_impl {
00054   static inline bool doit(const From &Val) {
00055     return To::classof(&Val);
00056   }
00057 };

00193 // cast<X> - Return the argument parameter cast to the specified type.  This
00194 // casting operator asserts that the type is correct, so it does not return null
00195 // on failure.  It does not allow a null argument (use cast_or_null for that).
00196 // It is typically used like this:
00197 //
00198 //  cast<Instruction>(myVal)->getParent()
00199 //
00200 template <class X, class Y>
00201 inline typename cast_retty<X, Y>::ret_type cast(const Y &Val) {
00202   assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
00203   return cast_convert_val<X, Y,
00204                           typename simplify_type<Y>::SimpleType>::doit(Val);
00205 }

00218 // dyn_cast<X> - Return the argument parameter cast to the specified type.  This
00219 // casting operator returns null if the argument is of the wrong type, so it can
00220 // be used to test for a type as well as cast if successful.  This should be
00221 // used in the context of an if statement like this:
00222 //
00223 //  if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
00224 //
00225 
00226 template <class X, class Y>
00227 inline typename cast_retty<X, Y>::ret_type dyn_cast(const Y &Val) {
00228   return isa<X>(Val) ? cast<X, Y>(Val) : 0;
00229 }
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6038330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档