C#+WPFチューニング戦記

C#とWPFで高速なコードと最適なシステムを書くためにやってきたいろいろな事を書いてみます。.NET Frameworkのソースコードを読み解きましょう。なお、ここに書かれているのは個人の見解であって何らかの団体や企業の見解を代表するものではありません。

値型のデフォルトコンストラクタのコスト

C#における struct は引数が無いコンストラクタを書くことができないのですが、

return new Size();

こういうのはコスト0で戻り値に格納してくれるのだろうかという疑問について、調査しました。
極めて厳密に最適化をすると、このコンストラクタはインライン展開可能で、インライン展開後にさらに最適化すれば戻り値を0フィルするだけでいいので、もしかしたらそのくらいまでなら既存のJITがやってくれるのではないか?という仮説があったためです。

結論から言いますと、現時点 .NET Framework 4.6 では32bit/64bitを問わずJITは言語規約にかなり忠実な展開をします。

つまり、スタック上に1回 0フィルした構造体を作成して戻り値に格納すべく値をコピーします。

最速で書こうと思えば、

static readonly Size _zeroSize = new Size();

:
:

return _zeroSize;

のように記述する必要があります。
こうなると、Size.Emptyが -∞ の値を持つサイズなのが恨めしく映ります。Size.Default も欲しかったなと思います。

ちなみにこの場合も最適化は若干弱いもので、転送元のアドレスをレジスタにロードする処理が含まれます。
デフォルトコンストラクタを用いた値を返す場合、戻り値を直接 0 フィルする最適化が欲しいと思います。
インライン展開時はさらに高度に扱って欲しいと思います。

転送命令1~4個分程度ではありますが、この程度をなぜ最適化できなかったのかという思いはどうしても残ります。

一応、シンプルなコードを作成して最適化の有無に無関係にこのコストはあることをアセンブラ上で確認したつもりではあります。
しかし、コードのパターンによって変わる可能性があることは否めません。
別の答えをお持ちの方がいらっしゃいましたら是非お知らせください。

なお、 new を書かないでも良いものは最適なコードになっています。リテラル値なら良いということなのでしょう。

余談ですが、 default(Size) は new Size() の糖衣構文なので、まったく同じ命令を出力します。