64bit processor

私の一昨日の日記
http://d.hatena.ne.jp/yaneurao/20040406#p1
に対して次のようなコメントをもらった。

サーバアプリケーションにJavaが多いことを考えると
int32にペナルティーの付くプロセッサがこれから開発されるとは
思えないのですがいかがでしょうか?

これに対してひとことで回答するのは大変なので、ちょっと資料を参照しながら説明したいと思う。IntelIA-64(Itanium)のアーキテクチャから。

http://developer.intel.com/design/itanium/hardware/process_arch.htm

IA-64ではレジスタはたいてい64bit長である。GR(GeneralRegister:汎用レジスタ)が64bit×128個,浮動小数レジスタは80bit×128個、あとまあ、いろいろあるのだが、そのへんはいま考えないでおこう。

そんなわけで、IA-64では浮動小数点演算以外は、おおむね64bit長で行なうことになるわけである。

では、比較やストア(メモリへの格納)、ロード(メモリからの読み込み)に関して、32bitにマスクしたり変なことをしないといけないのかというとそうではない。

・比較(cmp)に関して、cmp4(4は下位4byteの意味の4である)というのがあって、これはレジスタの上位32bitは無視して、下位32bitに対してのみ行なう。
・ストア(st)に関して、st4というのがあって、これも最初の4バイトのみをストアすることが出来る。
・ロード(ld)に関してもld4というのがあって..以下略。

そもそも、st4のような命令の場合、4のところには、1,2,4,8(あと場合によっては10も)が指定できる。

ようするに、メモリ上の32bit同士の加算を行ないたいのならば、ld4して、add(これは64bit幅で行なわれる)したあと、st4すればいい。ついでに言えば、addもadd4とすれば下位4バイトのみの加算が出来るので別に64bit幅でやる必要はない。このへん、なかなか優れたアーキテクチャであると思う。

ところが、32bit整数と64bit整数との加算に関しては、32bit整数を符号拡張(or 上位32bitを0で埋める)ことをしてからaddする必要がある。これを行なわないといけないことは比較的多い。たとえば次のような単純なコードでもそうだ。

   for( int i=0 ; i < n ; ++i ) a[i] = f;

aはアドレスを表していて(C言語で言うところの)ポインタであり、64bit符号無し整数だと考えられる。Javaはintが符号付き32bitなので、a[i]というアドレッシングは、符号なし64bit整数と符号付き32bit整数を何倍かしたものとの加算に他ならない。よって後者をいったん符号拡張して64bitにする必要が出てくる。言うまでもなくintが最初から64bit整数ならばこの作業は必要ない。

よって、64bit整数と、符号付き32bit整数(の何倍か)とを一命令で加算する命令がない限りは、この符号拡張しないといけない分だけ損なのだ。そんな命令がIA-64にあるかというと..確か..無いと思う。そんなわけで、64bitプロセッサではintは64bitのほうが(こういう点においては)有利だ。これをint型が32bitでないことに対する“ペナルティ”だと言えるかどうかは微妙なところだと思うけれど。

あと、Pentiumのときは、partial stallという非常に悩ましい問題があった。partial stallというのは、レジスタの下位16ビットにロードしたあと、そのレジスタを32bitでストアした場合、実行ユニットがぴよってしまうのである。(ぴよるて..格闘ゲームみたいだな..) この現象は、Pentium4であろうがPentiumMであろうが発生する。非常に困ったチャンなのである。

IA-64に関しては、partial stallは生じない。(と思う) しかし、RAW(Read After Write)やWAW(Write After Write),WAR(Write After Read)に関しては注意が必要である。このへん、かなりややこしいので続きはまた...気が向いたら書くことにする。