AMD64はレジスタが多くてうらやましい

最近アスキーのサイトで、CPUの黒歴史という一連の特集記事をみつけた。
http://ascii.jp/elem/000/000/420/420986/


半導体のしかもプロセッサ専業メーカーが出してきたこの20年くらいの製品について、主に販売やサポートが残念で売れなかったものにスポットを当てその当時の事情について面白おかしく記事にしているが、おのおののCPUの技術的な説明も簡潔かつ平易なわかりやすく噛み砕いた説明で書かれている。


ここを読んでいくうちにIntelが拡張したSSE3やSSE4.1などの概説があった。
SIMDっぽくない命令の多いSSE3 SIMDな命令を増やしたSSSE3
インテルとAMDの拡張命令の乖離が一層進む


その記事を読むまでは、MMXは64bit幅の整数演算のSIMD拡張、SSE1は128bit幅の単精度浮動小数点演算、SSE2は128bit幅の倍精度と理解していたが、上記のSSE3やSSSE4.1はよくわからなかった。
倍精度の拡張の次はどう拡張したんだ?とか、SSSE4.1はSが一個多いし4.1の.1ってなんだ?どういう意味だ??とか思ってたけど、くだんの記事にはその疑問を払拭する文章がきちんとあった。
なるほどレジスタの下位上位の水平演算*1とか、一命令でCRC32を一発で求めるアクセラレータ命令や、あまり必要でない命令をちょこちょこ付け足しなんとなく拡張して、AMDより技術的に優れているように見せかけてたのね。
CPUの命令に詳しくない人間ならSSSE4.1とかSSSE4.2とかスペックシートに記述があると、それだけでIntelすげーっておもっちゃうもんね。


ところで話はAMD64にもどる。


AMD64のメリットは、64bitアドレスによる莫大なメモリ空間をシームレスに扱えるようになったことと、レジスタを64bit化し本数を倍増させたこと。
いままでEAX〜ESPまで32bitレジスタが8本だったものが、RAX〜RSPの64bitレジスタ8本に加え、R8〜R15が新設されて合計16本に倍増。しかもSIMDで使う128bitのXMMSレジスタも8本から16本に倍増した。


x86の歴史の中で、整数ユニットでALUが直に面倒みてくれるレジスタが拡張されたのは、80286から80386になったときに動作モードの追加とともにレジスタ長が16bitから32bitに拡張が行われて以来、このAMD64が二度目だったりする。
Pemtium時代にFPUの80bitレジスタ、PentiumMMX時代にMMXの64bitレジスタ*2Pentium3時代にSSEの128bitレジスタが8本ずつ追加されてもいるけど、これらは正直サブセットみたいなもんで、普通に何も考えずにプログラム組んでる分にはFPUのみしか使われないし、浮動小数点演算をしないような手続き処理のプログラムではFPUも使われないことが多い。
つまり、普段使いのレジスタが、20年近く経ってようやく増えたことになる。
20年でっせ。
よく今まで変更なしでやってこれたななどと感慨深くも思います。


アセンブラでコードを書いたことがある人は経験あると思うが、ちょっと混みいったコードを書くとレジスタがとたんに足りなくなる。
そのときメモリ上に静的に定数を置いたり、スタックポインタを操作してそこに動的に置いたりとかいろいろやり方はあるんだけど、その度にいちいちメモリにアクセスする羽目になる。
このメモリアクセスというのが、高クロックシステムでは馬鹿にならない速度低下の要因になる。


i386sx/16Mhzの時代なら、メモリはノーウェイトだったし、リードライトもCPUが必要とするタイミングでその都度行われていたから、特になにも考えなくても問題はなかったけど、最近はCPUクロックとバスクロックが違うのは当たり前だし、キャッシュメモリの存在もあってやたらややこしい。
物理メモリ上のデータは、CPUレジスタにセットされる前に、一旦キャッシュに読み込まれる。
その際キャッシュラインサイズ*3を、一度にまとめて読み込みできるバーストリード*4が行われる。
デュアルチャネルシステムならさらに倍。
たった4バイトの書き換えで、32バイトとか64バイトとか読み込まれて、キャッシュの内容を書き換えて、再度メモリに書き戻し*5が行われる。
CPUは十分高速なのにバスの外に行くととたんに遅くなる。


