まずフロントエンドのFetch/Decodeある(Photo06)。従来は4命令/CycleのデコーダにMacroFusionやLoop Stream Detectorを組み合わせる形で実装されていたわけだが、このMacroFusionには色々と制限が多かった。以前こちらでちょっと触れている通り、MacroFusionの対象はCMP+JCCかTest+JCCに限られていたが、Nehalemではこのバリエーションが増やされ、かつ64bitモードでも動作するようになった(Photo07)。

Photo06:これはあくまでCore Microarchitectureでの話。

Photo07:x86の場合、異様に条件分岐命令が多いので、全ての条件分岐命令を網羅しているわけでは無い。例えばJA / JAE / JB / JBE / JC / JCXZ / JECXZ / JRCXZあたりはMacroFusionの対象にはならない。とはいえこれらの利用頻度を考えると、完全にサポートする必要も余り無い気はする。これらはむしろMicroOpsに変換後に、MicroOpsFusionで対処するのが正しいあり方かもしれない。

Stream Detectorにも大幅な変更が入った。従来は命令Fetch後にこれが入り、Loop構造を検出すると再FetchしなくてもLoop Stream Detectorから命令を取り出せる構造になっていた(Photo08)。NehalemではこのLoop Stream Detectorを、Decodeの後に持ってきている(Photo09)。これによりLoop構造内ではDecoderを動かす必要がなくなるので、省電力化が図れる(x86において一番激しく動いているのはDecoder→Rename/Alloc→Scheduler/Retirement Unitの部分であり、Decoderが動かなくなるだけで大幅に省電力化が図れるのは自明の事である)上に、バッファサイズも28 MicroOpsに増加されたことで、やや長いループにも対処できるようになった。

Photo08:ここでx86命令を最大18命令分格納できるため、小規模なループであればここで対処できるという話である。このあたり、Banias/Dothan/Yonahでどうなっていたかという資料がないのではっきりした事は言えないが、分岐予測と併せることでFetchの負荷を減らすことになるのは間違いない。かつ、これはパイプライン構造そのものには手が入らないから、例えばYonahに後付けで追加するには都合が良い機構だったと言える。

Photo09:1 x86Op≠1 MicroOpだから、単純にこれで以前よりも長いループに対応できるとは言いがたいわけだが、MacroFusionやMicroOps Fusionのお陰で命令密度が上がっている事を考慮すると、実質的にはよりバッファが深くなったと考えても良いだろう。

ところでこの構造であるが、見方を変えればNetBurst Architectureで採用されたTrace Cacheの再来とも言える。NetBurstでは12K語分のキャッシュだったから、これに比べれば遥かに小さいとはいえ、うまくLoop構造に入ると全く同じ動作をする事になる。見方を変えれば、これこそがL1命令キャッシュであり、Photo05に出てくる32KB Instruction CacheというのはL2命令キャッシュとも捉えられる訳だ。Stream Loop Detectorは、プログラムの非Loop構造部分の実行中は単にFIFOとして動作することになるから、これはキャッシュそのものと見るのが正しいと筆者は考える。

このLoop Stream Detectorの制御を行うBranch Predictorにも手が入った(Photo10)。もっともその方向性を見ると、非常に興味深い(Photo11)。Banias~Yonah~Merom~Penrynの世代はやはりMobile向けの設計だから、巨大サーバー向けのワークロードなどを考慮する必要はない(というか、それを考慮した結果としてメカニズムが増え、消費電力が増加することは容認できない)というポリシーで、この結果として同じアーキテクチャを使ったXeonなどが、結果としてOpteronに遅れを取る事になったとしても、これは仕方が無い事である。ただいつまでも「仕方が無い」では済ませられなかったようで、Opteron同様にマルチレベルのBranch Predictionを搭載することになった様だ。

Photo10:この説明そのものは至極当然というか、ごく当たり前の話である。

Photo11:具体的にはどんな? という話は今回はまだ未公開。ちなみに競合製品であるBarcelonaの場合はこんな具合

Branch Predictionに関してもう一つはReturn Stack Buffer(RSB)に手が入った(Photo12)。RSBはCALL/RETを利用する際に、RETで復帰すべきアドレスをあらかじめBufferに格納しておき、RET命令が来たら素早く復帰できるようにするためのものだ。ただし、分岐予測にミスをした場合、RSBが上書きされたり、またRSBがあふれた場合に古いデータを上書きして、結果として破壊されてしまう場合がある。これを防ぐために、RSBのRenamingをサポートすることになった。

Photo12:もっともRSBが無限に用意できるわけでないから、ネストして複数のルーチンをCALLするようなケースでは、いずれは溢れるのは避けられない。これはRENAMEしようが何しようが同じである。今回の対処は、SMTへの対応が主なのではないかと筆者は考えている。つまりThread AとThread Bが何れもCALLを発行してRSBを使う場合、これが混在すると内容が破壊されやすい。ところがThread別にRSBのエントリに名前をつけてやることで、混在しても安全になるという話がメインではないかと思う。