Zen 2アーキテクチャの拡張ポイント AMDの新CPUマイクロアーキテクチャ「Zen 2」は、従来の「Zen/Zen+」より性能を大きく引き上げた。性能向上の最重要ポイントは2つ、1つは、SIMD(Single Instruction, Multiple Data)演算ユニットを128-bit幅から256-bit幅に拡張して浮動小数点演算の性能を2倍にしたこと。もう1つは、命令の実行効率を高めて、オリジナルのZenに対してIPC(Instruction-per-Clock)をさらに最大で15%高めたこと。つまり、浮動小数点演算では2倍速く、整数演算でも15%＋クロック分速いのがZen 2だ。 下はZen 2とZenそれぞれのマイクロアーキテクチャのブロックダイアグラム図だ。Zen 2の図で赤い星印がついているのは、Zenから拡張された部分だ。 図中で目立つのは、浮動小数点演算ユニットが128-bit幅から256-bit幅に拡張されたこと、ロード/ストアパイプが2本から3本になったこと。それに対して、ちょっとわかりにくいが、右上の分岐予測(Branch Prediction)に、新たに「TAGE(テイジ)」と呼ばれる予測ユニットが加わっている。このほか、L1キャッシュやOPキャッシュのサイズも変更され、各種キューやレジスタなども拡張されている。ロード/ストアの拡張は、浮動小数点パイプの拡張と連動しているため、もっとも大きなポイントは、分岐予測とSIMDパイプの拡張となる。 SIMDパイプの拡張は、128-bitが256-bitとSIMD幅が2倍になったので、非常にわかりやすい。それと比べると、分岐予測の拡張は、ややわかりにくい。しかし、Zen 2のシングルスレッド性能の向上の大きな成分は、この分岐予測の機能強化にある。そして、CPUとしての機能拡張としては、分岐予測のほうが強烈だ。それは、TAGEが現在最強の分岐予測と言われているからだ。 分岐予測精度の向上は高性能CPUにとって二重にうれしい。性能が向上するだけでなく、分岐予測ミスによる無駄な投機実行が減るため省電力効果もあるからだ。精度向上による省電力効果は、分岐予測機構のハードウェアの大型化による電力アップである程度相殺されてしまうが、それでも省電力性が期待できる。

Zen 2のフロントエンドアーキテクチャ CPUは、大きく分けて、命令を取りこんでデコードするフロントエンドと、命令を実行しデータにアクセスするバックエンドに分けられる。Zen 2マイクロアーキテクチャの、フロントエンド部をZenのそれと比較すると、いくつかのポイントが見えてくる。上でふれた分岐予測については、後の記事で詳しく説明するとして、ほかのコンポーネントを見てみたい。 フロントエンドの基本の構成は分岐予測を除けば、ZenとZen

2で大きくは異ならない。命令系のキャッシュはx86命令をキャッシュするL1命令キャッシュと、デコードした内部命令「マイクロオペレーション(Micro-OP:マイクロOP)」をキャッシュするOPキャッシュの2つ。ただし、L1命令キャッシュはZenの64KBから、Zen 2では32KBと半減した。その一方で、OPキャッシュは、従来の2K Micro-OPsから4K Micro-OPsへと倍増されている。OPキャッシュに、内部命令を最大4K個格納(おそらく4,096個)できる。 「Zenの後、研究した結果、(ダイの)面積をどのユニットにどれだけ割くかのポイントで、よりよいバランスポイントがこの比率だとわかった。OPキャッシュと分岐予測に、より面積を割く組み合わせだ」とAMDのClark氏は言う。 L1命令キャッシュの面積を削り、その分、OPキャッシュと分岐予測の面積を増やすほうが、面積当たりの性能を伸ばすことができるという判断だったことがわかる。L1命令キャッシュは半減されたが、その代わり4-wayセットアソシエイティブだったのが、8-wayに拡張されている。 L1命令キャッシュへの命令フェッチも、基本のアーキテクチャは変わらない。L2キャッシュからL1命令キャッシュへの、命令プリフェッチは改良されている。このプリフェッチの改良は、プリフェッチアルゴリズムの改良だけでなく、分岐予測精度が向上したことも大きいという。次の命令のフェッチ先がより正確に予測できるから、プリフェッチ効率も上がったというわけだ。Translation Lookaside Buffer (TLB)も、基本は変わらず、L1 TLBは64エントリですべてのページサイズをサポート、L2 TLBは命令向けは512エントリで、1Gページはサポートしない。

