GHCへの私の貢献2023

この記事は Haskell Advent Calendar 2023 の6日目の記事です。


私はここ数年、HaskellコンパイラーであるGHCに貢献しています。この記事では、今年(2023年)に私が行った貢献を紹介します。

GHCの開発は独自ホストされたGitLab上で行われています。

目次

私の貢献

今年は貢献と言っても、バグ報告のみ(修正パッチは含まない)のケースが多いです。私はLunarMLが忙しいので……。

FMAについてコメント(2月ごろ)

2〜3月ごろに、FMA (fused multiply add) を計算するプリミティブをGHCに実装するマージリクエストが出ていました。

私は浮動小数点数についてそれなりに詳しいという自負を持っているので、何点かコメントしました。正しくないrewrite ruleを指摘したり、一部の環境でlibcの fma 関数が間違った答えを返すことを指摘したりなどです。

これらのプリミティブは無事GHC 9.8に実装されたというのは以下の記事に書いた通りです。

FMAのコード生成バグ(11月)

GHC 9.8.1に実装されたFMAプリミティブを使ってちょっと複雑なコードを書いてみると、レジスター割り付けの辺りでpanicが出ました。GHCのバグです。

というわけで報告しました:

私はレジスター割り付けについては詳しくないので修正は他の人にお任せという形ですが、いずれその辺も触れるようになりたいです。

同じコードでLLVMバックエンドの場合は別のバグが出現しました:

Wasm絡みのビルドエラー(3月)

WasmバックエンドをAArch64 macOSでビルドしたらなんかエラーが出ました。そのことは以下のissueで報告されていましたが、原因の特定と修正がされていませんでした。

なので、原因の特定と修正案(マージリクエスト)の提出を行いました。GHC 9.8には反映されています(9.6系にはバックポートされていない気がする)。

AArch64でのSIMDプリミティブのサポート(5月〜7月)

GHCにはSIMD命令を利用できるプリミティブがあり、LLVMバックエンドで利用できますが、従来はx86系(SSE/AVX/AVX-512)しか対応していませんでした。

LLVMバックエンドであれば他のアーキテクチャにも対応させるのは難しくないと思ったので、AArch64へ対応させてみました。

今後バグ発覚でrevertされるとかしなければ、GHC 9.10に入ると思います。

関連記事:

lookupIdSubst panicの報告(8月)

拙作ライブラリーrounded-hwのベンチマークのコードがGHC 9.4でコンパイラーの内部エラーを引き起こしていました。このことはしばらく前から認識しつつ報告を先延ばしにしていましたが、重い腰を上げて報告しました。

最小再現コードは不明ですが、複数のパッチのバックポートにより修正されたみたいです。感謝です。

LLVM 13でAVXを使用した時の問題の報告(8月)

これもSIMD絡みです。LLVM 13で仕様が変わったのか、GHCでAVXを有効にするとLLVMに渡すオプションが認識されずエラーになっていました。報告しました:

GHC 9.10でLLVM 11/12のサポートを切り捨てる、という形で対応されるようです。

32ビットArmでのエラー(10月)

最新のGHCを32ビットArm向けのクロスコンパイラーとしてビルドしたらエラーが出ました。原因を突き止めた上で報告しました。

この記事の執筆時点ではまだ修正されていません。

AVXで済むコードがAVX2を要求していた(11月)

256ビットの浮動小数点数のSIMD(FloatX8#DoubleX4#)は無印AVXの機能なので -mavx でコンパイルできて良いはずですが、不必要にAVX2 (-mavx2) を要求していました。なので直しました。

未完:x86 NCGバックエンドでのSIMDプリミティブ対応

現状、GHCのSIMDプリミティブを使うにはLLVMバックエンドが必要です。2018年のGoogle Summer of CodeでSIMDプリミティブをx86 NCGバックエンドで使えるようにしようという試みがあり、一旦mergeされましたが、その後revertされました。

せっかくなのでそのパッチを復活できないかなと夏頃から色々やっていて、256ビット(AVX/AVX2)にある程度対応してみたつもりです。しかし、そもそも「revertされた理由」をちゃんと認識しないままやっていたので、このままではマージされる見込みはないことに12月に入ってから気づきました。revertされた理由は以下に書かれていますが、

レジスター割り付けで変数をスタックに割り付ける必要がある際に、スカラー用の命令でロード・ストアしてしまうのでベクトルの64ビットよりも大きい部分が破壊されてしまうようです。これを直すにはレジスター割り付けの「全てのレジスターは64ビット(具体的には spillSlotSize という定数)以下である」という仮定を覆す必要がありそうで、今の私には厳しそうです。

ちなみに「LLVM 13でAVXを使用した時の問題」や「AVXで済むコードがAVX2を要求していた」はこの作業のついでに見つけています。

GHCに貢献するには

あなたがGHCのバグに遭遇した、あるいはGHCの改善点を見つけたとしましょう。つまり、貢献チャンスです。

GHCもOSSプロジェクトなので、大まかな貢献の流れは他と共通です。つまり、

  • 最新の開発版を取ってきて再現するか試す。
  • 最新の開発版で直っておらず、まだ報告されていないようなら、報告する。
  • 余力があればパッチも書く。

という感じです。

詳しくはリポジトリ内の文書

とかWikiの文書

を見てください。ビルド方法は

などを参照してください。

GHCのGitLabに新しくアカウントを作る際、管理者からの承認(手動)が必要かもしれません。その場合、IRCかghc-devsメーリングリストでその旨を連絡してください。参考:

お前もGHCの中の人にならないか?

夏頃、「GHCの中の人」を分かりやすいようにしよう、という動きがありました。

それで、チームメンバーをリストしたページができました。

このリストの草案はSPJが選んだようで、実は私のところにもメールが届きました。せっかくの機会でしたが、私はLunarMLの方が本命というか、あんまり手を広げすぎてどれもこれも中途半端になるのは良くないと思ったので、辞退させていただきました。

最後に

なんか自分語りみたいになってしまいました。ですが、OSSへの無償の貢献で得られるのは名誉くらいなので、名誉を稼ぐ(?)ための記事を書いても悪くはないでしょう。他のコントリビューター(人や組織)もやったことリストみたいな記事をHaskellのDiscourseに流してますしね。

GHCへの貢献はこれからも細々と続けていきたいです。あなたもチャンスがあったら貢献してみませんか?