x86_64の簡単な歴史
現在家庭用PCやサーバでよく利用されているCPUアーキテクチャはx86_64(AMD64, Intel64)です。x86_64は2000年にAMDが仕様を発表し、2003年から実装CPUが登場しています。
今から20年以上も前の規格なので、SSE, SSE2が標準とされていますが、それ以降の機能は規格に含まれていません。ですが、せっかく機能があるのですからなるべく新しい機能を利用して高速化を図りたいものです。
歴史の長さ故の問題
今でも-march=skylake
(GCC, Clangの例)のように、コンパイル時にCPU世代を指定することでCPU最適化ビルドが可能です。しかしCPUの世代ごとに引数が変わるため引数の種類が極めて多く、選ぶのも困難です。面倒なので数えていませんが、GCCのドキュメントを読むとやたらと多いことがわかります。
https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
そのうえ、-marchオプションでコンパイルしてしまうと、別のCPUでプログラムが動かなくなることがあります。そのため広く配布されるバイナリはCPU最適化を行わずにコンパイルするのが一般的です。自分でビルドする場合でも、GitHubActionsやECS Fargateなど物理サーバが隠蔽されている環境では問題になります。
こうした環境では時々違うCPUのマシンにデプロイされ、日和見で実行エラーになる場合があります。こうした事情から、これまでCPU最適化はあまり利用されてきていませんでした。
x86_64の世代分け
前置きが長くなりましたが、これに対応するため2020年にAMD, Intel, Red Hat, SUSEが共同でx86_64のバリアントを定義しました。これはCPU世代をある程度まとめて、その中で共通して利用できる機能を定義しているものです。具体的には現在以下のとおりです。
x86_64-v2(Level A)
対応する機能:CMPXCHG16B, LAHF/SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3
だいたい2008年から2011年くらいのCPUがこれにあたります。コードネームではNehalemに近いです。そして2020年にリリースされたAtom Pシリーズもこのレベルです。
Level B
対応する機能:x86_64-v2のすべて + AVX
Sandy Bridge世代に該当します。この世代は差が小さいので、あまり使われないだろうとのこと。この世代はx86_64-v*表記ではスキップされていてLevel表記だけです。
x86_64-v3(Level C)
x86_64-v2のすべて + AVX + AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE
だいたいHaswell世代のCPUが該当します。
x86_64-v4(Level D)
x86_64-v3のすべて + AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
Xeon Scalable Processorが該当します。コードネームではSkylake以降です。
コンパイラの対応状況
GCC 11, LLVM Clang 12以上でx86-64-v2, x86-64-v3, x86-64-v4が指定できるようになりました。今はまだこれらを利用したバイナリはほとんど出回っていませんが、そのうち各バリアント向けのバイナリも提供されるようになるでしょう。
GCC 11: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
Clang 12: https://releases.llvm.org/12.0.0/tools/clang/docs/UsersManual.html
RedHat 9ではx86_64-v2をビルドターゲットにする予定とのこと。
https://developers.redhat.com/blog/2021/01/05/building-red-hat-enterprise-linux-9-for-the-x86-64-v2-microarchitecture-level/