LLVM编译器
LLVM IR
编译器的中间表示 串联起编译器内各层级和模块 (intermediate representation)
为什么需要中间表示
抽象与语义
需要进行抽象,抛弃掉细枝末节帮助着眼于主要矛盾
使用抽象而产生的问题秒速称为模型,模型能够带给我们清晰的语义,通过模型和语义我们才能够进行精确的严谨推理。编译器需要清晰的语义来证明代码转换的正确性。
正确与优化
首要任务是要保证转化的正确性,优化是次要的考虑。(不正确的良好优化没有意义) 生成中可能会违反语义,但是每次转换遍历应该保证原子性,也就说之内可能不完全遵守。每次转换后需要进行验证来保证正确性。
递降和递升
递降后边的转换更具有结构劣势,具有的信息过于散缺乏高层次信息。 本质性问题是强耦合,在解决复杂问题时应尝试解耦。
效率工具
进行高级抽象带来的开发效率是显而易见的,而且这种取舍是可以接受的。 高级抽象带来的不一定是最高的效率,最高效的代码可能是通过汇编语言操作寄存器而来的。 通过统一的语言描述任务,再通过执行引擎执行,再到具体的操作调度,也可以看成一种编译。 (可能这个地方有点像解释器) 编译器要对中间环节进行一系列变换来链接不同层次的抽象。
中间表示的形态和兼容性
主要有三种形态
用于高效分析和变换的内存表示 用于存储和交换的字节码 用于阅读和纠错的文本表示
不同的需求需要不同的表示,无关对错只是角度不同而已。
中间表示的设计概念
希望和要求:
中间表示的操作具有清晰明确的语义 操作能够正交,有助于定义标准形态以减少变换考虑的情况 避免出现重复信息 尽可能的保持高层次信息 其他
反例:
对特殊功能模块,破坏了中间表示的正交性 SPIR-V中编译单元声明了所需的硬件能力,但是通过分析其实可以得到,不过声明带来的好处就是能够加速了实际的运行 对已有的低层次语言,需要对其进行提升,例如自动向量化
很多目标是相互冲突的,如何进行特定的优化是困难的,对编译器解绑来针对特定领域进行优化是能够提升效率的。(顺便提一句这样是会增加工程量的)
三种抽象表示
LLVM IR
2003 编译器解绑与模块化的实践
控制流 基础块 静态单赋值
是一种完备的表示 通过库的形式进行组织