はじめに
64ビットCPUが出始めて、数年が経ちます。現状では、ほとんどのデスクトップPCが64ビットCPUを搭載する形になり、ノートPCの64ビット化も時間の問題と思われます。今回は、64ビット技術がどのような特徴を持ち合わせているのか、ソフトウェア側のアプローチをどのように進めていったらよいのかという話題で進みます。
そもそも、64ビットCPUって
実は、ひとことで64ビットCPUと言うと、2つの異なるCPUを意味してしまいます。
- AMD64/EM64-T
- IA-64
AMD64/EM64-T(以下、AMD64)とは、x86アーキテクチャのレジスタ幅を64ビットに拡張し、64ビット対応のネイティブコードを追加した規格になります。一般的に、パソコン市場で64ビットCPUと言うと、ほとんどがこちらのAMD64のことを意味しています。因みに、このアーキテクチャの設計を一番初めに行ったのはAMDです。Intelは後追いの形でEM64-Tを発表し、双方のCPUには互換性があります。
IA-64は、Intelが開発したCPUアーキテクチャです。128個の汎用レジスタ、高度なパイプライン処理などを特徴とし、CPUの機能としてはかなり高いレベルを保持しますが、AMD64と比較したときの価格や互換性、コンシューマへの浸透率などが問題視され、サーバーサイドへの供給に留まっています。
今後、一般のユーザーに浸透していくと予想されるのはAMD64です。今回はx86からAMD64への拡張がいかなるものなのか、そこにはどのようなメリットが生じているのかを、機械語レベルで解説していきます。
64ビットの命名問題。ちょっとややこしい!?
実は、AMD64と同じ意味で下記のような名前が利用されることがあります。これらは呼び名が異なるだけで、同等の意味を持っていると思ってもらって差し支えありません。本稿では「AMD64」という呼び名に統一させていただきますので、ご了承ください。
呼び名 | 説明 |
AMD64 | x86を64ビットに拡張したアーキテクチャを初めて公開した際に、AMDが命名。 |
IA-32e | IA-32の64ビット拡張(Extension)版。基本設計はAMD64と同様。 |
EM64-T | Extended Memory 64 Technologyの略。意味はIA-32eと同様。 |
x86-64 | x86を64ビット拡張しましたよ、という意味を持つ。 |
x64 | 上記の名前が煩わしいので、これらの総称に用いる場合が多い(マイクロソフトはx64を多様しています)。 |
64ビットのメリット
新しいアーキテクチャのCPUと言うと、処理速度向上というキーワードが頭に浮かびますが、今回の64ビット化は、それよりも大きなメリットがあります。それは仮想記憶容量が格段に増える点。64ビット化によるメリットはなんといってもこれにつきます。
テラバイト単位のデータが手軽に扱える
従来の32ビットWindows環境との使用可能メモリの比較状況を表1に示します。
Windows XP (32ビット通常版) | Windows XP Professional x64 Edition | |
最大物理メモリ | 4GB | 128GB |
最大仮想メモリ | 4GB | 16TB |
16ビットアプリ | ○ | × |
32ビットアプリ | ○ | ○(※) |
64ビットアプリ | × | ○ |
どうやら、仮想メモリがテラバイト単位まで確保できる模様です。数ギガバイトのデータでビビっている筆者はこれだけで相当なインパクトを受けたわけですが、実は64ビット化による仮想メモリの用途があまり見出せていないという少々お粗末な現状があることも忘れてはいけません。大掛かりなグラフィックス処理やマルチメディア演算、大規模データを扱うCADやデータベースソフトなどでの活躍が見込まれていますが、筆者の率直な意見を述べますと、一般消費者に向けた技術革新が多少薄いような印象を受けてます。多分、ここらへんの一般層への浸透率に関する問題は、Windows Vistaが解消してくれるものだと信じたいところです。
その反面、物理メモリの壁が4GBを突破する点は見逃せません。1GBの物理メモリが平気で流通してしまう世の中ですので、ソフトウェア側が4GB超を要求する日はそう遠くはなさそうです。
どちらにせよ、64ビット化に伴う非常に大きなメリットの一つとして、その膨大なメモリ空間が挙げられるのは間違いありません。
32ビットソフトウェアとの互換性が非常に高い
先ほどの表1にも記載してあるとおり、64ビット版Windowsでは、ほとんどの32ビットアプリケーションが快適に動作します。さらに、AMD64アーキテクチャにはロングモード/レガシーモードという2つのモードが搭載され、OSを越えた互換性を提供しています。
- ロングモード
- レガシーモード
この解説を読む限りだと、「32ビットのソフトウェアはロングモードで動くのか?」といった疑問が生まれますが、ご安心いただいて結構です。Windows XP Professional 64bit Editionには、WOW64(Windows on Windows 64)というソフトウェア的な機構が用意されており、OSが32ビットネイティブコードの実行の面倒を見てくれます(下図参照)。
このように、ハードウェアから根こそぎ32ビットモード(レガシーモード)で動作させることも可能ですし、ロングモードで動作させたときでもWOW64が32ビットの実行環境を提供してくれています。
ここまで互換性がしっかりしていると、Windows Vistaがリリースされることで、より一層、一般消費者の64ビット化が進みそうです。
x86とAMD64のアーキテクチャ的な相違点
AMD64はx86をベースに64ビット拡張がなされたアーキテクチャですが、具体的にはどのような点に変更が生じているのでしょうか。
ビット数が増量
x86では32ビットだったレジスタが、AMD64では64ビットに拡張されています。一つのレジスタで表現できるアドレス空間が、理論上、4GBから16EB(エクサバイト*1)までに広がりました(現段階ではソフトウェア的な都合上、16TBとまでとなっています)。
x86の環境で64ビット整数演算を行う際は、一つの値を保持するだけでも2つのレジスタを必要としていました。AMD64では、64ビット整数・実数を単体レジスタで手軽に扱えるため、従来のx86環境と比較して高速に、64ビット演算を行うことができます。表2は8~64ビットの値が表現できる範囲を示しています。
データ型 | ビット数 | 符号あり | 符号なし |
Char / Byte | 8 | -128 ~ 127 | 0 ~ 255 |
Integer / Word | 16 | -32768 ~ 32767 | 0 ~ 65535 |
Long / DWord | 32 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 |
Int64 / QWord | 64 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 |
レジスタ本数が増量
従来は8本だった汎用レジスタが、倍の16本に増えました。クロック周波数が格段に向上するわけではないx64展開ですが、これらの増量されたレジスタを、ソフトウェア側がどれだけ有効活用できるかで、実行速度は格段に向上するはずです。
アセンブラ使いの方やコンパイラ開発者の方は、レジスタの64ビット化より、むしろこちらの方が興味深い拡張だったのかもしれません。いかにメモリアクセスを少なく、レジスタのみで処理をパスするのかは永遠の課題であり、ハードウェアに補助してもらいたい問題の一つでもあります。
SSE2を標準搭載
x86までは、下位互換のため、FPU(実数演算のためのスタック構造64ビットレジスタ)に頼っていた部分があり、実数演算は遅いものだという認識がありました。
これに対し、x64の水準を満たしているCPUは、すべてSSE2を備えています。ということは、x64に対応するソフトウェアは自動的にSSE2に対応するコードを生成できるということになります。
SSE2を標準搭載したことに加え、xmm0~xmm7までの8個だったXMMレジスタの数がxmm0~xmm15までの16個に増加しました。汎用レジスタが16個に増えたのと同様の拡張であり、これもまた一部の技術者にとってはありがたい出来事です。
AMD64機械語の特性
アセンブラ、機械語レベルでは、基本的な記述方法はx86のそれと対して変わりません。気をつけたいところは、拡張されたレジスタをどのように表現するのか、SSE2に完全移行される浮動小数演算をどのような流れで実現すべきなのかにあります(SSE2に関しての解説は、次回に持ち越します)。
幅・個数共に増幅したレジスタの表現
先ほど説明したとおり、AMD64は64ビットを表現できる16個の汎用レジスタを搭載しています。アセンブラ、機械語レベルでそれらの汎用レジスタに自由にアクセスする必要があります。まず、アセンブラでは下記のような汎用レジスタの記述が可能です。
32ビット | 64ビット | 備考 |
eax | rax | 汎用レジスタ |
ecx | rcx | |
edx | rdx | |
ebx | rbx | |
esp | rsp | スタックポインタ |
ebp | rbp | ベースレジスタ |
esi | rsi | ソース インデックス レジスタ |
edi | rdi | デスティネーション インデックス レジスタ |
r8d | r8 | 拡張汎用レジスタ |
r9d | r9 | |
r10d | r10 | |
r11d | r11 | |
r12d | r12 | |
r13d | r13 | |
r14d | r14 | |
r15d | r15 |
この表を見れば一目瞭然ですが、64ビット幅を持つレジスタはrax
、rcx
のように「r」が先頭文字として存在し、r8
~r15
のレジスタが拡張されています。rsp
、rbp
のような特殊な用途を持ち合わせるレジスタはr8
~r15
にはありませんので、これらの拡張レジスタは比較的自由に扱うことができます。
REXプリフィックス
さて、前々回の『x86系CPUのネイティブコードを解析する』で解説したレジスタを識別するための3ビットの内容を覚えておられるでしょうか。3ビットあれば、eax
~esi
の8個のレジスタを識別できるのは明白ですが、AMD64ではそれが16個に拡張されているのです。となると、レジスタを識別するために、x86よりも1ビット余分な4ビット分のデータ領域が必要となります。
だからといって単純にレジスタ識別コード部分を4ビットに拡張するわけにはいきません。なぜなら、レジスタ識別の部分のみのビットを拡張することで、一つの命令語が1バイトで割り切れなくなるためです。
そこで登場するのがREX(Register Extension)プリフィックス。名前の通り、拡張レジスタを表現するためのプリフィックスです。
一般的なプリフィックスと同様、REXプリフィックスは1バイトの領域を使用し、具体的には下記のような状態判別を指定できます。
- r/m、baseに
r8
~r15
のレジスタを使う - reg に
r8
~r15
のレジスタを使う - 64ビットオペランドとしてレジスタを指定する
ようは、「従来のレジスタ識別のための3ビットがr8~r15までの拡張されたレジスタを示していますよ」または「指定したレジスタを64ビットとして扱ってくださいね」という意味付けを行えるのがREXプリフィックスということになります。ちなみに、REXプリフィックスとして指定可能なデータ範囲は0x40~0x4Fまでの16種類になります。下位4ビットはそれぞれ下記のような意味を持ちます。
- 第0ビット … r/m、baseに拡張レジスタ(
r8
~r15
)を指定 - 第1ビット … indexフィールドに拡張レジスタ(
r8
~r15
)を指定 - 第2ビット … ModR/Mのregフィールドに拡張レジスタ(
r8
~r15
)を指定 - 第3ビット … 64ビットオペランドの指定
このREXプリフィックスを機械語の中に埋め込めれば、自動的に従来のネイティブコードフォーマットと高い互換性を保ちながら、拡張されたレジスタを大いに活用できる状況が生まれるワケです。