マイコンでは一般的なのかもしれないが、プログラムの最適化の1つの方法として命令フェッチラインに基づく最適化というものがある。
これは早い話が、ループの境界がなるべく命令フェッチの範囲を超えないようにし、フェッチ回数を減らすというものだ。
例えば、4命令をループさせるプログラムがあったとして、
data_ready_loop: sw x2,0x00(x1) // addi x2,x2,0x01 addi x1,x1,4 addi x4,x4,1 bltu x4,x5,data_ready_loop
このプログラムをコンパイルすると、以下のようなアセンブラが生成された。
80000090 <data_ready_loop>: 80000090: 0020a023 sw sp,0(ra) # 80002000 <_sp+0xffffde38> 80000094: 00408093 addi ra,ra,4 80000098: 00120213 addi tp,tp,1 # 1 <_tbss_end+0x1> 8000009c: fe526ae3 bltu tp,t0,80000090 <data_ready_loop>
現在、自作RISC-Vプロセッサのフェッチラインは128ビットだ。つまり、これが0x10の境界に入っていれば、一度にフェッチしてこれる。 これが、フェッチ境界を跨いでしまったらどうだろう。
800000c8 <data_ready_loop_hit2>: 800000c8: 0020a023 sw sp,0(ra) # 80002000 <_sp+0xffffde78> 800000cc: 00408093 addi ra,ra,4 800000d0: 00120213 addi tp,tp,1 # 1 <_tbss_end+0x1> 800000d4: fc526ee3 bltu tp,t0,800000b0 <data_ready_loop_hit>
この場合、このループを実行するのに、2回のフェッチが必要になる。この2種類のループを、RTLシミュレーションで比較した。
- フェッチアラインに合わせたもの: 151cycle
- フェッチ境界を跨いだもの : 239cycle
結構な差が出てきた。これはフェッチを2回したことにより、無駄な命令発行をしているということでもある。