Llvm的类型转换系统

Llvm内置了一个类型转换系统,并定义了类似于dynamic_cast这样的转换函数。Llvm底层的很大部分是由模板类构成的,这个转换系统对于模板类间的类型判断及转换至为重要。以下只是描述这个转换系统的一个框架,该系统的正确实现,还依赖于参与模板类正确实现某些函数(下面会提到)。
cast_retty类 cast_or_null是llvm所提供的类型转换系统的部分,这是一个有趣的模板实现。这个实现在llvm-3.1/include/llvm/support/Casting.h。

202template
203inline typename cast_retty::ret_type_cast_or_null(Y *Val) {
204if (Val == 0)return0;
205assert(isa(Val) && "cast_or_null()argument of incompatible type!");
206returncast(Val);
207}

首先,cast_or_null的返回类型是cast_retty中定义的ret_type类型。cast_retty只定义了ret_type(cast_retty顾名思义是cast return type的意思)。

156template
157struct cast_retty{
158typedef typename cast_retty_wrap 159typenamesimplify_type::SimpleType>::ret_typeret_type;
160};

这个ret_type则是typedef自cast_retty_wrap提供中定义的ret_type。

142template
143struct cast_retty_wrapp{
144// When thesimplified type and the from type are not the same, use the type
145// simplifier toreduce the type, then reuse cast_retty_impl to get the
146// resultant type.
147typedef typename cast_retty::ret_type ret_type;
148};
149
150template
151structcast_retty_wrap {
152// When thesimplified type is equal to the from type, use it directly.
153typedef typename cast_retty_impl::ret_typeret_type;
154};

看到cast_retty_wrap非特化版本在147行又递归回了cast_retty。这是怎么回事?在cast_retty定义的159行,simplify_type的定义如下:

30template struct simplify_type {
31typedefFrom SimpleType; // The realtype this represents...
32
33// An accessor toget the real value...
34staticSimpleType &getSimplifiedValue(From &Val) { returnVal; }
35};
36
37template structsimplify_type {
38typedef const From SimpleType;
39staticSimpleType &getSimplifiedValue(const From&Val) {
40returnsimplify_type::getSimplifiedValue(static_cast(Val));
41}
42};

类型SimpleType就是参数From。不过这只是Casting.h提供的默认实现,这个类的本义是提供类型简化,实际上在llvm及Clang的许多地方都另外提供了特化的simplify_type的定义,那么147行cast_retty的每次递归都将化简类型一次,直到无法化简(即调用上面的默认simplify_type实现),这时142行的类型From与SimpleFrom相同,因此使用cast_retty_wrap在150行的特化形式,进而由cast_retty_impl确定该类型。

122template struct cast_retty_impl {
123typedefTo& ret_type; // Normal case, return Ty&
124};
125template struct cast_retty_impl {
126typedef const To &ret_type; // Normal case,return Ty&
127};
128
129template struct cast_retty_impl {
130typedef To*ret_type; // Pointer arg case, return Ty*
131};
132
133template struct cast_retty_impl {
134typedef const To* ret_type; // Constant pointer arg case, return const Ty*
135};
136
137template struct cast_retty_impl{
138typedef const To* ret_type; // Constant pointer arg case, return const Ty*
139};

为什么要采用这么复杂的返回值类型声明呢?因为C++制订的类型转换规则仅允许调用用户定义的转换操作符一次,而这里则不限制转换的次数,只要给出simplify_type的特化实现,当然这样存在cast_retty陷入无限递归的情形(实际上无限递归是不存在的,因为C++限制了模板嵌套的层数,GCC好像是128)。
isa函数 Isa函数的作用是测试给定的变量是否具有指定的类型。

108template
109inline bool isa(const Y &Val) {
110return isa_impl_wrap::SimpleType>::doit(Val);
111}

这里再次应用了simplify_type来简化类型Y,并作为模板参数SimpleFrom的实参调用下面的函数。

84template
85struct isa_impl_warp {
86// When From !=SimplifiedType, we can simplify the type some more by using
87// thesimplify_type template.
88static booldoit(const From &Val) {
89returnisa_impl_wrap 90typename simplify_type::SimpleType>::doit(
91simplify_type::getSimplifiedValue(Val));
92}
93};
94
95template
96struct isa_impl_wrap {
97// When From ==SimpleType, we are as simple as we are going to get.
98static booldoit(const FromTy &Val) {
99return isa_impl_cl::doit(Val);
100}
101};

在89行对isa_impl_wrap的调用中,也再次使用simplify_type对Y的化简类型(SimpleFrom)进行类型化简。同时对给定的值进行转换(通过getSimplifiedValue,91行)。一旦From与SimpleFrom达成一致,isa_impl_wrap的doit方法(98行)调用isa_impl_cl的对应的方法。

54template struct isa_impl_cl {
56static inline bool doit(constFrom &Val) {
57return isa_impl::doit(Val);
58}
59};
60
61template struct isa_impl_cl {
62static inline bool doit(constFrom &Val) {
63return isa_impl::doit(Val);
64}
65};
66
67template struct isa_impl_cl {
68static inline bool doit(constFrom *Val) {
69return isa_impl::doit(*Val);
70}
71};
72
73template struct isa_impl_cl {
74static inline bool doit(constFrom *Val) {
75return isa_impl::doit(*Val);
76}
77};
78
79template struct isa_impl_cl{
80static inline bool doit(constFrom *Val) {
81return isa_impl::doit(*Val);
82}
83};

上面所有的定义都调用下面这个类的doit方法。

47template
48struct isa_impl {
49static inline bool doit(constFrom &Val) {
50returnTo::classof(&Val);
51}
52};

为了实现isa,涉及的类必须定义50行的classof静态成员函数。当然classof的语义由定义它的类来决定,这带来了很高的灵活性。比如,我们不仅可以声明派生类isa基类,甚至不相关的类也可以声明为isa关系。
cast函数 cast函数的定义也是类似的。

192template
193inline typename cast_retty::ret_type cast (const Y&Val) {
194assert(isa(Val) && "cast() argument ofincompatible type!");
195return cast_convert_val 196typename simplify_type::SimpleType>::doit(Val);
197}

注意178行的const_cast。到这里我们可以明白,所谓的cast过程是依靠simplify_type的机制实现的。还有,const_cast之前是C形式的强制类型转换,不过前面cast_convert_val的递归调用能保证Val(注意通过getSimplifiedValue转换)与这个类型相容。

165template struct cast_convert_val {
166// This is not asimple type, use the template to simplify it...
167static typename cast_retty::ret_type doit(const From &Val) {
168returncast_convert_val 169typenamesimplify_type::SimpleType>::doit(
170simplify_type::getSimplifiedValue(Val));
171}
172};
173
174templatestruct cast_convert_val{
175// This _is_ asimple type, just cast it.
176static typenamecast_retty::ret_type doit(const FromTy &Val) {
177typename cast_retty::ret_type Res2
178= (typename cast_retty::ret_type)const_cast(Val);
179return Res2;
180}
181};
dyn_cast函数 利用isa与cast,构建了另一个对应C++的dynamic_cast操作符的dyn_cast函数。

218template
219inline typename cast_retty::ret_type dyn_cast (constY &Val) {
220return isa(Val) ? cast(Val) :0;
221}
【Llvm的类型转换系统】

    推荐阅读