世界を動かす技術を、日本語で。

クロードのCコンパイラとGCCの比較

概要

  • Anthropic社のClaude が完全自動でCコンパイラ「CCC」を開発した事例の検証
  • GCC との比較実験をSQLiteとLinuxカーネルで実施
  • CCCはCコードの正確なパース はできるが、最適化やリンカ処理で課題
  • SQLiteの機能的正しさは確保 されるも、実行速度はGCCに大きく劣後
  • リンクエラーやパフォーマンス低下 の根本原因を技術的に解説

Claudeが自動生成したCコンパイラ「CCC」の実力検証

  • Anthropic社のClaude Opus 4.6 が100%自動生成したCコンパイラ「CCC」の性能検証
  • CCCはRust製 で、x86-64/i686/AArch64/RISC-V 64に対応
  • フロントエンド、SSAベースIR、最適化、コード生成、アセンブラ、リンカ、DWARFデバッグ情報まで 全て自作実装
  • GCCとCCC を同一ハードウェア・同一ソースで比較検証
  • SQLite(標準C)とLinuxカーネル(超巨大Cコード) をテスト対象に選定

Cコンパイルの4段階と各工程の難易度

  • プリプロセッサ :#includeや#define等の前処理、ソース展開
  • コンパイラ :C言語構文からアセンブリ生成、型チェックや最適化も担当
  • アセンブラ :アセンブリを機械語(オブジェクトファイル)に変換
  • リンカ :複数オブジェクトを一つの実行ファイルに結合、アドレス解決やメモリ配置
    • リンカ工程が最難関 :複雑な再配置やシンボル管理、PIE、スクリプト対応等

CCCとGCCの比較検証方法

  • Debian系VM(6vCPU, 16GB RAM) 上で同一条件テスト
  • GCC 14.2.0 vs CCC(gcc_m16機能で一部GCC委譲)
  • .S(アセンブリ)はGCC、.cはCCC で処理するラッパースクリプト運用
  • SQLiteベンチマーク :I/O影響排除、42種SQL操作・10フェーズでCPU性能重視
  • Linuxカーネル :v6.9(x86_64 defconfig)、ビルド完了までの挙動観察

主な検証結果と数値比較

  • カーネルビルド時間 :GCC 73.2分、CCC 42.5分(リンク失敗で未完了)
  • カーネルビルド結果 :GCCは成功、CCCはリンク失敗(約40,784件の未定義参照)
  • SQLiteコンパイル速度 :GCC(-O0)64.6秒、CCC 87.0秒(1.3倍遅い)
  • SQLiteバイナリサイズ :GCC 1.55MB、CCC 4.27MB(約3倍)
  • SQLite実行時間 :GCC(-O0)10.3秒、CCC 2時間6分(737倍遅い)
  • メモリ使用量 :CCCはGCC比で5.9倍消費
  • クラッシュ・正当性テスト :両者とも全パス

カーネルビルド失敗の詳細

  • CCCは全Cファイルを正確にコンパイル (0エラー、96警告)
  • リンカで40,784件の未定義参照 :__jump_table, __ksymtab等の再配置・シンボル生成ミス
  • リンカ実装の難しさ を象徴、C言語処理自体は問題なし

SQLiteベンチマーク詳細

  • CCCは最適化フラグ(-O2等)を無視 :常に同一バイナリ生成
  • GCCの-O2は多段最適化(レジスタ割付、ループ展開、関数インライン化等) を実施
    • CCCは最適化パスが15個あるが、全レベルで同一動作
  • 「最適化なし」での比較が公平 :CCCは1.3倍遅いのみ
  • 最適化有効時はGCCが圧倒的に高速 :CCCは全く追いつけない

実行性能とボトルネック分析

  • 単純クエリは1~7倍遅いが、複雑なJOINやサブクエリは数千~十万倍遅い
  • 主原因はレジスタスピリング :変数がレジスタに乗らずスタック多用
    • SQLiteの主要関数(sqlite3VdbeExec)はローカル変数100個超、巨大switch文
    • CCCはほぼ全変数をスタックに退避し、スタックオフセットが1万バイト超に達する例も
  • GCCは最適化なしでも効率的なスタック・レジスタ管理 を実施

