ブロックのインライン化を作ってみました
nbodyを速くしたいなと思い、ブロックをインライン化できるようにしてみました。
yarv2llvmではブロックは別関数にコンパイルし、yieldのタイミングで、呼び出しもとのローカル変数のフレームへのポインタを引数に渡して関数呼び出しをするようにしています。
例えば、
for i in 0 ... nbodies b = bodies[i] e += 0.5 * b.mass * (b.vx * b.vx + b.vy * b.vy + b.vz * b.vz) end
なんていうプログラムは、
b = bodies[i]
e += 0.5 * b.mass * (b.vx * b.vx + b.vy * b.vy + b.vz * b.vz)||<
の部分が別関数としてコンパイルされます。
また、forはYARVのレベルではRangeオブジェクトのeachメソッドに変換されます。Rangeオブジェクトのeachオブジェクトはインライン展開するようにしています。このようにすると、別関数としてコンパイルされたブロックもインライン展開できます。そうすると、関数呼び出しのcall/returnその他もろもろの処理が削減されるはずです。
うまく動いたので、実行時間を計ってみました。bm_so_nbody N=20_000_000です。
インライン化あり
-0.169075163828524 -0.169031664551191 real 5m10.868s user 5m9.295s sys 0m0.654s
インライン化無し
-0.169075163828524 -0.169031664551191 real 5m9.798s user 5m8.185s sys 0m0.467s
かえって遅くなりました 涙)。ブロックのインライン展開はオプションで有効・無効を設定できて、デフォルトで無効にしています。