Mono.Simdの実装に関して

この前書いた「.NET上でMono.Simd使ってみたいなぁ」っていうつぶやき
http://d.hatena.ne.jp/kaminarioyaji/20081202/1228210788

に対して、atsushieno様からトラックバックで、Mono.Simdの実装に関して詳しい説明を頂きました(一介の学生相手に時間を割いて頂きありがとうございます)。

『Mono.Simd on .NET does not make sense』
http://d.hatena.ne.jp/atsushieno/20081210/p1

タイトルの通り、現状、Mono.Simdを.NET上で使っても有効に機能しないようです(詳しい説明はatsushieno様の日記に書かれています)。今現在、直接SSEを使って計算したい場合はC/C++とかでコード書いて、それをライブラリにして呼び出すのが手っ取り早いってことかなと、、、自分には出来ませんが…。JITに手を加えるという話は、、、これまた無理です*1。アドバイス頂いたのにすみません。。。

まぁ、そんなこんなで、今回惜しげもなく思慮の浅さを晒してしまいご迷惑をおかけしたわけですが、上記内容を踏まえた上で、勉強を兼ねて、という名目のもと、単なる好奇心でMono.Simdのコードを眺めてみました(ごめんなさい、懲りてません…)。なお、C#SIMD命令を使いたい!という当初の目的は完全に投げ捨てていることをここに宣言しておきます。

と、その前に、Mono.Simdのdocumentを見たら
http://go-mono.com/docs/index.aspx?tlink=0@N%3aMono.Simd

Code that uses the types defined in the Mono.Simd assembly will work even on systems that do not have hardware SIMD operations, systems where Mono has not added support for the native SIMD operations and even on the Microsoft.NET runtime as it currently does not have support for hardware accelerated SIMD operations.

「Mono.Simdのコードは.NET上でも動くけどSSEは使われんよ」って思いっきり書かれてた…orz

気を取りなおして。SourceForgeから、Mono.Simdのtarボール取ってきてSimdRuntime.csとか読んでみたら、
http://anonsvn.mono-project.com/viewvc/trunk/mcs/class/Mono.Simd/

[Acceleration (AccelMode.SSE1)]
[CLSCompliant(false)]

っていう、.NET上じゃ機能しないよって雰囲気を漂わせた属性が…(AccelMode.*は列挙子)*2。とはいえ、これらのコード見てもこれ以上のことは分からなかったので、もう一歩踏み込んで、atsushieno様が書かれていた

Mono.Simdをmonoランタイム (mono/mono/metadata) が解釈し、CILメタデータJIT (mono/mono/mini) に渡す

に該当するコードを、SourceForgeから(以下略)
http://anonsvn.mono-project.com/viewvc/trunk/mono/mono/metadata/

で、流し見たけど、どういう流れになってるのかさっぱりわからなかった。mono-config.cあたりで、アーキテクチャの判別をしてるような、してないような。というわけで、次。

miniは(simd最適化が有効になっていたら)そのCILがMono.Simdのものでないかどうかチェックして、SIMDサポートのコードであれば、それを単なるx86命令ではなくSIMD命令として出力する

という部分に該当すると思われるコード(simd-instrisics.c)を含むtarボー(もういいや以下略)
http://anonsvn.mono-project.com/viewvc/trunk/mono/mono/mini/

案の定どうなってるのか、よくわからなかったのですが…。とりあえず、mini JITのMono.Simdコード解釈?部分(simd-instrisics.c)は、

  • monoランタイムが吐き出すアーキテクチャ情報に基づき、x86アーキテクチャであれば、mini-x86.c(line:750)のmono_arch_cpu_enumerate_simd_versions()関数*3でSSEのサポート情報を入手
  • CPUが対応してる命令については、Mono.SimdのコードをSSE命令で書き下してる(ってわけで、対応してなければ、Mono.Simdのコードはただのx86命令で出力される)

って感じなのかなぁ。

とりあえず、ここまで、ざーっと見た感想として、現状の実装はMono.SimdというよりMono.SSEって雰囲気かなぁと(x86アーキテクチャ以外ではmono_arch_cpu_enumerate_simd_versionsに相当する関数自体実装されてないっぽいし、atsushieno様が最後に暗に言及されているように、SIMD命令はSSE以外は使われてないっぽい)。あと、これってC/C++コンパイラでいうところのintrinsics関数の実装そのものじゃないのかなぁと妄想。

全然どうでもいいけど、(x86命令で実行するとして).NETでも動くのかどうかを左右する部分がどこにあるのか分からなかった。Acceleration属性定義してる部分かなぁ。まぁ、動いた所で意味はないし、単にMono.Simdのdocumentの一文が気になっただけなのでこれは放置。

と、まぁそんなことより何より、changelogを眺めてみて気付いたのですが、Mono.Simdってnovell社の方がほとんど一人で実装されたんだなぁと。この方が、atsushieno様のおっしゃられているRuntimeハッカーの方だと思うのですが、かっこいいなぁ。ソースコード中に、ToDoやSIMD命令の扱い方に関するTipsを書いてる辺りもなんかプロっぽいなぁとか。まぁ勝手な思い込みなのですが。

*1:C/C++が書けない&あえて学ぶモチベーションもわかないため

*2:いや、あくまで雰囲気が、ってだけです。

*3:CPUID命令を発行実行してレジスタをチェックしてるっぽい