2013-08-02

OpenBSDのコンパイラー

'Compilers in OpenBSD' - MARC

List: openbsd-misc
Subject: Compilers in OpenBSD
From: Miod Vallat <miod () online ! fr>
Date: 2013-07-31 21:19:11
Message-ID: 20130731211911.GE17582 () tazenat ! gentiane ! org

最近の議論(Default software in the base)は、近い将来、OpenBSDではClang/LLVMをシステムコンパイラーとして使う方向になっている。この議論は、これ以上発展していないが、現在OpenBSDのデファクトなコンパイラーメンテナーである私が思考の帯域を浪費してみようと思う。

だいたい、私はOpenBSDのシステムコンパイラーの保守に立候補したわけじゃないのだ。私は移植メンテナーのひとりとして、gccの大量のバグを修正するか回避するかしなければならなかったので、自然にこの地位に至ったのだ。私はその必要がなければよかったのにと思っているのだ。

今は昔、*BSDプロジェクトが始まってからの数年、様々なプラットフォームのBSDシステムが使っていた自由ソフトウェアコンパイラーはgccだった。pccは開発が停止し、TenDRAはいまだ面倒なビルドシステムを使っていて、十分なプラットフォームをサポートしていなかった。これが当時の自由ソフトウェアの地のすべてだったのだ。

さらに、gcc 2.5(当時)は、いくつかのバグを抱えていたが、それほど大量というわけではなかった。gcc 2.5はどの最適化レベルでも、動くコードを生成することに関して信頼することができ、何も深く考える必要はなかったのだ。つまり、当時はコンパイラーを保守する必要などまったくなかったのだ。なぜなら、gcc 2.5は(ほぼ)バグフリーだったからだ。

この状況は、2.7の時代まで続いた。この当時の知識としては、-O2には-fno-strength-reduceを組み合わせて使えというものだ。なぜならば、2.7はstrength reductionコードにバグがあり、i386コードに影響したからだ。これさえ守れば、当時のコンパイラーは信頼できた。

そして、C++98や、C99といったものが出てきて、gccにとっては多大な作業となった。これらの規格の新機能をサポートすることのみを試みていればの話だが。中には当時の思想を覚えている人もいるだろう。保守的だが、C++98に追いつこうとしていたgcc 2.8と、最適化コードを拡充して、より速いコードを生成しようとしていた"Pentium gcc"一味だ。

このプロジェクト達は、最終的に、gcc 2.95としてマージされた。その時から、いくつかのことが永久に変わってしまったのだ。

  • より多くの人間が、[訳注:特定プラットフォーム]専用の最適化に関わるようになった
  • これらの最適化は、2.5/2.7の最適化とは違い、「ほぼプラットフォーム非依存」ではなくなり、かわりに特定のターゲットプラットフォームの機能を活用するようになり、より多くのコードが、ある最適化手法を適用すべきかどうかの判断をするようになった

これによる不可避な結果として、世界のある重要な仕組みが変わってしまった。gccにはバグが存在するようになり、その事実を受け入れ、対処しなければならなくなったのだ。

筆者が"gcc"と書く時、読者は「コンパイラー」と読んで差し支えない。アーサー・C・クラークがかつて言ったように、「十分に最適化するコンパイラーは魔法と区別がつかない」

この昔話は我々に何を教えてくれるのか。

一つ目に、コンパイラーは壊れているということだ。モダンなコンパイラーには最低限の正確性と信頼性を期待したいところだが、期待できない。どのコンパイラーでも状況は同じだ。

二つ目に、コンパイラーは変化するものだということだ。十分なテスターと開発者のいないアーキテクチャーは、挙動がおかしくなり始め、(なぜならば、新しく付け加えられた最適化手法における推定をぶち壊しているにもかかわらず、95%は正しく動くコードを生成するからだ)、そしていずれ、取り除かれる。この典型的な例はm88kだ。m88kは、ターゲット専用のマクロが急に括弧で囲まれた引数を必要とするようになり、そして誰もm88kなんてテストしないし気にかけなかったので修正されず、gcc 2.95で壊れた。

OpenBSDが、プラットフォーム毎に別のコンパイラーを使うのはそのためだ。あるgccのリリースは、あるあまり有名ではないプラットフォームには適切ではないかもしれないからだ。(これはgccにおいては驚くにあたらない。というのも、他のコンパイラーとのベンチマーク競争にあけくれているし、gcc 3からは、gcc開発者は「バグフリー」な新バージョンをリリースしようとして、"regression"のみを修正するポリシーを持っているものの、あるいは、より多くの時間をregressionの定義を変更することに費やしているか、あるいは、あるregressionは実はregressionではないと説明し、stableリリースで修正する必要を生じさせないように努力しているからだ)。gcc 2.95がC99を完全に実装していなかったのは実に残念なことだ。もし実装していれば、我々は喜んでgcc 2.95を、現在はサポートされていない古いプラットフォーム向けに保存し、新バージョンを罵ることもできたであろうに(何も変わらないが)

