BOOMの分岐予測について、boom-docs.orgを読みながら解き明かしていこうと思う。
いくつかテストパタンを作ってRASの挙動を確認してみることにした。作ってみたのは以下のようなマイクロベンチマーク。
.section .text dummy_call: ret .global recurse_add recurse_add: bnez a0, _next li a0, 0 ret _next: addi sp, sp,-24 sd ra, 8(sp) sd a0, 16(sp) addi a0, a0, -1 jal recurse_add jal dummy_call mv t0, a0 ld a0, 16(sp) ld ra, 8(sp) add a0, t0, a0 addi sp, sp, 24 ret
jalrでもjalでも良いけど、現在のPC+4をRASで積み上げていくためのコード。C言語で書くと単純すぎて最適化されてしまうためアセンブリで書いた。
このコードの目的は、recurse_addを呼び出すことによりRASに積み上げられ、投機実行された次のdummy_callの呼び出しもRASに積まれることを想定している。
2回分RASに積み上げたうえで、retはrecurse_addからの1回なのでRASから1回しか取り出されないはずなので、そこで矛盾が生じるのをどのように処理しているのかをチェックしている。
まず、RASへの書き込みはwrite_validにより引き起こされるが、この段階でras_idxがインクリメントされている。そして投機的に別のジャンプ命令によるRAS登録が想定されている。
以下のように波形を確認すると、RAS[4]への登録後に投機的に次々とエントリが登録されていることが分かる。

投機的に登録されたものについては、バックエンドからのフラッシュ情報によりリストアすることができる。
以下の図では、バックエンド側からのredirect_flushによりras_idx=4から先のRASの情報をフラッシュしている。
