「Apple M1の速さの秘密って他にない新命令の影響じゃないの?」みたいな発言がSNSで目立つので、では実際役に立ちそうな新命令について、考察して見ることにする。
ARM NEON(ASIMD)からサポートされている64/128ビット論理演算命令
- NOT (論理否定)
- D = ~A
- AND (論理積)
- D = A & B
- BIC (否定 + 論理積)
- D = A & ~B
- ORR (論理和)
- D = A | B
- ORN(否定 + 論理和)
- D = A | ~B
- EOR (排他的論理和)
- D = A ^ B
- BIF/BIT/BSL (ビット単位選択)
- D = (Mask & A) | (~Mask & B) ※ソース破壊型命令
BIF/BIT/BSLはvselq_u32などの組み込み関数に割り当てられており、どのソースを破壊するかによって命令名が分かれているがコンパイラが勝手に選んでくれるので、C/C++以上のレイヤーで使う分にはプログラマーが特に意識する必要はない。
SHA3サポートによって追加された128ビット論理演算命令(Apple A13/A14/M1対応)
- BCAX (否定 + 論理積 + 排他的論理和)
- D = A ^ (B & ~C)
- EOR3 (3入力排他的論理和)
- D = A ^ B ^ C
排他的論理和はパリティを取るための処理に多用するので、連続するEORはEOR3に可能な限り置き換えた方がパフォーマンスが向上する傾向がある。他、BCAXもBIC+EORを置き換え可能な箇所があれば使いたい。
また、0xFFをブロードキャストしたベクトルをソースの一つに指定することでXNOR操作などの代替にもなる。
3入力の論理演算はビットスライス型暗号アルゴリズムで重宝するので有効に使っていきたい。
ただしclangでは組み込み関数は未サポートなので、インラインアセンブラを使うか、対応したコンパイラをビルドする他ない。
EOR3は光るが、トータルで劇的に速いというほどでもない。
なお、Appleがサポートするのは128ビットまでのSIMDである。Intelのように256ビットとか512ビットのSIMDはサポートしないので、当然SIMDによって相対的優位性を得ているはずはないという考察もできる。
どういう演算で速くなるのかの具体例
わかりやすい例として64ビット整数版Mersenne Twitsterを例に出すと、新命令を使うことによってビット論理演算を纏めることができる箇所は、この程度には存在する。
SHA3はM1以外のARMでもサポートするか
ARM社公式のアプリケーション向けCPUコアの実装としては最新のCortex-A78(Snapdragon 888もこれに基づくと思われる)でもSHA3をサポート予定がないので、M1以降のMacかA13/A14以降のiOSデバイス専用にコードを組むことになる。