Closed4

[C#]アセンブリコードを見てみよう

Tremendous1192Tremendous1192

はじめに

以前の記事で、Span<T>構造体を用いて行列積の高速化を図ったところ逆に遅くなりました。この結果についてアドバイスを頂きまして、Span<T>構造体の強みを殺すコードになっていたようです。
強みを理解するためにはアセンブリコードを見るのが一番ということで、教えていただいたサイトでアセンブリコードを見てみようと思います。

Tremendous1192Tremendous1192

コードの見比べ

初期状態

まずは、何も記入していない状態のコードを見てみます。

using System;
public class MyClass {
    public static void Main(string[] args) {
    }
}

下記がアセンブリコードとのこと。

(゚д゚ )

( ゚д゚)

( ゚д゚ )なんじゃこりゃ

; Core CLR 7.0.22.51805 on x86

MyClass..ctor()
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: push eax
    L0005: mov [ebp-8], ecx
    L0008: cmp dword ptr [0x207fc19c], 0
    L000f: je short L0016
    L0011: call 0x71ef8db0
    L0016: mov ecx, [ebp-8]
    L0019: call dword ptr [0x6641030]
    L001f: nop
    L0020: nop
    L0021: pop ecx
    L0022: pop edi
    L0023: pop ebp
    L0024: ret

MyClass.Main(System.String[])
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: push eax
    L0005: mov [ebp-8], ecx
    L0008: cmp dword ptr [0x207fc19c], 0
    L000f: je short L0016
    L0011: call 0x71ef8db0
    L0016: nop
    L0017: nop
    L0018: pop ecx
    L0019: pop edi
    L001a: pop ebp
    L001b: ret

Microsoft.CodeAnalysis.EmbeddedAttribute..ctor()
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: push eax
    L0005: mov [ebp-8], ecx
    L0008: cmp dword ptr [0x207fc19c], 0
    L000f: je short L0016
    L0011: call 0x71ef8db0
    L0016: mov ecx, [ebp-8]
    L0019: call dword ptr [0xa07f6f0]
    L001f: nop
    L0020: nop
    L0021: pop ecx
    L0022: pop edi
    L0023: pop ebp
    L0024: ret

System.Runtime.CompilerServices.NullableAttribute..ctor(Byte)
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: sub esp, 0x10
    L0007: xor eax, eax
    L0009: mov [ebp-0x10], eax
    L000c: mov [ebp-0x14], eax
    L000f: mov [ebp-8], ecx
    L0012: mov [ebp-0xc], edx
    L0015: cmp dword ptr [0x207fc19c], 0
    L001c: je short L0023
    L001e: call 0x71ef8db0
    L0023: mov ecx, [ebp-8]
    L0026: call dword ptr [0xa07f6f0]
    L002c: nop
    L002d: mov ecx, [ebp-8]
    L0030: mov [ebp-0x10], ecx
    L0033: mov ecx, 0x6f9ca3c
    L0038: mov edx, 1
    L003d: call 0x0582319c
    L0042: mov [ebp-0x14], eax
    L0045: mov edx, [ebp-0x14]
    L0048: xor eax, eax
    L004a: cmp eax, [edx+4]
    L004d: jb short L0054
    L004f: call 0x71efa060
    L0054: lea edx, [edx+eax+8]
    L0058: mov eax, [ebp-0xc]
    L005b: mov [edx], al
    L005d: mov edx, [ebp-0x10]
    L0060: lea edx, [edx+4]
    L0063: mov eax, [ebp-0x14]
    L0066: call 0x057d0008
    L006b: nop
    L006c: lea esp, [ebp-4]
    L006f: pop edi
    L0070: pop ebp
    L0071: ret

System.Runtime.CompilerServices.NullableAttribute..ctor(Byte[])
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: sub esp, 8
    L0007: mov [ebp-8], ecx
    L000a: mov [ebp-0xc], edx
    L000d: cmp dword ptr [0x207fc19c], 0
    L0014: je short L001b
    L0016: call 0x71ef8db0
    L001b: mov ecx, [ebp-8]
    L001e: call dword ptr [0xa07f6f0]
    L0024: nop
    L0025: mov edx, [ebp-8]
    L0028: lea edx, [edx+4]
    L002b: mov eax, [ebp-0xc]
    L002e: call 0x057d0008
    L0033: nop
    L0034: lea esp, [ebp-4]
    L0037: pop edi
    L0038: pop ebp
    L0039: ret

System.Runtime.CompilerServices.NullableContextAttribute..ctor(Byte)
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: sub esp, 8
    L0007: mov [ebp-8], ecx
    L000a: mov [ebp-0xc], edx
    L000d: cmp dword ptr [0x207fc19c], 0
    L0014: je short L001b
    L0016: call 0x71ef8db0
    L001b: mov ecx, [ebp-8]
    L001e: call dword ptr [0xa07f6f0]
    L0024: nop
    L0025: mov eax, [ebp-8]
    L0028: mov edx, [ebp-0xc]
    L002b: mov [eax+4], dl
    L002e: nop
    L002f: lea esp, [ebp-4]
    L0032: pop edi
    L0033: pop ebp
    L0034: ret

System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32)
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: sub esp, 8
    L0007: mov [ebp-8], ecx
    L000a: mov [ebp-0xc], edx
    L000d: cmp dword ptr [0x207fc19c], 0
    L0014: je short L001b
    L0016: call 0x71ef8db0
    L001b: mov ecx, [ebp-8]
    L001e: call dword ptr [0xa07f6f0]
    L0024: nop
    L0025: mov eax, [ebp-8]
    L0028: mov edx, [ebp-0xc]
    L002b: mov [eax+4], edx
    L002e: nop
    L002f: lea esp, [ebp-4]
    L0032: pop edi
    L0033: pop ebp
    L0034: ret
Tremendous1192Tremendous1192

Main関数だけ切り出しました。

視線が散ってしまうのは良くないので、Main関数に着目してみます。

MyClass.Main(System.String[])
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: push eax
    L0005: mov [ebp-8], ecx
    L0008: cmp dword ptr [0x207fc19c], 0
    L000f: je short L0016
    L0011: call 0x71ef8db0
    L0016: nop
    L0017: nop
    L0018: pop ecx
    L0019: pop edi
    L001a: pop ebp
    L001b: ret
Tremendous1192Tremendous1192

配列の宣言

Span<T>につなげたいので、ジャグ配列を宣言しました。1行追加しただけなのにアセンブリのコードは1.5倍になりました。コンパイラがすごい仕事しているんですね。
とりあえず25行目(?)の0x72が配列の要素数を16進数にしたものであることはわかりました。今は、これ以上は分からないですね。

    L0025: mov edx, 0x72
using System;
public class MyClass {
    public static void Main(string[] args) {
        double[][] jagArray=new double[114][];
    }
}
MyClass.Main(System.String[])
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: sub esp, 0xc
    L0006: xor eax, eax
    L0008: mov [ebp-8], eax
    L000b: mov [ebp-0xc], eax
    L000e: mov [ebp-4], ecx
    L0011: cmp dword ptr [0x205ec19c], 0
    L0018: je short L001f
    L001a: call 0x71ef8db0
    L001f: nop
    L0020: mov ecx, 0x1f18feb0
    L0025: mov edx, 0x72
    L002a: call 0x0582313c
    L002f: mov [ebp-0xc], eax
    L0032: mov eax, [ebp-0xc]
    L0035: mov [ebp-8], eax
    L0038: nop
    L0039: mov esp, ebp
    L003b: pop ebp
    L003c: ret
このスクラップは2023/06/29にクローズされました