さて、その追加されたRadix-16であるが、これは要するに割り算器である。CPUにとって、割り算というのは昔から非常に苦手(というか、手間が掛かる)な処理である。論より証拠でちょっと数字を見てみよう。Intel 64 and IA-32 Architectures Optimization Reference ManualのAPPENDIX Cに、"INSTRUCTION LATENCY AND THROUGHPUT"として主要な命令のスループットとレイテンシが示されている。判りやすいところで、Conroe世代のx87の浮動小数点命令におけるFADD/FSUB/FMUL/FDIV(加算/減算/乗算/除算)の一覧をまとめると表1の様になっている。これはなぜか? という話をまずしておこう。

表1
命令 Latency Throughput
FADD 3 1
FSUB 3 1
FMUL 5 2
FDIV 32 32

ものすごく古い話からすると、綺麗に割り切れる計算はともかく、割り切れないような割り算(例えば1÷3とか)は素直に処理が出来ない。そこで様々な近似解を求める方法(有名なのがNewton-Raphson法である。筆者は確か高校か大学でやった記憶があるが、最近はどうなんだろう?)を実装することになるが、ただこの方式で全ての割り算を行うと手間が掛かりすぎるので、実際はある程度のテーブルを用意しておき、このテーブルで大まかな近似値を出した上で、残った差を近似式を解いて求めるといった方式を取る。1994年に大問題になったPentiumプロセッサのFDIVバグは、このテーブルの一部に間違いがあった事で起きた問題である。

話を戻すと、FADD/FSUBではスループットが1(つまり1cycleあたり1回の加減算が可能)、FMULでもスループットは2(つまり2cycleあたり1回の乗算が可能)なのに対し、FDIVはスループットが32にも及ぶ。FDIVは本来Single Precision/Double Precision/Extend Precisionで異なるスループット/レイテンシになるのだが、Conroe世代は全て同じ32なので、ここでは統一している。とりあえずDouble Precisionだと64bitのデータ長で、これを処理するのに32cycleかかるから、処理性能としては2bit/cycleという表記になるわけだ。これをPenryn世代では4bit/cycleに向上したとしている(Photo05)。つまり、スループットが16cycleになったという話だ(Latencyがどうか、という話はまた別問題である)。

Photo05:Radix-16 Dividerの性能。DividerそのものはInteger/FPに無関係で一つであり、割り算以外にも平方根の計算などでも威力を発揮する。

これを実現するためには、大雑把に言って除算器の回路規模は4倍以上(恐らく5倍を越えるだろう)に膨れ上がることになる。まずテーブルで従来と同じ精度の近似値を確保するためには、テーブルの除数/被除数をそれぞれ倍にしなければならないから、テーブルサイズは4倍になる。また近似式の計算部も倍の桁数を同時に扱う必要があるから、こちらも4倍以上になる。加えて、テーブルの数が増えても同じスループットでアクセスできるようにしないといけないので、除算器内部の制御部も肥大するはずで、普通に考えるとトランジスタが猛烈に必要になる。

実のところ、こうした話は別にx86に限らず、全ての計算機に共通の話である。なので、コンパイラにとっては「いかに割り算を行わないで済ますか」が腕の見せ所であり、プログラマにとってもこれは大きな課題だった。例えば、

E=(A÷B)×(C÷D)

なんて計算を行う場合、コンパイラはこれを、

E=(A×C)÷(B×D)

と並び替えて割り算の数を減らすのは常識だし、2の倍数の割り算の場合は、これをShift演算に置き換えてしまうことで割り算そのものを省く事もやはり常識である。プログラマにとっても、「割り算はコストが高い」というのは周知の事実であり、従ってなるべく割り算の数を減らすのが、スピードが求められるプログラムにおいてはごく当たり前の様に行われてきた。

こうした背景もあって、除算を高速化しても、実はすぐさまに恩恵を受けるプログラムというのはそう多くないというのが現状である。勿論そうは言っても要件によってはどうしても割り算を多用せねばならないケースはあるから、そうしたプログラムは間違いなく高速化されると思うが、ただ全体としてのIPCの底上げにどこまで効果があるかはやや疑問である。にもかかわらずこれを実装した理由についてMooly Eden氏は「90nmから65nmにプロセスを移行することで、膨大な量のトランジスタを利用することが可能になった。この使い道を検討した結果、Radix-16を実装することにした」と説明する。

実はこの説明がまたちょっと面白い。同じMooly Eden氏に「何で8MB L2ではなく6MB L2にしたのか」と聞くと「増えたトランジスタの使い道を検討した結果、6MBで十分という結論が出た」と答えている。要するに、Radix-16を実装して6MBキャッシュにするか、RADIX-16を実装せずに8MBキャッシュにするかという選択肢があった模様だ。

では何故Radix-16を選択したか? という話になるわけだが、一つの理由として6MBでも8MBでも大きな性能差が無かったであろうという事は容易に想像が付く。ただここからは筆者の想像になるのだが、科学技術計算向けにFPUの強化をすることがやはり大きな理由付けになっていたのではないかと考える。

ちょっと古い話になるが、Pentium II/IIIとK6-2/IIIの世代までで言えば、FPUの性能は明らかにPentium II/IIIが上だった。一部の命令(=それほどトランジスタを費やさなくても高速に出来る命令)はK6も健闘するのだが、FDIVの様なものに関してはK6は明らかに手を抜いており、Pentium II/IIIの敵ではなかった。この状況が大きく変わるのはAMDがK7をリリースしてからである。K7はFPUを大幅に強化しており、同一周波数におけるFPU性能は明らかにIntelを圧倒した。この構図は現在まで続いており、SSE系の拡張命令を使った場合はともかく、FPUを使う限りにおいてはまだまだAMDのK7/K8にアドバンテージがある。

これが問題になるのは、最新のSSE4を持ってしても、まだ64bitの演算までしか出来ない(拡張精度の80bitをサポートしていない)上に、64bitでも様々な特殊関数はSSE系で提供されていないからである。特に科学技術計算の場合、64bitでも不十分ということで倍々精度(128bit)をライブラリを使って実現する場合があるが、こうしたケースで使われるのはFPUであり、SSE系はまだちょっと使いにくい。こうした部分でのAMDへのビハインドが、結果としてHPC分野でAMDが躍進する理由の一つになっている事を強く懸念して、FPUの強化を目論んだのが今回のRadix-16の搭載であり、こちらにトランジスタを大量に割り当てた結果、L2キャッシュは6MBに落ち着いたのではないか、と筆者は考えている。