命令デコード回りはZen世代と変わらず 命令デコーダは4-wayで、最大4個のx86/64系命令をデコードできる。x86/64系命令はCISC(Complex Instruction Set Computer)系命令であるため、1命令に複数のオペレーションが含まれているケースも多い。しかし、Zenも含めて高性能x86 CPUの内部パイプラインはアウトオブオーダ実行であるため、CISCの複合命令では効率的に実行する設計が実現できない。 そこで、x86/x64パフォーマンスCPUでは、CISCの複合命令は、単純なオペレーションのRISC(Reduced Instruction Set Computer)風内部命令に変換されてから実行される。一般に、CPU内部命令はマイクロオペレーション(Micro Operation)を略して「Micro-OP(マイクロOP)」と呼ばれ、「uOP」と表記するメーカーもある。 だが、ややこしいことに現在の高性能x86/x64系CPUは、単純にx86/x64系命令をMicro-OPに変換しない。x86/x64系命令をいったんCISC的な複合オペレーションの内部命令に変換してから、後段のディスパッチステージで単一オペレーションの内部命令に再度変換している。これは、命令のハンドリングを容易にするためで、CPUのインオーダ部では複合型Micro-OPでハンドルして、実際にオペレーションを発行するアウトオブオーダ部で、単純なオペレーションのMicro-OPに分解する。 そして、複合型のMicro-OPをどの程度の粒度にするかが、CPUによって大きく異なっている。さらに、同じAMD CPUでも、Zen系CPUとそれ以前の世代でも大きく異なっている。加えて言うと、各段階の命令の名称も異なっている……AMD CPU同士でさえ。 AMDは、Bulldozer世代までのアーキテクチャでは、複合型のMicro-OPを「マクロOP(Macro-OP)」、単純なOPを「マイクロOP(Micro-OP)」と呼んで区別していた。ところが、ややこしいことに、Zenでは、最初2種類の内部命令がどちらもMicro-OPとされており、名称上で区別されていなかった。 さらにややこしいことに、Zenのソフトウェア最適化ガイドが出た段階で、複合型のMicro-OPが「Instruction(命令)」という記述となり、今度はx86/x64命令と区別がつきにくくなってしまった。 AMDのZen 2のスライドでも、複合型Micro-OPは命令(Instruction)と表記されている。さらに、複合型Micro-OPに、命令フュージョンをかけたものを「融合命令(Fused Instruction)」と呼んでおり、わかりにくさが倍増している。 AMDとしては、Bulldozer時代までのMicro-OPと、ZenのInstructionでは、オペレーションの粒度が異なるため区別したいのだと思われる。しかし、そのInstructionを格納するキャッシュはOPキャッシュで、ディスパッチへのキューは「Micro-OP Queue(マイクロOPキュー)」と、名称の統合性がまったく取れていない。名称については、混乱状態にある。 整理すると、Zenでは、x86/x64命令→Instruction(命令)→Fused Instruction(融合命令)→Micro-OP(マイクロOP)、の順番で命令が変換される。AMDの名称では、このようになる。この記事でも、仕方がないので、これにしたがって、これ以降は上の命令名称で表記することにする。

ほぼ1対1で変換されるZen 2の命令デコーダ L1命令キャッシュはすでに説明したようにZen 2では32KB。ここから、32-byte/サイクルで命令フェッチを行なう。命令フェッチは16-byteバウンダリをサポートしている。x86/x64命令エッチのキューは「Instruction Byte Queue」で、ここから最初の4個のx86/x64命令がピックされ、命令デコーダに送り込まれる。 AMDはZen世代でCPUの命令デコードの仕組みを大きく変えた。Zen系統では、x86/x64命令はほぼ1対1で複合型のInstructionに変換される。それまでのBulldozer系では2個のMacro-OP(ZenのInstructionに相当)に変換されていたケースでも、Zenでは1個のInstructionに変換される。CISCの色彩が強いアーキテクチャとなっている。 たとえば、従来のAMD CPUで「ファーストパスダブル(Fast-Path Double)」と呼んでいたデコード後に2個の複合型Micro-OP、ディスパッチ時に2～4個のMicro-OPに変換される命令も、Zenではデコード後は1個の複合型のInstructionとなる。 命令デコーダは4 x86/x64命令/サイクルデコードで、4 Instruction/サイクルのデコーダ出力。命令デコードの時点では、マイクロコード命令は実際にはデコードされず、マイクロコードROMのアドレスを格納するInstructionに変換される。命令デコーダで変換されたInstructionは、ディスパッチに向けたキューである「Micro-OP Queue」に送られる。 また、デコード済みのInstructionは、内部命令のキャッシュである「OP Cache(OPキャッシュ)」でキャッシュされる。OPキャッシュの目的は、複雑で電力消費の多いx86/x64命令のデコードをバイパスすることで、性能と省電力を高めることだ。Zen 2では、OPキャッシュの量を、2Kエントリから4Kエントリと2倍にすることで、OPキャッシュにヒットする確率を高めている。

