以前から話題になっていたAMDのZenであるが、IDF 2016の裏番組として、AMDが開催したイベントでその一端が明らかにされたほか、8月21日から23日にかけて開催されたHotChips 28で、Mike Clark氏(AMD Senior Fellow)が、正式にZenのアーキテクチャ詳細を説明するなど、相次いで情報が出てきた。今回はこれについて解説したい。

Overall Architecture

年初の「PCテクノロジートレンド 2016」にて、GCCのZen向けのPatchから、ある程度Microarchitectureが推察できたという話を紹介したが、今回発表された内容を見ると、このZen向けPatchに沿った構造になっていることが明らかになった(というか"Zenの構造に沿った形でPatchが構成されていた"が正確か)。

まずOverallであるが、ZenはJaguarと同程度の低い消費電力から、Excavatorにかなり近いところまでカバーするScalableなcoreであり、Excavatorと比較して、同じ消費電力であればIPCがおおむね40%高いとしている(Photo01)。

またIPCを改善しながらも、1cycleあたりの消費電力をExcavatorと同等にしている(Photo02)ということは、いまExcavatorがターゲットにしているモバイル向けにも十分利用できることを示している。また、従来だとJaguarでカバーしていた低消費電力のレンジもZenでカバーできるというわけで、将来的にはTabletあたりまで狙える。

その40%のIPC改善(と消費電力の低減)を実現するための主な特徴がPhoto03となる。以下細かく説明したい。

Photo03:数字の比較はいずれもExcavator coreとのもの

Photo04が全体の構成となる。Bulldozerで導入された、FPUとALUを分離するデザインは放棄され、昔のK7/K8/K10を思わせる構造になった。ただし、単なる先祖返りではなく、いくつかの変革も見られる。まずDecodeはx86命令を4命令/cycleでデコード、これをMicroOp Queueに蓄える形になる。このQueueには別系統でOp Queueが設けられ、Decodeを動かさずにこちらからMicro-Opの供給を受けることも可能になっている。

DispatchはIntegerとFloating Pointで別々に行われるが、面白いのはSchedulerを各実行ユニットごとに用意する形を採っていることだ。Integer Unitだけで192 instruction in flightということで、Scheduler毎に48命令を保持できるものと思われる。またAGUに関しては最大72 Out-of-Order Loadをサポートする。Register Fileが合計168というのもかなり大きめ目の数字だ。

一方のFloating Pointに関しては、特にSSE/AVXなどでは複数のユニットを連携して動かす方式になっていることもあってか、全体で1つのSchedulerという構成になっており、理論上は1cycleあたり、256bitのFMACを同時に2つ行えるように見える。しかし、PCテクノロジートレンド 2016で紹介したように、avx256_fma命令の実行はFPU2が使われないといった制約があり、実際には256bitのFMACが1cycleあたり1命令に制約されている。

これを支える足回りだが、L1 I-Cacheは64KB、L1 D-Cacheは32KB、Unified L2 Cacheは512KBとなっている。ここまではcoreの一部だが、これとは別に外部にL3 Cacheが搭載される。

ちなみにL1 I-CacheがL1 D-Cacheの倍なのは、この世代からSMT(Simultaneous Multi-Threading)を実装していることと無縁ではないと思う。後述するようにZenではL1/L2/L3の帯域がいずれも非常に大きいので、L1 Missの場合のペナルティが従来よりも低いと考えられる。そのため、必ずしもL1を大容量にする必要はない。つまり、1 Thread動作でよければ32KBでもそれなりに性能は出ると思われる。ただSMTだと全く異なるプログラムを実行することも十分考えられるから、このためには64KB程度必要だった、ということであろう。

Fetch/Decode

さらに詳細についてみていく。まずはFetch/Decode段ということで、Fetchであるが、このステージではL1から32Bytes/cycleで命令を読み取り、これをDecode段に送り出す仕組みとなっている(Photo05)。

この際に、Micro-Tagを生成し、これをI-Cache内の命令(とMicro-Op Cache)に付加する仕組みが用意されている。これは単に命令の区切り位置を示すだけに留まらず、その命令の依存関係(Branch Predictionからの情報を基にしているから、おそらくはループ制御に関係する情報と思われる)も付加する形となっている。

また、後述するReturn Stackに関しても、32 entryのReturn Stackが用意されており、これが溢れない限りはこの中で処理する仕組みが取られている模様だ。これはAMDがK10の世代で実装したSideband Stack Optimizerをもう一歩進めたものだ。

Stackは簡単にいうとStack Pointerを足したり引いたりしながら、アドレスをメモリに保持したり、そこから復活させたりするものだが、処理そのものは単純で、これだけのためにALUを動かすのは消費電力的にもったいないということで専用回路を設けたのがSideband Stack Optimizerである。

ただSideband Stack Optimizerでも、Stackの実体はメモリ中に保持されるから、当然メモリアクセスが発生する分、消費電力が増える。今回は32entry分のStackは内部のMemfileで処理できるから、極端にStackを深く取らない限り、この範疇でStackへのPUSH/POPが完結し、高速かつ省電力になるという話の様だ。

ちなみにBranch Predictionのメカニズムについて詳細は明らかになっていないが、かなり大きなBTB(L1/L2に分かれている)を搭載するほか、TLBもL0～L2まで用意される。これは、明らかにServer向けのWorkloadを考慮したものと思われる。ちなみにTLBのサイズを直近のIntel製品と比較すると

Haswell Broadwell Skylake Zen L0 0 0 0 8 L1 128 128 128 64 L2 1024 1536 1536 512

ということで、絶対的な量で言えばややZenの方が少ないのだが、L0 TLBを設けている点がちょっと異なる。Skylakeの場合、L1 TLBのLatencyは4cycleほどになるが、ZenではL0 TLBというからには1cycle程度のLatencyで提供できているのかもしれない。また、BTBそのものも高速で、1cycleあたり2 つの分岐先アドレスを取得できるとする。これはALUの側も最大1cycleに2つの分岐命令を処理できることに対応したものであろう。

続いてはDecode(Photo06)だ。Pickは命令の区切りにあわせて命令を引っ張り出す作業で、DecodeはこれをMicro-Opに変換、Micro-Op Queueに投入する。実際はここからもう一段、Microcode ROMを経てDispatchされる。つまり、Decode段で生成されるMicro-opは言ってみれば中間コードだと想像できる。また、OP Cacheもこの中間コードのまま保持する構造のようだ。ちなみにこのステージにStack Engine Memfileも保持されている。

ここでもう1つ追加になったのが、Branch Fusionである。x86における分岐では、まずcmpなどの比較命令が行われ、続くjnzなどの分岐命令が比較結果に応じて分岐を実行する形になるが、Decode段ではこの2つの命令は別々のMicro-opになる。これを1つのMicro-opとすることで、Schedulerの効率化や消費電力の低減を図っている。