x86/x64で効力を発揮するマイクロOPキャッシュ AMDの新CPUマイクロアーキテクチャ「ZEN」では、内部命令「マイクロOP(Micro-OP)」を格納する「OPキャッシュ(OP Cache)」を備える。ZENにおいて、性能/電力が大幅に向上する秘密の1つは、このOPキャッシュだ。複雑極まりないx86/x64命令のデコードをバイパスすることで、デコードの消費電力を削減、レイテンシを短縮し、性能を向上できるからだ。 これまでも、x86/x64 CPUでは、内部命令のキャッシュが採用されてきた。Intelの場合は、Pentium 4のNetBurstアーキテクチャで、マイクロOPを格納する「トレースキャッシュ(Trace Cache)」を採用した。トレースキャッシュは、実行された命令の軌跡(Trace)に沿ってキャッシュに格納する方式。分岐のない命令部分であるベーシックブロック(Basic Block)群を、条件分岐命令の予測された分岐に沿って結合させたトレースを生成して格納する。しかし、トレースキャッシュは、トレースビルド(トレース生成)が複雑であるため、効果が出にくいケースがあった。 そこで、IntelはSandy Bridgeから、異なる仕組みの「uOPキャッシュ(uOP Cache)」を導入した。uOPはマイクロオペレーションで、AMDのマイクロOPと同じ意味だ。uOPキャッシュは、トレースを生成せず、L1命令キャッシュと同様に、アドレスベースで読み出すことができる。ここは、トレースキャッシュと大きく異なる点だ。命令フェッチライン(16-byte)を2つ繋げた32-byteの中のマイクロOPを、uOPキャッシュラインに格納する。 AMDは、ZENにおいて、ついにマイクロOPのキャッシュを搭載した。マイクロOPをキャッシュする場合、問題となるのは、キャッシュにどのように命令を格納して、どうやってアクセスできるようにするか。具体的に言えば、メモリ上の命令のアドレスを格納したInstruction Pointer(IP)レジスタと、OPキャッシュライン上のマイクロOP群のアドレスをどう紐付けるかが重要となる。ここが難しいため、マイクロOPのキャッシュは採用が難しかった。 ZENで採用したOPキャッシュは、おそらく、IntelがSandy Bridge以降に採用したキャッシュと似たような仕組みと見られる。まず、マイクロOPを格納するものの、トレースキャッシュではない。そして、L1命令キャッシュからの命令フェチラインと紐付けされていて、IPから簡単にOPキャッシュ上の命令をアドレスできると見られる。 ZENのアーキテクトであるMike Clark氏(Senior Fellow, AMD)は次のように説明する。 「OPキャッシュはトレースキャッシュではない。ベーシックブロックは、依然として尊重している。トレースキャッシュは非常に複雑なので、適していないと考えた。また、L1命令キャッシュとOPキャッシュは分離されたキャッシュで、L1命令キャッシュはOPキャッシュに対して、インクルーシブキャシュにはなっていない。OPキャッシュは、専用のキャッシュタグを備えている。マイクロタグ(Micro-tags)で、L1命令キャッシュとOPキャッシュのどちらでヒットするのかが分かる」。 OPキャッシュはL1命令キャッシュにインクルードされていない。つまり、OPキャッシュでヒットしても、L1でヒットしないケースもありうる。ただし、エクスクルーシブ(exclusive)キャッシュとも言っておらず、分離されたキャッシュだと言っている。OPキャッシュの大部分はL1命令キャッシュにインクルードされるが、L1からキャッシュラインが排除されても、OPキャッシュに残る場合があるという。Intelアーキテクチャの場合は、uOPキャッシュはL1命令キャッシュにインクルードされると見られている。命令フェッチでは、OPキャッシュとL1命令キャッシュの両方をプルーブする必要があるが、それはマイクロタグ(Micro-tag)で行なう。 AMDは、OPキャッシュの具体的な仕組みやサイズを、まだ明らかにしていない。IntelはSandy Bridgeで最大1.5K uopsの容量(実際には命令フェッチラインとuOPsキャッシュラインのひも付けでキャッシュラインが有効に使われない場合もあるので1.5Kはあくまでも最大)のuOPsキャッシュを採用した。AMDも、相当量のキャッシュを搭載すると見られる。 また、OPキャッシュの採用は、ZENマイクロアーキテクチャの、命令デコードの仕組みにも影響を与えていると見られる。そして、ZENの命令デコードの仕組みから、AMDの方がIntelよりも、同じキャッシュ量で格納できるオペレーション数は多いと推測される。