今後の課題とAI自動生成コンパイラの展望

  • C言語の正確なパース・アセンブリ生成はAIでも可能
  • 最適化・リンカ・アセンブラの精度と効率性が圧倒的に不足
  • GCCは40年分の知見と最適化技術の塊、現状のAI生成コンパイラは実用には遠い
  • CCCの「動くCコンパイラを完全自動生成できた」点は画期的
  • 今後は最適化パスの強化・リンカ精度向上が課題

まとめ・総評

  • Claude Opus 4.6によるCCCは「Cコードを通す」レベルには到達
  • 実用レベル(高速・コンパクト・複雑コード対応)には大きな壁
  • AI自動生成コンパイラの「現状の限界」と「今後の可能性」 を示す好事例

Hackerたちの意見

Cの最適化されてない状態がどれだけ遅いかを見るのは本当に面白いね。Cが他の言語に比べてパフォーマンスで圧倒的に優れているのを見慣れているから、まるでそれが言語自体に内在する特性だと思っちゃう。でもベンチマークを見ると、SQLite3の最適化されてないビルドはCCCで12倍遅く、最適化されたビルドでも20倍遅いんだ。これはすごい!CCCをディスってるわけじゃなくて、GCCが本来は速いとされる言語からどれだけスピードを引き出しているかに感心してるんだ。

Cのスピードはまだまだ言語自体に内在している部分が大きいよ。プリミティブは実際のシリコンに直接関連してるからね。関数呼び出しは実際には呼び出し命令に変わるし(インライン化されることもある)。構造体のバイトの順序はメモリ上での存在の仕方だし、ポインタの逆参照はロード/ストアになる。逆もまた然り。インタプリタ言語はこのハードウェアとの関連がないから遅いんだ。レジスタのシャッフルをたくさんするクソみたいなコンパイラだと、この関連が失われる。特に、1000倍遅くなる原因となった特定の関数の定数スピリングがあると、CコードがPythonコードに近く見えるようになる(Pythonではすべての変数が数回の逆参照を必要とするからね)。

まあ、常に物事を遅くすることはできるよ。最適化しない、または低最適化のコンパイラは、これよりもはるかに速いものがたくさんある。TCCが最も有名な例かもしれないけど、GCCの-O1と-O2の間のパフォーマンスを持つ他のCコンパイラもたくさんある。私の理解では、CCCは-O0よりもパフォーマンスが悪いらしいけど、正直驚きだよ。だって-O0は達成するのが難しい目標じゃないはずだから。私の理解では、-O0ではCは基本的にマクロがアセンブリに展開されるだけで、少しの演算の順序が加わるだけなんだ。レジスタの割り当てもやってないと思う。

これはこの議論の両方の視点を示す良い例だと思う。LLMコーディングエージェント支持派:「ほら!エージェントが数時間で作った動くコンパイラだ!すごい!」反対派:「でも、これは動くコンパイラじゃないよ。それに、どれだけ少ない時間で作ったかは関係ない。動かないんだから、無意味だよ。」支持派:「確かに、でもエージェントにそれを直させられるよ。」反対派:「本当にできるの?コードベースが複雑になるほど、エージェントのパフォーマンスは悪くなるのを見てきたよ。コンパイラの複雑な問題を直すのはエージェントには難しいと思う。それに、もし直せるなら、なんで直してないの?」支持派:「今はそうかもしれないけど、次の世代が直すよ。」反対派:「そうかもね。最近の世代はどんどん良くなってるけど、まだこの種の複雑さにうまく対処できてるわけじゃない。」支持派:「でも、見て!これはすごい!数時間でコンパイラができたんだ!GCCをここまで持ってくるのに何百万時間もかかったんだよ?こんな風に比較するのはフェアじゃない!」反対派:「AnthropicはLinuxカーネルをコンパイルできる動くコンパイラを作ったと言った。GCCは通常Linuxカーネルをコンパイルするために使うものだから、比較は招かれたものだよ。結果的に(理由はどうあれ)CCCはGCCができるLinuxカーネルのコンパイルに失敗した。AIの期待が現実に合わないってことだね。」支持派:「でも、LLMを使い始めて数年、エージェントを使い始めてからも1年しか経ってないんだ。これはまだ始まりに過ぎない!」反対派:「それは本当だけど、これは面白いね。でもこの技術には他にもたくさんの疑問がある。急いで進めて全部台無しにしないようにしよう。」

