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の情報をフラッシュしている。