当编译器让你惊喜

Lobsters Hottest 新闻

摘要

Matt Godbolt 探讨了编译器优化如何将 O(n) 求和循环转换为 O(1) 的闭式解,突出了 Clang 和 GCC 如何采用循环展开和数学简化等复杂技术来大幅提升代码性能。

<p><a href="https://lobste.rs/s/vugypt/when_compilers_surprise_you">评论</a></p>
查看原文 导出为 Word 导出为 PDF
查看缓存全文

缓存时间: 2026/04/20 14:44

# 编译器令人惊喜的时刻 — Matt Godbolt 的博客 来源:https://xania.org/202512/24-cunning-clang 作者:我,由 LLM 校对。详细信息见文末。 编译器时不时会用一些真正聪明的技巧让我惊叹。当我第一次看到这个优化时,几乎不敢相信。我在研究循环优化时写了这个简单的函数,它用来求和到给定值的所有数字: 到目前为止看起来还不错:GCC 做了一些初步检查,然后进入一个循环,使用 `lea` 高效地求和(我们之前见过这个(https://xania.org/202512/02-adding-integers))。但仔细看循环,我们会发现一些不寻常的东西: ``` .L3: lea edx, [rdx+1+rax*2] ; result = result + 1 + x*2 add eax, 2 ; x += 2 cmp edi, eax ; x != value jne .L3 ; keep looping ``` 编译器巧妙地意识到它可以一次处理两个数字¹(https://xania.org/202512/24-cunning-clang#fn:check),利用了这样一个事实:我们会加上 `x` *和* `x + 1`,这等于加上 `x*2 + 1`。非常巧妙,我同意! 如果你把优化器调到 `-O3`,你会看到编译器更加努力地使用并行加法来向量化循环。非常聪明。 这都是 GCC 的表现。让我们看看 clang 对我们代码的处理: 这是我差点从椅子上摔下来的地方:**根本没有循环**!Clang 检查 `value` 是否为正,如果是,它执行: ``` lea eax, [rdi - 1] ; eax = value - 1 lea ecx, [rdi - 2] ; ecx = value - 2 imul rcx, rax ; rcx = (value - 1) * (value - 2) shr rcx ; rcx >>= 1 lea eax, [rdi + rcx] ; eax = value + rcx dec eax ; --eax ret ``` 对我来说,这到底在干什么根本不明显。通过回推数学,这等价于: ``` v + ((v - 1)(v - 2) / 2) - 1; ``` 展开括号: ``` v + (v² - 2v - v + 2) / 2 - 1 ``` 重新整理一下: ``` (v² - 3v + 2) / 2 + (v - 1) ``` 将 `(v - 1)` 乘以 2 / 2: ``` (v² - 3v + 2) / 2 + (2v - 2)/2 ``` 合并这些项并化简: 简化和因式分解得到 `v(v - 1) / 2`,这就是"整数和"的闭式解!真是令人惊叹²(https://xania.org/202512/24-cunning-clang#fn:why)——我们从按照编写方式的 O(n) 算法,转变成了 O(1) 的算法! 我喜欢尽管和编译器打了二十多年交道,它们仍然能让我惊喜和欣喜。多年来为了让编译器优秀而投入的经验和工作确实令人谦卑,也令人鼓舞。 我们快到这个系列的尾声了——还有很多要说,但那得等下一次了。明天会有点不同:到时见! *观看伴随这篇文章的视频(https://youtu.be/V9dy34slaxA)。* --- *这篇文章是编译器优化降临节 2025(https://xania.org/AoCO2025-archive) 的第 24 天,一个 25 天的系列,探索编译器如何转换我们的代码。* *← 有点变化(https://xania.org/202512/23-switching-it-up) | 谢谢(https://xania.org/202512/25-thank-you) →* *这篇文章由人类(Matt Godbolt(https://xania.org/MattGodbolt))撰写,由 LLM 和人类审阅和校对。* *在 Patreon(https://patreon.com/c/mattgodbolt) 或 GitHub(https://github.com/sponsors/compiler-explorer) 上支持 Compiler Explorer,或在 Compiler Explorer Shop(https://shop.compiler-explorer.com/) 购买 CE 产品。* 发布于 2025 年 12 月 24 日 CST 06:00:00。

相似文章

使用并行Claude团队构建C编译器

Anthropic Engineering

Anthropic研究员展示了如何使用16个并行Claude实例自主构建一个基于Rust的C编译器,该编译器能够编译Linux内核。文章详细介绍了这一多智能体自主编码实验的架构、成本和经验教训。

用 Zig 写一个 C 编译器

Hacker News Top

一位开发者记录了用 Zig 语言、按照 Nora Sandler 的教程系列构建名为 paella 的 C 编译器的全过程。

让 Julia 达到 C++ 的速度(2019)

Hacker News Top

这是 BYU FLOW Lab 于 2019 年发布的一篇博客文章,以真实的空气动力学应用(涡粒子法)作为基准测试,探讨如何优化 Julia 代码以匹配 C++ 的性能。作者分享了在 Julia 中实现高性能计算的经验,涵盖类型声明、JIT 编译以及代码优化技巧。