こんな風に比較するのはフェアじゃない!この議論で支持派に傾いている私としては、その発言はしないかな。結果はまさに予想通りだと思う。こういう高い検証可能性を持つタスクはLLMに向いているし、次の2年以内にAIツールがGCCよりも良いコンパイラを作ると思ってるよ。

これってSpaceXの会話にすごく似てると思うな: - おお、見て![小さな関数を書く / 小さなロケットのホップをする]ことができるけど、[コンパイラを書く / 軌道に乗る]ことはできない! - おお、見て![おもちゃのコンパイラを書く / 軌道に乗る]ことができるけど、[Linuxをコンパイルする / 再利用可能になる]ことはできない! - おお、見て![Linuxをコンパイルする / 再利用可能な軌道ロケットを得る]ことができるけど、[GCCに匹敵するコンパイラを作る / ロケットを素早く回転させる]ことはできない! - このポイントを証明するためだけにこのコンパイラを作り続ける理由はないよ。でも、もし数人のコンパイラエンジニアにガイドされれば、GCCにすぐ追いつくと思う。AI支援の開発からたくさんの変革が起こるだろうね。

プロ: 確かに今はそうかもしれないけど、次の世代がそれを解決するよね。「十分に賢いLLM」のためにc2のウィキページが必要なのかな? https://wiki.c2.com/?SufficientlySmartCompiler のように。

最近の「バイブコーディング」OCamlの騒動を思い出すよ[1]。PRの著者は、自分の完全にLLM生成の貢献がどうしてそんなに疑わしく見られたのか全く理解してなかった。この記事は重要なポイントを確認してるね。合格するテストがあるのと、正しさに似た出力を生成できるのは別の話だから。ただ、その出力が良くてメンテナブルであることは全く別のことなんだ。[1] https://github.com/ocaml/ocaml/pull/14369

その通り。未来のモデルで全てが解決されるというこの欠陥のある議論には毎回イライラする。

反対派としての私の主張は、「もしAIが将来良くなるなら、未来に戻ってきてみて」ってことだね。

これがプロと反対派の会話の進め方だとは思わないな。プロは、GCCの開発者がOpus 4.6を活用できれば、もっと生産的になると言うだろうし、反対派は、それが生産性を助けるわけではなく、コードベースに対する理解が薄れると言うだろうね。CCCプロジェクトは、Opusが今自律的にできることのデモンストレーションだったと思う。99.9%のソフトウェアプロジェクトは、Linuxコンパイラのような複雑なものを作ってるわけじゃないし。

まったく正当な視点だね。ただし、正しくコンパイルされたLinuxカーネルが必要な場合は、すぐに疲れちゃうかも。

それに、Cコンパイラって実際に50年分のコードがあるんだよね。LLMが本当に新しい問題に取り組む能力には、まだ疑問を感じてる。

それに、忘れてることがあると思うよ:反対意見として、全てはGCCや他のコンパイラが既に存在していたからこそ生成できたってこと(反対の感情がどれだけ強いかによるけど、盗まれたってこともあるし…)!

ビルドはリンカーステージで失敗した > コンパイラはちゃんと仕事をした > CCCが成功した点 正確性:カーネルのすべてのCファイルをコンパイルした(エラーは0) それは成り立たないと思う。コンパイラがカーネルコードの一部に対してゴミのアセンブリを生成した可能性は十分にあるし、たとえリンクできたとしても全く動かないかもしれない。(SQLiteのコードが自己テストを通過したからといって、LinuxカーネルがSQLiteよりもはるかに高度で低レベルな特徴を使っているから、私を納得させるものではない。)

同意するよ。エラーがないからって、正しくコンパイルされているとは限らないからね。何かを/dev/nullにパイプしてもエラーは出ないし、そこからは何も結論を出せない。SQLiteを正しくコンパイルできるってことは、少なくともそのコンパイラがSQLiteに関わるCのセマンティクスを十分に実装している証拠にはなるね。

「奇跡はクマが上手に踊れることではなく、クマがそもそも踊れることだ。」 - 古いロシアのことわざ。

でも、ポスターやチケット販売者、サーカスの団長はみんな「アンナ・パブロワが生まれ変わった、著名なアイススケーターのように踊れるクマだ!」って言ってたよ。