gccからclangに切り替えるのは検討すべき価値があるし、実際、何人かの開発者が実験している。おそらくいくつかのプラットフォームでは移行されるかもしれない(llvmはOpenBSDほど多くのプラットフォームをサポートしていないため)。しかし、OpenBSDのサポートするプラットフォームの一部で切り替えるのは、単純な作業ではなく、多大な労力を必要とする(例えばlibgccをcompiler-rtで置き換えるとか、欠けているプラットフォーム向けに移植するとか)

そして、もしそのような切り替えが起こったならば、バグが発見され、問題を修正しなければならなくなる。我々はllvm開発者が、gcc開発者よりも、バグ報告とバグ修正をより良く行うと楽観視することはできない(ただし我々はそう願っているが)

upstream開発者による修正がなければ、我々の手で出くわすコンパイラーの問題を解決しなければならない。時には、upstreamに提出するパッチを選ぶだけでよく、我々が使うバージョンにbackportする必要がないこともあるが、時として、最新版のコンパイラーでは再現しない問題もあり、そういう場合は我々の開発者のスキルとコンパイラーの修正能力に頼らなければならないのだ。

うちのところの開発者の何人かは、長年の成果で、gccを恐れなくなり、問題を調査し、修正をbackportし、また修正し、あるいはバグを迂回したりできる。私は今ここでは、niklas@とespie@とetoh@とotto@しか挙げないが、名前を挙げられなかったその他の者は許してもらいたい。これは、少なくとも、簡単な道のりではない。さて、また、うちのところの何人かの開発者は、llvmにおいて似たような知識を構築中だ。彼らに多大な幸運あれかしと願うし、私も近い将来、彼らに合流する。

とはいえ、最も有名なOpenBSDプラットフォームをgccからllvmに置き換えることには、あまり自信が持てない。

数ヶ月か数年たてば、また状況は違ってくるのだろうが。

・・・しかし、それ以外に起こってほしいことがある。

オープンソースコンパイラーのLTSリリースだ。

今日のすべてのコンパイラーがバグまみれで、多くのバグが、ちょっと単純ではないコード辺をコンパイルしただけで出くわすわけで、しかも我々はアセンブリに戻るなどということはできない、我々には信頼できるコンパイラーが必要なのだ。

GCCとLLVMは、Fortune 500に入る会社に支援され、賢い開発者にフルタイムで働かせるべく賃金を払っている。

しかし、長期サポート版を提供しようという者は皆無だ。バージョンNのバグはバージョンN+1で修正されるが、新しいバグが導入される。少し落ち着いて信頼できるコンパイラーを作ろうという者はどこにもいない(なぜならば、バージョンN+1はどっかの非現実的なベンチマークで3.14%速いからだ)。まあまあ、そんなことを気にする必要はありません。明日のコンパイラーは無限ループを5秒以内に完了できるコードを吐くかもしれませんよ。さらなる発展をお見逃しなく!

自由ソフトウェアの世界は、LTSコンパイラーを必要としている。最後のデファクトLTSコンパイラーはgcc 2.7.2.1で、これはモダンなCやC++のコードをコンパイルできないほど古い。

自由ソフトウェアのLTSコンパイラーが現れたならば(gcc forkにせよ、llvm forkにせよ、別のものにせよ)、OpenBSDは、とても真剣に、利用を考慮すべきだ。我々だけがそれを行う自由ソフトウェアプロジェクトというわけではないだろう。

Miod Vallatが"Pentium gcc"と呼んでいるのは、gcc 2.7から2.8あたりの時代に発生したgccの多数のforkのことだ。とくに、Cygunusやegcsのようなものは知名度が高い。

まだストールマンがGCCの開発姿勢に強い影響力を持っていた時代、GCCはかなり保守的な伽藍式の開発をしていた。外からの大規模な新機能追加パッチは、ほとんど受け付けなかった。GCCの開発自体、停滞気味だった。そこで、GCCのforkが多数立ち上がり、特に多くのforkで、プラットフォーム専用の最適化に力が注がれた。

結局、GCC本体の開発は止まり、EGCSをGNUに取り込むというか、公認するという形で、GCC 2.95がリリースされ、今のGCCの本流となっている。GCCとEGCSのマージと言うよりは、EGCSに母屋を明け渡したような感じだ。

ストールマンが強い影響力を持っていた保守時代、GCCは最適化の具合はともかく正しく動くコードを吐いたが、今のGCCはバグまみれというのは、なかなか考えさせられるものがある。

今ではClangもでてきて、自由なソフトウェアのCやC++のコンパイラーはGCCの独壇場ではなくなったが、正しく動くコードを吐くという点に関しては、どちらも大差なく悪いのだとか。

コンパイラーの世界では、信頼できるLTSリリースは存在しない。やはり、コンパイラーとして評価されるには、優秀な最適化により、競合のコンパイラーより優れたコードを生成しなければならないし、正しいコードを吐くというのは、どうも二の次のようだ。それに、正しいコードを吐くという修正だけbackportするというのも、相当の手間なのか行われていない。

もとより、コンパイラーのbackportというのがあまり一般的ではないと思う。backportすべき修正があまりにも多くなるのも問題なのだろうか。結局、問題を修正するには、バージョンN+1でなければならず、それには新たなバグも含まれる可能性がある。

No comments: