ある程度頭に入っているつもりだが、CPUにおけるアウトオブオーダ実行でのメモリアクセス命令の取り扱いについて確認する。
- EECS 470 Lecture 12 Memory Speculation
https://web.eecs.umich.edu/~twenisch/470_F07/lectures/12.pdf
動的にメモリ操作の順序を変えることにはいくつかのリスクがあるのだが、当然のようにRAWハザードを考慮する必要がある。 そして注意しなければならないのは、メモリアクセス命令同士には、メモリアドレスによる見えない依存関係が存在しているということ。
store x10, (a0) load x11, (a2)
果たしてload
はstore
よりも先に投機実行することができるだろうか?答えは、基本的には否。a0
とa2
がもし同じアドレスである場合にはload
の値はstore
によって変わるかもしれない。store
のアドレスが確定するまでは、load
はいったいどの値をロードすればよいのか決定できない。
アウトオブオーダにおけるLSUの組み方にはいくつかの方法があるが、大きく分けて、
- ロードキュー(LDQ)とストアキュー(STQ)をまとめて扱う方法 (LSQ : Unified Memory Access Queue)
- 簡単だが実装が汚くなる。
- ロードキュー(LDQ)とストアキュー(STQ)を別々に扱う方法
- 複雑だがよりエレガントな実装になる
というように分けられる。
まずはUnified Memory Access Queueだが、以下のようになる。各キューはインオーダで格納されインオーダで解放される(まあインオーダで開放されないと面倒なので)。
ロード命令の発行条件は、自身よりも古いストア命令(older)の物理アドレスがすべて判明した場合となる。つまり上記のstore
とload
の依存関係が解決された場合のみ発行できるという条件である。
次にロードとストアのキューを分離する方法だが、個々のキューで動作が異なる。
まず、分離した場合のロード命令の動作だが、個々のストアエントリとアドレスを比較し、さらにAge Check (ロード命令よりもアドレスのヒットするストア命令が古いかどうか)を判定したうえでデータをフォワードする。
こうすると必ずロード命令と古いストア命令の間に依存関係が発生し、古いストア命令の物理アドレスが判明するまでは後続のロード命令は投機実行することができない。
そこでどうするかというと、若いロード命令は「古いストア命令の物理アドレスが判明していなくてもどうせヒットしないだろ」という楽観的メモリスケジューリングを行うことになる。
ストア命令は物理アドレスが判明した時点でそれをロード命令の各エントリ(LDQ)と比較し、万が一当該ストア命令よりも若い命令で物理アドレスがヒットした場合、「そのロード命令は誤っているのでやり直せ」と指令を出す。