3.1. dyn_cast()与cast()
C++支持类型间的自动转换(如operator =声明的转换),但在转换的调用链里自动转换只能调用一次,这固然是避免给编译器带来过分的复杂性,但更重要的是允许自动转换接力调用几乎很难避免出现递归调用,而且调用链过长会很快失去控制,给人带来意想不到的结果。但是,C++原生的类型转换系统对于LLVM/MLIR来说局限性太大,因此,LLVM打造了自己的类型转换系统,它仿造C++的惯例,给出了自己的类型转换函数:cast、dyn_cast。显然,它们分别对应其他cast与dynamic_cast。它们与C++版本的最大不同在于:cast、dyn_cast都支持无限次自动转换(这在用户眼皮底下发生,但用户需要提供一些指定的方法)。在这个体系中,dyn_cast最有代表性,llvm里一共定义了3个版本,它们的区别在于函数参数类型:
331 template <class X, class Y>
332 LLVM_NODISCARD inline std::enable_if_t<
333 !is_simple_type
334 dyn_cast(const Y &Val) {
335 return isa
336 }
337
338 template <class X, class Y>
339 LLVM_NODISCARD inline typename cast_retty
340 return isa
341 }
342
343 template <class X, class Y>
344 LLVM_NODISCARD inline typename cast_retty
345 return isa
346 }
在这些函数里用到isa()与cast(),isa()是这样的:它检查参数的类型是否与模板参数里给出的类型一致。
141 template <class X, class Y> LLVM_NODISCARD inline bool isa(const Y &Val) { // 最终调用的函数
142 return isa_impl_wrap
143 typename simplify_type<const Y>::SimpleType>::doit(Val);
144 }
145
146 template <typename First, typename Second, typename... Rest, typename Y>
147 LLVM_NODISCARD inline bool isa(const Y &Val) {
148 return isa
149 }
实际上,isa()支持对某个类型列表,检查指定类型是否与其中一个类型一致。而两个特定类型比较的实现是由isa_impl_wrap这个类提供的:
116 template<typename To, typename From, typename SimpleFrom>
117 struct isa_impl_wrap {
118 // When From != SimplifiedType, we can simplify the type some more by using
119 // the simplify_type template.
120 static bool doit(const From &Val) {
121 return isa_impl_wrap 122 typename simplify_type 123 simplify_type<const From>::getSimplifiedValue(Val)); 124 } 125 }; 126 127 template<typename To, typename FromTy> 128 struct isa_impl_wrap 129 // When From == SimpleType, we are as simple as we are going to get. 130 static bool doit(const FromTy &Val) { 131 return isa_impl_cl 132 } 133 }; 为了支持无限次自动转换,这里指出了3个类型:To、From、SimpleFrom。其中,被转换值从From类型转换到SimpleFrom类型,这个SimpleFrom类型还可能进一步转换为另一个SimpleFrom类型,直到From与SimpleFrom类型一致为止,这意味着From不能再“简化了”。这时我们使用128行的isa_impl_wrap特化定义。 首先,我们先看一下完成从From到SimpleFrom的simplify_type类。注意,如果存在llvm所不知道的From到SimpleFrom的转换,必须提供这个目的的simplify_type特化版本。如果不提供,将使用simplify_type的非特化版本(llvm对自己的数据结构定义了若干simplify_type特化版本): 33 template<typename From> struct simplify_type { 34 using SimpleType = From; // The real type this represents... 35 36 // An accessor to get the real value... 37 static SimpleType &getSimplifiedValue(From &Val) {