CISCの特徴を残した中間段階のマイクロOP ZENマイクロアーキテクチャの大きな特徴は、命令デコードが2段階構成になっていることだ。 「主に命令デコーダでデコードを行なうが、ある程度のデコードはOPキャッシュとマイクロOPキューの後にも発生する。OPキャッシュとマイクロOPキューに格納されるマイクロOPは、かなり“デンス(高密度:Dense)”だ。それが、ディスパッチされる段階で、より伝統的なマイクロOPに展開される。本当は、デンスなマイクロOPと、展開したマイクロOPでネーミングを変えるべきだが、今回はしていないので、ちょっと分かりにくいかも知れない」(Clark氏,AMD)。 AMDの従来のアーキテクチャも、Intelの現在のアーキテクチャも、いずれも2段階のデコード方式を取る。x86/x64命令は、CISC(Complex Instruction Set Computer)型であるため、複数のオペレーションが含まれている命令が多い。しかし、内部パイプラインはアウトオブオーダ実行であるため、CISCの複合命令では効率的に実行する設計が実現できない。 そこで、x86/x64高性能CPUでは、CISCの複合命令は、単純なオペレーションの内部命令、マイクロOPに変換されてから実行される。マイクロOPは、言ってみればRISC(Reduced Instruction Set Computer)型の単純命令だ。例えば、ロード/演算/ストアの複合CISC命令の場合は、ロード命令、演算命令、ストア命令が分離したRISC型マイクロOPに分解される。これが、CISCのマイクロOP変換の基本だ。 しかし、現在のx86/x64系CPUの多くは、CISCの特徴をある程度保持した、複合型のマイクロOPを採用している。インオーダ部では複合型マイクロOPでハンドルして、実際にオペレーションを発行するアウトオブオーダ部で、単純なオペレーションのマイクロOPに分解する。 AMDの従来のアーキテクチャでは、複合型のマイクロOPを「マクロOP(Macro-OP)」、単純な方を「マイクロOP」と呼んで区別していた。今回のZENでは、2種類の内部命令を区別するネーミングがないが、依然として2種類の内部命令となっている。ちなみに、マイクロOPは、表に露出するISA(Instruction Set Architecture)と異なり、命令長を切りのいい単位(32-bit長など)にする必要がない。変則的な長さでも許容できるため、マイクロOPは自由な命令設計ができるという。 複合型の内部命令を取る点は、IntelとAMDのx86/x64 CPUマイクロアーキテクチャに共通している。しかし、ZENでは2段階デコードがさらに進んだ。大半のx86/x64命令が、1対1で、1個のデンスマイクロOPに変換される。複合型マイクロOPの粒度がますます大きくなり、単純マイクロOPに分解されるステージにデコード機能がさらに移動した。ZENでは、命令デコーダは、命令デコードからディスパッチまでのステージ全体に拡張されたイメージだ。

命令デコーダの仕組みが大きく変わったZENアーキテクチャ AMDの従来アーキテクチャでは、命令デコード段階では、x86/x64命令は3つのデコードタイプに分かれており、AMD独自のネーミングがされていた。1個のマクロOPに変換されるのが「ファーストパスシングル(Fast-Path Single)」、2個のマクロOPに変換されるのが「ファーストパスダブル(Fast-Path Double)」、2個以上のマクロOPとなるのが「マイクロコード(Microcode)」だ。1個のマクロOPは、通常は2個までのマイクロOPを含む。 【表】Bulldozerマイクロアーキテクチャでの命令デコード種類 Fast-Path Single 1個のマクロOP 1～2個のマイクロOP Fast-Path Double 2個のマクロOP 2～4個のマイクロOP Microcode 3個以上のマクロOP 3個以上のマイクロOP AMDのデコーダは継承性があり、高性能CPUのBulldozer系と省電力CPUのBobcat系でも似通った部分が多い。ちなみに、AMDアーキテクチャの場合はロード/演算/ストアのx86/x64命令の場合には、ロード/ストアOPと演算OPの2個のマイクロOPに分解され、3個にはならない。同じメモリアドレスのオペランドのロードとストアは、AMDでは1個のマイクロOPに格納されるからだ。おそらく、この基本は、ZENでも継承されていると思われる。 2個のマクロOPに変換されるファーストパスダブルは、例えば、256-bit SIMDのAVX命令などで、2個の128-bit SIMDのマクロOPに変換されるケースなどだ。メモリアクセスを含む場合は、2個のマクロ128-bit SIMD OPがそれぞれ2個のマイクロOPを含む。合計で4個のマイクロOPが、1個のAVX命令から生成される。 BulldozerやJaguarでは、上のようにデコードタイプによって、x86/x64命令は種類によって2個以上のマクロOPに変換されていた。つまり、x86/x64命令は、命令デコーダから、2個以上のマクロOPとして出力されることもそれなりの頻度であった。しかし、ZENではそれがほとんどなくなり、x86/x64命令はほぼ1対1で、1個のマイクロOPとして出力されるようになったという。 「ZENの命令デコードは、Intelとはかなり異なっている。命令デコーダでは、命令バウンダリを見つけて(x86/x64命令を切り分け)、マイクロOPに変換してマイクロOPキューに送る。しかし、この時のマイクロOPは非常にデンスだ。我々がファーストパスダブル(Fast-Path Double)と呼ぶ命令も、マイクロOPキューの中では、1個の(デンス)マイクロOPとなってる。ディスパッチ(ステージ)までそのままだ」(Clark氏,AMD)。 BulldozerやJaguarでは、2個のマクロOPに変換されたファーストパスダブル(Fast-Path Double)も、ZENでは1個のデンスマイクロOPとして扱われる。ちなみに、IntelのCore系のマイクロアーキテクチャも2個のマクロOP的な内部命令にデコードされるケースがあり、Bulldozerと部分的に似ている。Intel系のマイクロアーキテクチャで、x86/x64命令を1個の内部命令に変換する傾向が強いのは、Atomに使われている「Silvermont(シルバモント)」系マイクロアーキテクチャだ。

