多倍長整数算法のPentiumによる最適化
梅谷 武
作成:2001-01-23 更新:2005-04-20
Pentiumの最適化技術を使って多倍長整数クラスの高速化を試みる。
IMS:20010123001; NDC:007.64; keywords:Pentium, 最適化;
Pentiumという言葉は、文献[
X5]におけるPentium Plainを意味するものとします。MMX, Pro, U, V, Wというような修飾子が付かないのですが、最初に出荷されたPentium、あるいは各修飾子固有のアーキテクチャに依存しないという二通りの意味をもたせることにします。この文書ではこのPentiumの最適化技術について述べますが、これは修飾子が付いたPentiumにも有効です。ただ、各Pentium固有の高速化機能を使っていないわけですから、そのような高速化よりは性能は落ちることになります。
486では5ステージのパイプラインアーキテクチャが採用されましたが、Pentiumではそのパイプラインが2つ並列に動作します。スーパースケーラという言葉はこのことを指しているようです。各パイプラインでは整数命令が1クロックで実行できますから、1クロックで2つの命令が実行されることになります。2つのパイプにはUパイプ・Vパイプという名前が付けられていて、連続した2つの命令が並列に実行されることを対向(Pairing)と呼びます。連続する2つの整数命令は必ずしも対向になるわけではありません。対向となるには、
- 対向可能整数命令であること
- 対向可能条件を満たすこと
が必要です。このことからPentiumにおける最適化を次のように表現することができます。
このことによって、同じx86であっても486以前とPentiumの最適化とはまったく違った様相を示すことになります。対向可能な整数命令の表を以下に示しますが、これでわかるようには使える命令の数はかなり限られてしまいます。ただ、このことによって人手による最適化作業が楽になっている面もあります。
表1: 対向可能整数命令表
オペコード | オペランド | クロック | U | V |
---|
nop | - | 1 | ○ | ○ |
mov | r/m, r/m/i | 1 | ○ | ○ |
mov(*1) | m, acc | 1 | ○ | ○ |
push | r/i | 1 | ○ | ○ |
pop | r | 1 | ○ | ○ |
lea | r/m | 1 | ○ | ○ |
add/sub/and/or/xor | r, r/i | 1 | ○ | ○ |
add/sub/and/or/xor | r, m | 2 | ○ | ○ |
add/sub/and/or/xor | m, r/i | 3 | ○ | ○ |
adc/sbb | r, r/i | 1 | ○ | - |
adc/sbb | r, m | 2 | ○ | - |
adc/sbb | m, r/i | 3 | ○ | - |
cmp | r, r/i | 1 | ○ | ○ |
cmp | m, r/i | 2 | ○ | ○ |
test | r, r | 1 | ○ | ○ |
test | m, r | 2 | ○ | ○ |
test | acc, i | 1 | ○ | ○ |
inc/dec | r | 1 | ○ | ○ |
inc/dec | m | 3 | ○ | ○ |
shr/shl/sar/sal | r, i | 1 | ○ | - |
shr/shl/sar/sal | m, i | 3 | ○ | - |
ror/rol/rcr/rcl | r/m, 1 | 1/3 | ○ | - |
jmp/call(*2) | short/near | 1 | - | ○ |
jcc(*2) | short/near | 1/4/5/6 | - | ○ |
r=レジスタ, m=メモリ, i=即値, acc=アキュムレータ, クロックは最小値を意味する。
1) accに書き込んだ場合と同一条件
2) 分岐予測を参照のこと
連続する2つの命令は以下の条件が満たされたとき対向可能となります。
- 最初の命令はUパイプで、二番目の命令はVパイプで対向可能であること。
- 二番目の命令は最初の命令が書くレジスタを読み書きしないこと。
- 規則2で部分レジスタはレジスタ全体として扱われる。
- 規則2と3にかかわらず、フラグレジスタの一部に書き込む二つの命令は対向にできる。
- 規則2にかかわらず、フラグに書き込む命令と条件ジャンプは対向にできる。
- 次の命令の組合せは、両方がスタックポインタを変更するという事実にもかかわらず、対向にできる。 PUSH + PUSH, PUSH + CALL, POP + POP
- プリフィックスつき命令は、near条件ジャンプを除いてUパイプでのみ実行可能である。
- 変位と即値の両方を持たないこと。
番地が一つ前のクロックサイクルで実行された命令の結果に依存する場合は、番地の計算のために1クロックサイクル余分に待たなければなりません。これは番地生成インターロックと呼ばれます。
対向する2つの命令が同時に実行されなかったり、時間的に一部だけオーバーラップしたりする状況があります。これを不完全な対向と呼びます。不完全な対向の両方の命令の実行が完了しないと、引き続く命令の実行は始まりません。以下に不完全な対向となる条件を示します。
- 二番目の命令が番地生成インターロックを生ずるとき。
- 2つの命令はメモリの同じDWORDを同時に読み書きするとき。
- 規則2は2つの番地のビット2〜4が同じである場合に拡張される(キャッシュバンク競合)。DWORDの番地に対しては、これは2つの番地の差が32で割り切れてはならないことを意味する。
- read/modify/write命令がread/modify命令またはread/modify/write命令と対向になるとき
- 対向する2つの命令が両方とも、キャッシュミス、ミスアラインメント、または分岐予測ミスによって余分な時間がかかるとき、その対向は各命令単独よりは時間がかかるが2つの和よりは少ない。
Pentiumは分岐予測機構を持ち、正しく予測できたときには、ジャンプ命令を1クロックで実行できます。失敗した場合は、通常は3クロック、対向で実行される条件ジャンプの場合は、4クロックの追加クロックが必要になります。したがって、なるべく分岐予測が成功するような命令列にする必要があります。このための原則を次に示します。
- 条件ジャンプはなるべくジャンプするように配置する。
- 予測ミスの起きやすい分岐命令の後に実行される命令ペアに、分岐命令を入れないようにする。
- コードの重要な部分では、サブルーチンを異なる場所から交互に呼んだりしないようにする。
LEA命令は、シフトと二回の加算とデータの移動を1クロックの対向可能命令だけでできます。
x86
[
X2] インテル, Pentiumプロセッサ・ファミリー アーキテクチャとプログラミング, インテル, 1993