这是一篇关于 LLVM 集成汇编器中片段优化的博客文章,主要内容总结如下:
- 改进历程:2009 年引入 LLVM 集成汇编器,其片段设计简单,随着时间推移,众多特性依赖此设计,导致片段表示优化日益困难,文中列举了多年来增加复杂性的特性。
- 优化片段管理:直接减少 MCFragment 对象的内存占用,包括减少 MCInst 内联元素计数、减小 MCDataFragment 大小、移动 MCFragment::Atom 等,还将链表从双向改为单向以简化管理,并解决了因某些特性导致的复杂性问题。
- 追求可简单销毁的片段:历史上 MCFragment 子类依赖 SmallVector 存储内容和修正,存在存储小对象效率低和非简单析构的问题,2024 年进行了改进,将片段内容和修正存储在线外,并重新设计了 MCRelaxableFragment 的数据结构。
- 减少片段数量:LLVM 21.1 之前,每个跨距依赖指令都在单独的片段中,现在将固定大小部分和可选的可变大小尾部存储在单个片段中,大大减少了片段数量。
- 减少指令编码开销:自 2023 年 5 月以来,致力于减少 MCObjectStreamer 中编码单个指令的开销,进行了一系列相关优化,同时注意到 x86 指令填充特性带来的开销。
- 急切创建片段:优化编码指令的过程,维护一个保证没有可变大小尾部的当前片段,减少了函数添加数据时的检查,提高了效率。
- 片段内容在尾随数据中:利用 MCFragment 类管理的四种可追加数据,将固定大小内容作为尾随数据存储,提高数据局部性和简化元数据,但也有一些需要考虑的因素。
- 弃用复杂性:NativeClient 的捆绑对齐模式:Google 的 NativeClient 项目的捆绑对齐模式在 LLVM 汇编器中实现存在问题,带来性能损失和内部工作复杂性,经过一系列更改最终将其移除。
- 经验教训:早期设计选择会对未来代码产生深远影响,如 LLVM MC 的初始设计导致优化困难;存在“货拜编程”和“雪球效应”,复制现有解决方案会增加复杂性和冗余代码;某些特性如 NaCl 的捆绑对齐模式引入了不必要的复杂性和性能开销。
- 附录:GNU 汇编器如何处理片段:追溯到 1987 年,GNU 汇编器(GAS)在片段处理方面展现出远见,其片段分配器设计在近四十年前就已具备相关理念,令人惊叹。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。