LLVM 的基本类型是如何设计的?

LLVM 好像没有 bool 类型, bool 就是 bit=1 的 int, int 也不区分 signed/unsigned, 这个无法理解, 我…
关注者
78
被浏览
13,463

9 个回答

对底层来说signed int和unsigned int的区别很小,只有某些指令会有影响,很多处理器的汇编就是这样的。

LLVM里面就是通过不同的指令来区分,譬如sdiv和udiv,还有icmp不同的condition code等。另外还有nsw和nuw这种flag来标记signed和unsigned overflow。

谢谢楼上的链接,还有这样的历史,蛮有意思的。

基类型的定义是编译器设计的一个最基本问题,似乎就是整数和浮点再加上宽度。但其实历史上还是会有大相径庭的设计。例如Open64里面的整数就和早期的llvm一样区分符号,而且更进一步大多数指令都适用浮点和整数。

所以在Open64代码里面会经常需要判断指令的类型是整数还是浮点,因为很少有分析同时适用两者。所以经验教训就是,浮点和整数有根本区别, 所以最好区分它们的所有操作。

整数的符号问题更复杂一些,似乎有时候我们在乎是不是有符号,有时候我们不在乎。所以怎么实现都有一定问题。但其实还有一个基本问题,就是我们没有办法表示一个指令不在乎有符号与否,或者一个变量不区分有没有符号位。所以还是在数据类型上不要区分两者,而是在指令上加以区分比较合理一些。

从这个更改我们也看到,取消整数类型符号需要同时增加一些特定符号操作,例如有符号位移操作,而另外一些操作需要增加一些标记,例如nuw这些。

另外这个改动使得后端的处理更容易,实际上是通过去除一些高层次的特性。因为在源语言层次,所有的指令和变量,即使是临时的,都有非常明确的类型。

类型转换和比较操作的细化这部分其实是连带的,这部分非常明确的是必要的合理化。

归结起来就是因为指令集和语言特性,编译器在定义基础类型时尽量使分析和优化代码可以最小化。而llvm目前的实现是一种比较好的平衡(这里不同意见大概也是有的)。