编译器中间表示的设计哲学:从单层IR到多层次抽象的六十年演进

1957年,IBM的John Backus团队发布了第一个Fortran编译器。这个改变计算机科学历史的程序有一个鲜为人知的细节:它没有使用任何我们今天称为"中间表示"的东西。编译器直接从源代码生成机器码,所有优化都在生成过程中即时完成。这种方式在今天看来几乎不可想象,但它恰恰揭示了编译器设计中一个根本性的问题——为什么我们需要中间表示? ...

17 min · 8138 words

函数内联:编译器如何决定把代码复制到哪里

1972年,David Gries在《Compiler Construction for Digital Computers》中描述了一个看似简单的优化:把被调用函数的代码直接复制到调用点。五十年后,这个"复制粘贴"技术仍然是编译器优化中最关键、最复杂,也最容易被误解的一环。 ...

15 min · 7142 words

编译器寄存器分配:从图着色到线性扫描的四十年算法博弈

1981年,IBM的研究员Gregory Chaitin面临一个棘手的问题:如何让PL.8编译器生成的代码更高效?当时,程序中的变量远多于处理器寄存器,编译器必须决定哪些变量驻留在寄存器,哪些被"驱逐"到内存。这个看似简单的资源分配问题,实际上是计算机科学中最经典的NP完全问题之一。 ...

10 min · 4809 words

数据库查询引擎为何跑不过手写代码?从火山模型到编译执行的三十年突围

2008年,一位数据库研究员做了一个简单的实验:他用C++手写了一段处理TPC-H Query 1的代码,然后与当时最先进的数据库系统对比性能。结果令人震惊——手写代码比数据库快了整整一个数量级。这个结果刺痛了数据库社区:为什么精心设计的查询引擎,竟然输给了几行手写的循环? ...

9 min · 4500 words

别被编译器骗了:为什么你的安全检查代码可能正在被悄悄删除

Google Native Client团队曾遭遇过一次令人后背发凉的漏洞:沙箱逃逸保护机制被编译器悄无声息地删除了。问题出在一行看似无害的代码重构:将 aligned_tramp_ret = tramp_ret & ~(nap->align_boundary - 1) 改成了 return addr & ~(uintptr_t)((1 << nap->align_boundary) - 1)。 ...

8 min · 3607 words