10.万花筒:结论和其他有用的LLVM花絮
- 教程结论
- 目标独立
- 安全保障
- 语言特定优化
- 技巧和窍门
- 垃圾收集堆栈框架
10.2 LLVM IR的属性
我们在LLVM IR表格中有一些关于代码的常见问题 - 让我们现在就把这些问题解决掉,好吗?
万花筒是“便携式语言”的一个例子:用Kaleidoscope编写的任何程序在运行它的任何目标上都会以相同的方式工作。许多其他语言都有这个属性,例如lisp,java,haskell,javascript,python等(请注意,虽然这些语言是可移植的,但不是所有的库都是)。
LLVM为代码提供紧凑的,与目标无关的表示这一事实让很多人兴奋不已。不幸的是,这些人在询问有关语言可移植性的问题时,通常会考虑C语言或来自C家族的语言。我说“不幸的是”,因为除了传送源代码之外,实际上没有办法让(完全通用的)C代码可移植(当然,C源代码实际上也不是可移植的 - 所以端口真的很旧应用程序从32位到64位?)。
C的问题(再次,完全普遍性)是它充满了目标特定的假设。作为一个简单的例子,预处理器在处理输入文本时经常破坏性地从代码中删除目标独立性:
10.2.2 安全保障
上面的许多语言也是“安全”语言:用Java编写的程序不可能破坏其地址空间并使进程崩溃(假设JVM没有错误)。安全性是一个有趣的属性,需要结合语言设计,运行时支持和操作系统支持。
当然可以在LLVM中实现安全语言,但LLVM IR本身并不能保证安全。LLVM IR允许不安全的指针强制转换,在释放错误之后使用,缓冲区溢出以及各种其他问题。安全性需要在LLVM之上作为一个层实现,并且方便地,几个小组已经对此进行了调查。如果您对更多细节感兴趣,可以在llvm-dev邮件列表上询问。
LLVM关闭许多人的一件事是,它并没有在一个系统中解决所有世界的问题(抱歉’世界饥饿’,其他人将不得不在其他日子解决你)。一个具体的抱怨是人们认为LLVM无法执行高级语言特定优化:LLVM“丢失了太多信息”。
首先,你是对的,LLVM确实会丢失信息。例如,在撰写本文时,无法在LLVM IR中区分SSA值是来自ILP32机器上的C“int”还是C“long”(调试信息除外)。两者都被编译成’i32’值,并且有关它的来源的信息丢失了。这里更普遍的问题是LLVM类型系统使用“结构等价”而不是“名称等价”。令人惊讶的另一个地方是,如果你在高级语言中有两种具有相同结构的类型(例如,两个具有单个int字段的不同结构):这些类型将编译成单个LLVM类型,这将是不可能的告诉它是什么来的。
其次,虽然LLVM确实丢失了信息,但LLVM并不是固定的目标:我们会以多种不同的方式继续增强和改进它。除了添加新功能(LLVM并不总是支持异常或调试信息)之外,我们还扩展了IR以捕获用于优化的重要信息(例如,参数是符号还是零扩展,有关指针别名的信息等)。许多增强功能都是用户驱动的:人们希望LLVM包含一些特定的功能,因此他们继续并扩展它。
第三,可以轻松添加特定于语言的优化,并且您可以选择多种方式进行优化。作为一个简单的例子,很容易添加特定于语言的优化过程,这些过程“了解”为语言编译的代码。在C系列的情况下,有一个“知道”标准C库函数的优化过程。如果在main()中调用“exit(0)”,它知道将其优化为“return 0;”是安全的,因为C指定了“exit”函数的作用。
除了简单的库知识外,还可以将各种其他语言特定信息嵌入到LLVM IR中。如果您有特殊需求并碰壁,请将主题放在llvm-dev列表中。在最糟糕的情况下,您可以始终将LLVM视为“哑代码生成器”,并在特定语言的AST上实现您在前端所需的高级优化。
10.3 提示和技巧
如果您试图保持编译器生成的代码“目标独立”,那么有一件有趣的事情是,您经常需要知道某些LLVM类型的大小或llvm结构中某些字段的偏移量。例如,您可能需要将类型的大小传递给分配内存的函数。
不幸的是,这可以在不同的目标之间变化很大:例如,指针的宽度通常是针对特定目标的。但是,有一种 聪明的方法可以使用getelementptr指令 ,允许您以可移植的方式计算它。