【C#】CILの算術演算命令

このエントリーをはてなブックマークに追加

C#をコンパイルするとCILになりますが、CILの情報は結構少ないので、メモがてらに書いておきます。

基本

たとえば1 + 10とするC#コードがあったとして、これをCILにすると以下のようなものに論理的にはなります。

ldc.i4.1
ldc.i4.s 10
add

逆ポーランド記法とかを知っている人ならどういう変換をされたかわかるかと思います。 C#での+の数値の加算はCILではaddになりますが、このaddはスタックにある2つの値を加算するものになります。 日本語で言うと「1 足す 10」は「1と10を読み込んで、読み込んだ2つの値を足す」になります。 どうしてこのような変換をするかとかは逆ポーランド記法を調べたら利点がわかるかと思いますので割愛。

ちなみに、先ほど「以下のようなものに論理的にはなります」と言いましたが、実際のところは1 + 10ぐらいはコンパイラーが最適化してldc.i4.s 11になってしまうことがあります。

命令一覧

スタック操作

命令動作
nop何もしない
dupスタックのトップを複製
popスタックのトップを破棄

定数読み込み

命令動作
ldc.i4 {value}int32な{value}を読み込む
ldc.i4.s {value}int8な{value}を読み込む
ldc.i4.m1-1を読み込む
ldc.i4.00を読み込む
ldc.i4.11を読み込む
ldc.i4.22を読み込む
ldc.i4.33を読み込む
ldc.i4.44を読み込む
ldc.i4.55を読み込む
ldc.i4.66を読み込む
ldc.i4.77を読み込む
ldc.i4.88を読み込む
ldc.i8 {value}int64な{value}を読み込む
ldc.r4 {value}float32な{value}を読み込む
ldc.r8 {value}float64な{value}を読み込む

ldc.i4.m1~ldc.i4.8は短縮命令です。

算術演算

命令動作
add加算(+)
sub減算(-)
mul乗算(*)
div除算(/)
div.un符号無し整数の除算のときに使われる
rem乗除(%)
rem.un符号無し整数の乗除のときに使われる
neg符号反転(-)

ビット演算

命令動作
and論理積(&)
or論理和(
xor排他的論理和(^)
notビット反転(~)
shl左シフト
shr右シフト
shr.un符号無し右シフト

変換

命令動作
conv.i1int8へ変換
conv.u1uint8へ変換
conv.i2int16へ変換
conv.u2uint16へ変換
conv.i4int32へ変換
conv.u4uint32へ変換
conv.i8int64へ変換
conv.u8uint64へ変換
conv.inative intへ変換
conv.unative uintへ変換
conv.r4float32へ変換
conv.r8float64へ変換
conv.r.unuintをnative floatへ変換

まとめ

数が多すぎて一覧にはポインターやオーバーフローチェックのことは載せきれませんでしたが、単純な算術演算は表を見れば理解できるようになるかと思います。

実際のC#コードでは、これの応用で引数やローカル変数などからの読み込みとかもあるので、もっとややこしくなりますが……