x86/x64の最大の弱点は命令デコード x86/x64命令では、命令デコードが設計上の最大の難関となっている。それは、x86/x64がCISC(Complex Instruction Set Computer)型命令で、さらに長年の命令拡張が加わって、きわめて複雑な命令セットアーキテクチャ(ISA:Instruction Set Architecture)」となっているからだ。とくに命令の前につけるプリフィックスが問題で、そのために命令デコードが非常に難しくなっている。最長の命令は15-byteに達する。 x86/x64命令では、命令の切れ目を見つけて切り分けることが難しい。決まった命令長のRISC(Reduced Instruction Set Computer)系CPUでは、たとえば、32-byte毎に命令の切れ目が来るため、命令を切り出すことが簡単だ。 ところが、x86/x64では、命令長のバリエーションがあまりに多いため、簡単に命令を切り分けることができない。x86/x64命令のCPUは、命令デコードのロジックが複雑になり、デコード段での電力消費が大きくなり、デコードのレイテンシが長くなる。こうした問題があるため、現在の高性能x86/x64 CPUは、デコード済みの内部命令をキャッシュしている。AMDでは、Zenからこの機能を搭載した。 OPキャッシュの利点は大きく分けて3点。(1)まず、複雑なx86/x64命令デコーダをスキップすることで、電力効率をアップさせる。(2)同じくデコードステージをスキップすることで、命令フェッチからディスパッチに送るまでのパイプラインレイテンシを低減できる。(3)命令デコーダからのInstruction出力帯域は4 Instruction/サイクルだが、OPキャッシュからは8 Instruction/サイクルと2倍の帯域で命令をフィードできる。 Zenの実装では、x86/x64命令を格納するL1命令キャッシュと、デコード済みのInstructionを格納するOPキャッシュは、分離されたキャッシュとなっている。L1命令キャッシュとOPキャッシュはそれぞれ専用のタグを備えている。しかし、両タグをひも付けする「Micro-Tag(マイクロタグ)」が実装されており、このMicroタグによって、L1キャッシュアクセスがOPキャッシュにヒットするかどうかが判定される。 ZenのOPキャッシュには、2つのモードがある。「Instruction Cache Mode (IC mode)」、と「OP Cache Mode (OC mode)」で、これはタグアクセスの違いだと推測される。基本的にはICモードからOCモードへの一方方向の遷移で使われる。ちなみに、OC modeという用語も、Over Clock Mode(OC Mode)と混同しやすく、AMDは用語の整理をしたほうがいいように感じられる。OPキャッシュとL1命令キャッシュは包括的関係にはなっておらず、命令キャッシュから追い出された場合でも、OPキャッシュに残っているケースがありうるという。

8 Instruction/サイクルで読み出しできる広帯域OPキャッシュ Zen 2のOPキャッシュでは、最大4,096個のInstructionを格納することができる。最初のZenの2倍の容量だ。Instructionが32-byte長だと仮定するなら約16KB相当の容量となる。L1命令キャッシュが32KBなので、乱暴な言い方をすれば約半分に相当とも言えるが、L1命令キャシュはx86/x64命令なので、単純な比較はできない。 ZenのOPキャッシュのキャッシュラインは、8 Instructions/ライン。つまり、命令デコーダの出力の2倍の幅となっている。Zen 2でも、これは変更がないと見られる。OPキャッシュはトレースキャッシュ(Trace Cache)ではなく、トレースビルドを行なって分岐パスを格納しているわけではなくアドレスベースだ。4K Instructionsは最大値で、実際にはキャッシュの命令スロットが埋まっていない可能性もある。また、すべてのInstructionがキャッシュラインに8個収まるわけではない。 Zenでは、Instructionのうち、64-bit命令でイミディエイト(immediates)かディスプレイスメント(displacements)を持つ命令は2スロットを使うとされていた。また、マイクロコード命令も、2スロットを占める。Zen 2でも、おそらくこの点は変わらないと推測される。基本のInstruction長は短めに抑えて、長くなるInstructionだけ2倍長にしたと思われる。 OPキャッシュからの出力は最大8 Instructions/サイクル。つまり、1つのキャッシュライン分のInstructionを1サイクルで読み出しする。OPキャッシュから読み出したInstructionは、命令デコーダはバイパスして、ディスパッチに向けたキューである「Micro-OP Queue」に送られる。 言い換えれば、Micro-OPキューは、8個のInstructionを読み出す帯域を備えていることになる。通常のデコーダからのInstruction読み出しでは、その半分しか使わない。ちなみに、x86/x64 CPUでは常に4命令/サイクルでデコードできるとはかぎらないため、OPキャッシュからの8 Instruction/サイクルのフェッチはキューを埋めることに役立つ。