
2025/12/24 22:27
コンパイラがあなたを驚かせる時 --- *Titleの翻訳は「コンパイラがあなたを驚かせるとき」としました。長さや意味は元の英語に合わせつつ、自然で丁寧な日本語にしています。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
記事では、現代のコンパイラが整数をある値まで合計する単純なループを即座に1行の計算に変える方法を示しています。最大最適化(-O3)で実行されたGCCは、低レベル命令(
lea とベクトル化加算)を使用してループを書き換え、一サイクルあたり2つの数値を処理できるようにし、イテレーション回数を半分に削減します。Clangはさらに進みます:正の値の場合、ループ全体を完全に排除し、閉形式式 (v(v-1)/2) をアセンブリで imul、shr、そして最後に ret で直接計算します。著者は生成されたコードからこの結果を導き出し、コンパイラが最適化中に代数的恒等式をどのように発見するかを示しています。この投稿は Matt Godbolt の「Advent of Compiler Optimisations 2025」シリーズ(24 Dec 2025 06:00 CST)の一部であり、LLM と人間によってレビューされました。著者は20年の経験後に得た驚きとインスピレーションを指摘し、将来のコンパイラリリースでも同様のパターン認識最適化が登場し続けることを示唆しています本文
私は自分で書き、LLM に校正してもらったものです。
詳細は最後にあります。
たまにコンパイラが本当に賢いテクニックを見せてくれることがあります。最初にこの最適化を目にしたとき、ほぼ信じられませんでした。私はループ最適化を調べており、与えられた値までの全数を足し合わせるだけのシンプルな関数を書いていました。
...
ここまではまあまあで、GCC はいくつかの前処理チェックを行った後、
lea を使って効率的に数値を足し合わせるループに落ち込みます(以前見たことがあります)。しかしループをもう少し掘り下げてみると、何か変わった点があるのです。
.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
コンパイラは巧妙に、
x と x+1 を足し合わせることが同じく x*2 + 1 になると判断し、一度に二つの数を処理できるようにしました。非常に狡猾ですね! -O3 にするとさらにハードで、並列加算を使ってループをベクトル化します。すべてが非常に賢明です。
これは GCC の話でした。では Clang は同じコードをどう扱うのでしょうか。
...
ここで私は椅子から落ちそうになりました:実際にはループがありません!Clang は正の値をチェックし、もしあれば次のようにします。
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 が得られます。これは「整数の総和」の閉形式解です! 本当に驚くべきことで、書いた O(n) アルゴリズムが O(1) に変わったのです。
私は二十年以上コンパイラを扱ってきましたが、それでもまだ驚かされることがあります。コンパイラを素晴らしくするために注ぎ込まれた経験と努力は本当に謙虚で、刺激的です。
このシリーズももう終わりに近づいています – もっと話したいことは山ほどありますが、それは次の機会に。明日は少し違う内容になります:それではまた!
この記事には付随する動画があります。
これは「2025年コンパイラ最適化 Advent of Compiler Optimisations」シリーズ第24日目です。25日間にわたり、コンパイラが私たちのコードをどのように変換してくれるかを探ります。
この記事は人間(Matt Godbolt)によって書かれ、LLM と人間によってレビューと校正が行われました。
Compiler Explorer を Patreon または GitHub でサポートするか、コンパイラエクスプローラーショップで CE 製品を購入してください。
2025年12月24日06:00:00 CST に投稿しました。