このスカウトモードでは、先行するスカウトスレッドの実行結果はメモリのフェッチなどに間接的に利用されるだけであったが、そのまま、演算結果も使ってしまおうというのがEXEモードである。

次の図は、発表を元にした筆者の推定によるEXEスレッドの動作を示す図である。

EXEスレッドの動作(筆者の推定のよる図)

メモリのA番地をアクセスして、レジスタR3にロードする命令nが、キャッシュをミスして時間が掛かることが判明すると、スカウトスレッドの場合と同様に、アーキテクチャレジスタのチェックポイントとEXEスレッド用のコピーを作り、EXEスレッドをforkして命令n+1から実行を開始する。

命令n+1は、実行を完了していない命令nに依存していないので、そのまま実行を完了して、演算結果をEXEスレッドのアーキテクチャレジスタに書き込んでしまう。次の命令n+2が命令nがロードするレジスタR3に依存する場合は、この命令は正しく実行できないので、延期命令キューの溜め込む。そして、この図では、命令n+3も実行中のロード命令とは関係の無い命令であり、実行を完了してしまう。

そして、命令nのロード命令が完了すると、EXEスレッドは、命令デコードユニットからの新たな命令の実行を止め、延期命令キューに溜まった命令を実行する。この図では、命令n+2だけしか入っていないので、この命令を実行すると延期命令キューは空になり、joinが行われる。EXEモードではスカウトの場合と異なり、継続されるのはEXEスレッドであり、以降、こちらがメインスレッドとなる。

このように実行すると、命令nに依存しない命令n+1とn+3は、キャッシュミスによるメモリアクセスの待ちの間に実行されてしまい、join後に再実行する必要がなくなる。実は、アーキテクチャレジスタは、NT(Not There)というフラグビットをもっており、完了していないレーテンシの長い命令の結果を格納するレジスタエントリにはNTビットを立ててEXEスレッドを走らせる。そして、命令n+2のように、入力オペランドにNTビットが立っていると、命令は実行するのであるが、演算結果はNTビットを立ててレジスタファイルに格納するという動作を行う。従って、この図では存在しないが、命令n+2の演算結果を使う命令があれば、その命令も再実行のために延期命令キューに格納されるようになっている。

EXEスレッドは、ある意味では、投機的に実行されるスレッドであり、投機が失敗するとその実行はキャンセルされて、fork時点のメインスレッドの状態に戻す必要がある。このEXEスレッドの中で、他のプロセサから見えるメモリ領域(キャッシュコヒーレントなキャッシュを含む)にデータを書き込み、それを他のプロセサが使ってしまうと、投機失敗の場合のキャンセルが効かなくなってしまう。このため、EXEスレッドの実行中に発生したストア要求はストアキューに溜め込んでおき、キャッシュには書き出さない。そして、joinの時点で、ストアキューに溜まっているストア要求を処理する。

また、EXEスレッドの中で実行したロード命令のアクセスしたメモリ番地が、別のプロセサで書き換えられるという可能性もある。そのこと自体は異常ではないが、EXEスレッド内で、ロード結果を使って演算を行い、それをストアするというようなケースでは、他のプロセサから見て、メモリの更新の因果関係が異常になってしまうケースが存在しうる。このため、EXEスレッド内のロード命令が読み込んだキャッシュラインにはSビットを立てておく。そして、joinの時点までにSビットの立っているキャッシュラインが他のプロセサの書き込み要求によりInvalidateされたり、キャッシュの領域不足でReplaceされたりした場合は、ロード命令が古い値を読んでいる可能性があるので失敗とみなして、EXEスレッドの結果は全部キャンセルして、メインスレッドのチェックポイントから実行を再開する。

なお、スカウトモードとEXEモードの図を見ると、forkからjoinの間は、メインスレッドはレーテンシの長い命令の完了待ちの状態であり、もう一方のスレッドだけしか命令をフェッチしていない。従って、Rockの実装では、アーキテクチャレジスタは、両方のスレッドの分を持つ必要があるが、命令発行ユニットとしては、1つの命令ストリームを扱えればよい。混乱しないように確認しておくと、Rockのマイクロコアは2つのハードウェアスレッドをサポートするので、アーキテクチャレジスタは、その2倍の4組が存在し、命令発行ユニットは2個である。