余計な処理があるおかげで、コードの可読性が悪くなってミスもおきやすいし、更なる処理速度を狙う場合は修正するのもうんざりになるので一から書き直したい気持ちになることも多々あった。
ループの一番深いところ*6のみアセンブラコードで記述するならばそれほど問題はないけど、さらにその上もとなるとやっぱりレジスタが少ないと面倒くさい羽目*7になる。
でそれを解決してくれるのがレジスタ本数の倍増ってわけ。


AMDがんばったなぁ。
いやMSの手柄か。


そもそもIntelだって、PentiumProやその後のカッパーマインPentium3からのメインアーキティクチャになるP6アーキティクチャをリリースするときに、32bitレジスタの本数を追加する機会はあったはずだと思うんだけど、過去の互換性を重視*8してかItanium搭載サーバとの差別化をはっきりさせるためか、より効率のよいコードが走るモードを付け足すことをしなかった。
P6アーキティクチャは、x86コードを内部のマイクロopというRISC命令のような単純なものに変換して、やたらめったら予測実行さして、条件分岐の結果のあと正解となる結果のみ受け取るというような*9アウトオブオーダー方式をとっている。
つまりプロセッサ内部にはレジスタのクローンが大量にあるはずで、トランジスタ数が足りないとかいう理由などはないわけで、その気になれば実現可能だったと思う。
実にもったいない。


もしIntelがその拡張を行なっていれば、WindowsXPは動画再生やゲームなどの特定アプリケーションではなく、電源いれて起動して使えるようになるまでなど、ごく普通に使ってるシーンで5%〜10%程度速度が向上したはずだ*10
PPGAセレロンが爆発的に売れてノリノリだったIntelには更に追い風が吹いただろうし、AMDIntelの拡張に対応するために一年〜二年を費やし速度向上の為の改良は後手にまわる羽目になったはずで、そうなるとAthlonXPがあれだけ売上を伸ばせなかったかもしれない。
その結果AMD64なんて登場させる余力なんか持ち得ず、他のx86互換CPUを製造していたメーカー同様、組み込み用に方針転換してほそぼそと作り続ける羽目になった可能性すらでてくる。
まあ『たられば』のヨタ話なんですけどね。


ちなみに最近流行ってるARMやちょっと前のPS1/PS2に搭載されてたMIPSレジスタが32本、68kの優れた思想をそのまま16bitに持ってきたようなH8シリーズや、国産RISCのSHシリーズも16ないし32本最初からあります。
80年代後半にリリースされたCPUコアは、Cコンパイラでのプログラム開発が前提なのは当たり前だったので、設計段階から抜かりなくさまざま考えられてたわけですね。


ちなみに僕はx68-64のCPUのマシンを所持していない(汗。
家庭で高負荷を必要とする、ゲームやHDビデオの再生は、PS3が全部面倒をみてくれていたから、買う必要性を感じなかったからだ。
ゲームやBD再生はもちろん、地デジの録画や、YouTubeにアップする程度のSD画質のムービーのカット編集とエンコードすらできる。
そういう用途なら、でかいテレビで、コントローラやリモコンでピッピの簡単操作のほうがいいでしょ。
ということでAMD C-50かC-60のサブノートを買ってLinuxの64bitモノでも突っ込んでgccでasm()してみようかと思ってる。


で、最後にえーと、なんつーか、その。

AMD!AMD!

*1:垂直じゃないのかなぁ

*2:FPUレジスタと兼用

*3:通常外部バス幅の4倍

*4:古いマザーのBIOSの、メモリの項目に4-3-3-3とかあったあれ

*5:ライトバック方式のキャッシュの場合

*6:実行される回数が桁外れに多い箇所で、この部分でのメモリアクセス回数を削減することが速度に直結する

*7:Cで書くより三倍くらいの時間がかかる。コンパイラより速いコードを書くには更に三倍かかる

*8:実際はP6用のコードでは、JMP命令を削減しパイプラインを乱さない利点のあるCMOV命令が多用されるので、P5では動きません

*9:ちょっと違うか

*10:当然オフィスの電気代にも影響します。全世界的に影響があるわけで、下手すると何十万ガロンの石油が節約できた可能性もある…かもしれない