Closed4
[C#]アセンブリコードを見てみよう
はじめに
以前の記事で、Span<T>
構造体を用いて行列積の高速化を図ったところ逆に遅くなりました。この結果についてアドバイスを頂きまして、Span<T>
構造体の強みを殺すコードになっていたようです。
強みを理解するためにはアセンブリコードを見るのが一番ということで、教えていただいたサイトでアセンブリコードを見てみようと思います。
コードの見比べ
初期状態
まずは、何も記入していない状態のコードを見てみます。
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
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
配列の宣言
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にクローズされました