ここで気になるのは、Anthropicがブログ記事でLinuxカーネルがx86でブートできると主張してたけど、これって本当にそうじゃないの? それとも、ただその部分をでっち上げたの? ブログ記事からは、カーネルが3つのアーキテクチャ全てでブートできると言っているように見えたけど、カーネルの設定オプションでかなりの手を抜かない限り、それは真実じゃないよね。リポジトリをよく見ると、RISC-VでのLinuxブートしか示してないし、だから… [0]: https://www.anthropic.com/engineering/building-c-compiler - "x86、ARM、RISC-Vでブート可能なLinux 6.9を構築する。" [1]: https://github.com/anthropics/claudes-c-compiler/blob/main/B... - RISC-Vのテストしか示してない。

私の推測では、CCCは静的キーやDKMSなどを無効にすれば動くと思う。__jump_tableの具体的なケースでは、Clangビルドを動かすために何か作業があったんじゃないかな。

「皮肉なことに、4つの段階の中で、コンパイラ(アセンブリへの翻訳)がAIが構築するのに最もアプローチしやすいものです。主にパターンマッチングとルール適用に関するもので、Cの構造を取り、アセンブリパターンにマッピングします。アセンブラは見た目よりも難しいです。ターゲットアーキテクチャの各命令の正確なバイナリエンコーディングを知っておく必要があります。x86-64だけでも、複雑なエンコーディングルールを持つ何千もの命令バリアントがあります(REXプレフィックス、ModR/Mバイト、SIBバイト、ディスプレースメントサイズ)。1ビットでも間違えると、CPUは全く予期しない動作をします。リンカーはおそらく最も難しいです。リロケーション、複数のオブジェクトファイル間のシンボル解決、異なるセクションタイプ、位置独立コード、スレッドローカルストレージ、動的リンク、ELFバイナリのフォーマット特有の詳細を処理しなければなりません。Linuxカーネルのリンカースクリプトだけでも、リンカーが正確に処理しなければならないレイアウト指示が何百行もあります。」私はコンパイラ、アセンブラ、リンカーに関わってきたけど、これはほぼ逆だね。

まさにこれ。リンカーは与えられたブロックを位置独立コードのための修正でつなげるもので、これをルール適用と呼ぶことができます。アセンブラはパターンマッチングですね。この説明には私も混乱しました:各個別の反復:約4倍遅くなる(レジスタのスピリング)キャッシュの圧力:約2-3倍の追加ペナルティ(命令がL1/L2キャッシュに収まらない)10億回の反復を合わせると:158,000倍の総遅延各反復がXパーセント遅くなるなら、10億回の反復もXパーセント遅くなるはず。実際に何が起こっているのか気になる。

同意する傾向があるけど… CCは動作するリンカーも作ったの?それとも動作するコンパイラだけだったの?Anthropicが作ったのはコンパイラだけだと思ってた。

Claudeが基本的なx86アセンブラとリンカーを一発で作ってくれたよ。確かに多くの命令が欠けてるけど、それはデータのテーブルを機械的に埋めるだけの問題だからね。リンカースクリプトのサポートはちょっと難しいけど、以前に手動でコンパイラを書いた経験から言うと、私の経験は君とは正反対だよ。

SQLiteの158,000倍の遅延がここで重要な数字であって、Cを正しくパースできるかどうかではない。パースは解決された問題だ — すべてのCSの学部生は再帰降下パーサーを書く。コンパイラの面白い(そして難しい)部分は、レジスタの割り当て、命令の選択、最適化パスで、まさにそこが崩れているところなんだ。それを踏まえると、「CCC対GCC」という枠組みは間違っていると思う。GCCには何千人ものエンジニアの年数が注ぎ込まれている。実際に印象的なのは、LLMがCの非自明なプログラムをコンパイルできる程度のコンパイラを作ったことだ。たとえそれがひどいものであっても。5年前には考えられなかったことだよ。みんなが注目すべきゴールポストは「GCCに匹敵できるか」ではなくて、次の反復がその158,000倍のギャップを100倍に縮められるかどうかだと思う。それができれば、実際の軌道について何かを示していることになる。

