Llvm内置了一个类型转换系统,并定义了类似于dynamic_cast这样的转换函数。Llvm底层的很大部分是由模板类构成的,这个转换系统对于模板类间的类型判断及转换至为重要。以下只是描述这个转换系统的一个框架,该系统的正确实现,还依赖于参与模板类正确实现某些函数(下面会提到)。
cast_retty类 cast_or_null是llvm所提供的类型转换系统的部分,这是一个有趣的模板实现。这个实现在llvm-3.1/include/llvm/support/Casting.h。
202template
203inline typename cast_retty
204if (Val == 0)return0;
205assert(isa
206returncast
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
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
148};
149
150template
151structcast_retty_wrap
152// When thesimplified type is equal to the from type, use it directly.
153typedef typename cast_retty_impl
154};
看到cast_retty_wrap非特化版本在147行又递归回了cast_retty。这是怎么回事?在cast_retty定义的159行,simplify_type的定义如下:
30template
31typedefFrom SimpleType;
// The realtype this represents...
32
33// An accessor toget the real value...
34staticSimpleType &getSimplifiedValue(From &Val) { returnVal;
}
35};
36
37template
38typedef const From SimpleType;
39staticSimpleType &getSimplifiedValue(const From&Val) {
40returnsimplify_type
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
123typedefTo& ret_type;
// Normal case, return Ty&
124};
125template
126typedef const To &ret_type;
// Normal case,return Ty&
127};
128
129template
130typedef To*ret_type;
// Pointer arg case, return Ty*
131};
132
133template
134typedef const To* ret_type;
// Constant pointer arg case, return const Ty*
135};
136
137template
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
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
91simplify_type
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
100}
101};
在89行对isa_impl_wrap的调用中,也再次使用simplify_type对Y的化简类型(SimpleFrom)进行类型化简。同时对给定的值进行转换(通过getSimplifiedValue,91行)。一旦From与SimpleFrom达成一致,isa_impl_wrap的doit方法(98行)调用isa_impl_cl的对应的方法。
54template
56static inline bool doit(constFrom &Val) {
57return isa_impl
58}
59};
60
61template
62static inline bool doit(constFrom &Val) {
63return isa_impl
64}
65};
66
67template
68static inline bool doit(constFrom *Val) {
69return isa_impl
70}
71};
72
73template
74static inline bool doit(constFrom *Val) {
75return isa_impl
76}
77};
78
79template
80static inline bool doit(constFrom *Val) {
81return isa_impl
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
194assert(isa
195return cast_convert_val
197}
注意178行的const_cast。到这里我们可以明白,所谓的cast过程是依靠simplify_type的机制实现的。还有,const_cast之前是C形式的强制类型转换,不过前面cast_convert_val的递归调用能保证Val(注意通过getSimplifiedValue转换)与这个类型相容。
165template
166// This is not asimple type, use the template to simplify it...
167static typename cast_retty
168returncast_convert_val
170simplify_type
171}
172};
173
174template
175// This _is_ asimple type, just cast it.
176static typenamecast_retty
177typename cast_retty
178= (typename cast_retty
179return Res2;
180}
181};
dyn_cast函数 利用isa与cast,构建了另一个对应C++的dynamic_cast操作符的dyn_cast函数。
218template
219inline typename cast_retty
220return isa
221}
【Llvm的类型转换系统】