アウトオブオーダー実行の性能改善

ここでは、アウトオブオーダー実行が可能なマイコンの性能改善案(アセンブラ・レベルの話)の一例を記載しますが、本来、マイコンメーカとコンパイラメーカが協議することなので参考にご覧頂きたい。


その1)2waySuperScalar対応コンパイラ vs 2waySuperScalar未対応コンパイラ

まず、2waySuperScalarとは2個の命令を同時に実行できるマイコンのことを意味し、アウトオブオーダー実行のマイコンではよく採用されている技術である。
アウトオブオーダー実行のマイコンは、マイコン内で命令間の依存関係を無くすため、レジスタ・リネーミングという機能があるので、2waySuperScalar未対応コンパイラが吐き出したコードを実行しても、性能向上を見込めます。しかし、レジスタ・リネーミングのためにマイコンが持つ内部レジスタは有限なため、2waySuperScalar対応コンパイラがあれば、コンパイラが可能な限りレジスタ依存のないコードを吐くため、マイコン内のレジスタ・リネーミング機能に負荷をかけずに(レジスタ・リネーミングのためのマイコンの内部レジスタを使わずに)、効率的に命令を実行できます。
下図の例のように、2waySuperScalar対応コンパイラだと、レジスタr2とレジスタr10の処理ができるだけ交互に配置されます。

--- 2waySuperScalar未対応コンパイラはレジスタが依存したコードが続く ---
LD r2, 0x0(r3) //レジスタr3が指すアドレスからデータをr2にロード
ADDI r2, r2, 0x20 //レジスタr2に0x20を加算
SLL r2, r2, 0x16 //レジスタr2を左に16bitシフト
SD r2, 0x0(r3) //レジスタr3が指すアドレスにr2のデータをストア
LD r10, 0x0(r11)
ADDI r10, r10, 0x20
SLL r10, r10, 0x16
SD r10, 0x0(r11)
 
--- 2waySuperScalar対応コンパイラはレジスタ依存のないコードを挿入 ---
LD r2, 0x0(r3)
ADDI r2, r2, 0x20
LD r10, 0x0(r11) //2waySuperScalar未対応コンパイラと違うところ
SLL r2, r2, 0x16
ADDI r10, r10, 0x20 //2waySuperScalar未対応コンパイラと違うところ
SD r2, 0x0(r3)
SLL r10, r10, 0x16
SD r10, 0x0(r11)

その2)整数/浮動小数点の積和命令

マイコンによっては、整数/浮動小数点の積和命令を実行するユニットを1つしか実装していない場合や、2つあっても積和命令の実行サイクル数が大きい場合、レジスタが依存する命令が後続にあると、効率的に処理できません(多くの待ち時間が発生します)。性能改善のため、例えば、
・実行サイクル数が比較的小さい整数の積和命令の場合は、積和命令間にレジスタが依存しない積和命令以外の命令を挿入。
・実行サイクル数が比較的大きい浮動小数点の積和命令の場合は、実行サイクル数が比較的小さいADD命令(加算)とMUL命令(乗算)の命令の組合せに分割。
 にすると良いです。マイコンの実行サイクル数や、コンパイラの最適化の内容を確認してコンパイラからコードを吐かせましょう。

その3)ロード命令、ストア命令

まず、下記のような処理をマイコンで実行したとする。更に、0x0(r3)と0x0(r11)が指すデータキャッシュのラインは異なり、それぞれのラインでミスヒットが発生と仮定する。

 ADDI r2, r2, 0x20 //例えばr2のデータ処理(加算など)
 SD r2, 0x0(r3) //レジスタr3が指すアドレスにr2のデータをストア
 LD r10, 0x0(r11) //レジスタr11が指すアドレスからデータをr10にロード
 ADDI r10, r10, 0x20 //例えばr10のデータ処理(加算など)

マイコンからメモリ(RAM)に出力されるリード/ライト・リクエストは、データキャッシュがミスヒットした順だから、0x0(r3)、0x0(r11)の順で、データキャッシュのリプレース(データキャッシュからRAMへライトバックや、RAMからデータキャッシュへのデータ送信)が発生します。

アウトオブオーダー実行のマイコンのデータキャッシュは、ノン・ブロッキング機能のデータキャッシュであることが多いです。このノン・ブロッキング機能のデータキャッシュとは、データキャッシュのラインに希望するデータがあれば(ラインがヒット状態)、他のデータキャッシュのラインのリプレース処理を待たずに後続の処理を実行できます。

つまり、上記の命令順を下記のように変更すれば(ストア命令よりもロード命令を前に配置すれば)、0x0(r11)、0x0(r3)の順に、データキャッシュのリプレースが発生し、0x0(r11)のキャッシュラインのリプレースが完了次第、「SD r2, 0x0(r3)」の処理を待たずに「ADDI r10, r10, 0x20」を実行できる。

 ADDI r2, r2, 0x20 //例えばr2のデータ処理(加算など)
 LD r10, 0x0(r11) //レジスタr11が指すアドレスからデータをr10にロード
 SD r2, 0x0(r3) //レジスタr3が指すアドレスにr2のデータをストア
 ADDI r10, r10, 0x20 //例えばr10のデータ処理(加算など)

この記事が気に入ったらサポートをしてみませんか?