記事の158,000倍の遅延についての部分は、正直よくわからないな。ネストされたクエリがSQLiteのバイトコード評価器を通して大量の反復を行うって言ってるけど、各反復が4倍遅くて、「キャッシュプレッシャー」からさらに2~3倍のペナルティがあるって主張してる。 (その数字がどこから来たのかの説明はないみたいだし。ブログ投稿が主にAI生成だと考えると、信じられるかどうかわからない。)でも、各反復が12倍遅くなるだけなら、全体のプログラムが12倍遅くなるはずで、158,000倍遅くなる理由にはならないよね。こんなに大きな遅延は、CCCが生成したコードがGCCの生成したコードよりも非対称的に遅いことを示唆していて、つまりは誤コンパイルの可能性があるってことだと思う。テストスクリプトがコンパイルされたコードの正しさを確認するようなテストをしていないのも気になるな、クラッシュしないこと以外は。SQLiteの広範なテストスイートを実行しようとしたら、もっと面白くなると思うんだけど。

このAIは、おそらくGCCやclang、他のオープンソースのCコンパイラの全てをトレーニングセットに含んでると思う。GCCのソースコードをそのまま見つけて、パフォーマンスを一致させることもできたかもしれないね。

中立的な観察として言わせてもらうと、人間が期待をどれだけ早く調整するかって、本当に驚くべきことだよね。5年前に、「一般的なAIが、シンプルな英語のプロンプトを書くだけで、Linuxカーネルを扱えるCコンパイラを自力でゼロから作れる」と言ったら、完全に信じられなかったと思う!あり得ない!誰も真剣に受け取らなかっただろうし。今、私たちがいる場所を見てみてよ。

その通りだね。すごい進歩だけど、これをもとに extrapolate する人たちを見ると、ほんとイライラするよ。今ここにいるからって、AGIに到達するわけじゃないし、スタバで仕事を求めるソフトウェア開発者が出てくるわけでもないからね。

簡単な英語のプロンプト それが私の疑念の根源なんだ。専門レベルのプログラマーが同じような人間の作品を作るには、すべての文脈が必要なんだよね。つまり、コンパイラを作るときにあった共有の洞察や議論、設計が必要なんだ。それなしでこれをやるのは、ただの非常に elaborate なコピペになっちゃう可能性が高い。

確かに、オーバートンウィンドウが動いたんだよね。だからこそ、実はAI推進派の方が反AI派より正しいと思ってる。ちょっと悲しいけど。

今一番重要だと思う分析が欠けてるのは、生成されたコードの質はどうなのかってこと。LLMがRustでCコンパイラの最初の完全なイテレーションを生成するのは超便利だけど、そのコードが人間(または他のAI)によってメンテナンスや改善ができるほどの質でないと意味がない。そうでなければ、ほとんど役に立たないしね。今のAIが生成するコードのほとんどがそういう感じだし。結局は人間がメンテナンスしなきゃいけないし、最終的には人間が責任を持つことになる。私が見たいのは、そのCコンパイラがひどく絡み合ったスパゲッティコードで、名前もひどいものなのか。それとも、明確な構造があって、良い名前付けと適切なコメントがあるものなのか。

注意すべきことがいくつかあるよ:1. 現実世界では、似たようなタスクに対して、A) 最適化に関するすべての論文やISAのPDF、MITライセンスのあらゆる種類のコンパイラにコンパイラがアクセスできない理由はほとんどない。そうすれば、もっとパフォーマンスが良くなるし、「GCCを解凍する」っていうのはただの主張だって証明になる(でももっと言うと2もね)。2. すべてのタスクの中で、アセンブラは記憶が一番役立つ部分だよ。逆に、LLMは事前トレーニング中に無限に見たISAのドキュメントなしでは動けない。どうなると思う?3. Rustはテスト対象としては悪い言語だよ。LLMでRustのCコンパイラを作りたいなら、LLMの経験があるなら、Cコンパイラを作ってからRustに移植するのが普通。Rustは、たくさんの参照がある可変データ構造があると難しいし、Cコンパイラはまさにそれだから。異なるレイヤーから複雑さを組み合わせるのは、オートマティックプログラミングに関わった人がよく知っているLLMのアンチパターンだよ。4. 現実世界では、そんなタスクを指導なしでやることはないし、指導があれば素晴らしい結果が出るよ。実験が悪い考えだったとは言わないけど、実験者はインターネットが持っている別のポイントを示そうとしていたってことだね(いつものように)。