マイクロコードエンジンをマイクロOPキューに x86/x64命令を分解しないで1個の内部命令にマップする方式は、ZENの命令デコード全般で一貫した思想となっている。x86/x64 CPUでは、非常に複雑な命令はマイクロコードエンジンROMでマイクロOPに展開される。AMDの場合は、BulldozerやJaguarまでは、1～2個のマクロOPに変換される命令は通常の並列型デコーダ、3個以上のマクロOPに変換される命令はマイクロコードシーケンスとなっていた。そして、従来は、デコードステージにマイクロコードエンジンがあり、そこで3個以上のマクロOPに変換されていた。 しかし、ZENマイクロアーキテクチャでは、マイクロコードROMが必要な命令は、命令デコードステージでは展開されず、マイクロコードROMアドレスを格納すると見られるデンスマイクロOPに変換される。ZENでは、マイクロコードROM命令は1個のデンスマイクロOPに転換して、マイクロOPキューに格納される。OPキャッシュに格納されるのもデンスマイクロOPだ。マイクロコードROMでの展開が必要なデンスマイクロOPが展開されるのは、マイクロOPキューの最後の方でとなる。 「マイクロコードROMからのマイクロOPは、マイクロOPキューには格納されない。(その代わりに)我々は、マイクロコードROMのアドレスをトラックする。我々は、(デンスマイクロOPを)最後の瞬間まで展開しないで保持しようとしている。マイクロOPキューの中の(マイクロコードROMが必要な)マイクロOPは、ディスパッチのタイミングに合うように設定されたキッキングシーケンス(Kicking Sequence)で、マイクロコードROMへとキックされる」(Clark氏,AMD)。 ZENのデコード段では、マイクロコードROMのアドレスを判定して、それをマイクロOPとしてトラックすると見られる。ちなみに、IntelのuOPキャッシュも、マイクロコードエンジンからの出力の内部命令は、uOPキャッシュに格納しない。代わりに、マイクロコードROMのアドレスを持つようになっている。内部命令キャッシュから見ると、IntelとAMDは似たような仕組みを取っている。これは、IntelとAMDで、ブロック図の書き方が異なるだけとも言えるかも知れない。 ちなみに、スタックエンジン(Stack Engine)もここに配置されている。スタックエンジンは、プッシュ(push)/ポップ(pop)で操作される、スタック(積み上げ)型のデータ保存領域の操作を行なう専用エンジンだ。スタック操作はx86のレガシの1つで、これを実行エンジンのロード/ストアパイプで行なうと、電力消費が多い上にレイテンシも長くなる。そのため、高性能x86/x64 CPUでは、専用エンジンを設けて処理する場合が多く、ZENもその方式を取る。省電力に効果がある。 面白いことに、マイクロOPをデンスにする「ブランチフュージョン(Branch Fusion)」については、ZENは命令デコーダで実行しない。AMDは、テスト/コンペア系命令とジャンプ命令を融合させるブランチフュージョンを、Bulldozerから採用した。依存性のある2個のシンプルな命令を組み合わせて、1個のマイクロOPとして1個の実行パイプで実行する。似たようなテクニックはIntelも採用している。命令の融合によって、マイクロOP数を減らし、スループットを高めることが狙いだ。 内部命令数を減らすという目的からすると、本来なら命令デコーダ部でフュージョンを行なう方が合理的だ。しかし、ZENでは「フュージョンはデコードでは行なわず、ディスパッチでフュージョンを行なっている。デコーダでは、依然として2個のマイクロOPとなっている。ディスパッチステージで、一緒にされて1個のマイクロOPとなる。ディスパッチステージからのディスパッチは6マイクロOPが上限だが、フューズしたマイクロOPは1個と数えられる」(Clark氏,AMD)という。 ブランチフュージョンについては、命令デコードの段階でマイクロOPは減らず、ディスパッチ以降のアウトオブオーダ部で減ることになる。つまり、インオーダ部の命令デコード帯域を増やすことが目的ではない。ここはIntelと異なる点だ。AMDのBulldozer系については、明記されていないが、ブランチフュージョンで2命令が1マクロOPに変換されるとみられる。