[英]Mono csharp AOT Optimizations
我開始學習 C#,來自 C++ 背景。 我想了解 C# 內存模型並將其與 C++ 的內存模型進行比較。 在這樣做時,我找到了文章The C# Memory Model in Theory and in Practice 。 到目前為止,沒有什么是令人驚訝的,但我試圖重現文章中的編譯器優化,該優化刪除了額外的內存讀取並遇到了問題。 我使用的是單聲道 csharp 編譯器,無法重現優化。 這是 C# 代碼:
// test.cs
class MainApp {
static void Main() {
Foo foo = new Foo();
foo.bar();
}
}
class Foo {
private int _A = 0, _B = 1;
public bool bar() {
if (_B == -1) throw new Exception();
int a = _A;
int b = _B;
return a > b;
}
}
然后我運行以下編譯命令:
mcs -optimize+ test.cs
mono --aot -O=all test.exe
當我檢查objdump -d test.exe.so
的輸出時,我看到以下(相關的)匯編行:
0000000000000500 <Foo_bar>:
500: 48 83 ec 08 sub $0x8,%rsp
504: 48 89 3c 24 mov %rdi,(%rsp)
508: 48 8b c7 mov %rdi,%rax
50b: 48 63 40 14 movslq 0x14(%rax),%rax
50f: 83 f8 ff cmp $0xffffffff,%eax
512: 74 1b je 52f <Foo_bar+0x2f>
514: 48 8b 0c 24 mov (%rsp),%rcx
518: 48 63 41 10 movslq 0x10(%rcx),%rax
51c: 48 63 49 14 movslq 0x14(%rcx),%rcx
520: 3b c1 cmp %ecx,%eax
522: 40 0f 9f c0 setg %al
526: 48 0f b6 c0 movzbq %al,%rax
52a: 48 83 c4 08 add $0x8,%rsp
52e: c3 retq
... # exception stuff
因此,指令50b
、 518
和51c
似乎表明讀取仍在重復發生,即使它可以被優化掉。 我的問題是,我做錯了什么,這是一個錯過的優化機會,還是這里有其他一些問題(為什么這個優化不會發生的一些很好的理由)? 我現在無法訪問 Visual Studio,我很想知道它是否真的進行了這種優化。
這篇文章聲稱我應該得到類似的東西:
push eax
mov edx,dword ptr [ecx+8]
cmp edx,0FFFFFFFFh
je 00000016
mov eax,dword ptr [ecx+4]
cmp eax,edx
我決定檢查 C++ 的情況是否有所不同,並對我的發現感到有點驚訝。 以下代碼:
class Foo {
int _A{0};
int _B{1};
public:
__attribute__ ((noinline)) bool bar() volatile {
if (_B == -1) throw 0;
int a = _A;
int b = _B;
return a > b;
}
};
int main(int argc, char **argv) {
volatile Foo foo;
foo.bar();
}
導致以下(相關)程序集:
00000000000007e4 <_ZNV3Foo3barEv>:
7e4: 8b 47 04 mov 0x4(%rdi),%eax
7e7: 83 f8 ff cmp $0xffffffff,%eax
7ea: 74 0b je 7f7 <_ZNV3Foo3barEv+0x13>
7ec: 8b 17 mov (%rdi),%edx
7ee: 8b 47 04 mov 0x4(%rdi),%eax
7f1: 39 c2 cmp %eax,%edx
7f3: 0f 9f c0 setg %al
7f6: c3 retq
... # exception stuff
所以優化也不會在這里發生(盡管公平地說,如果沒有((noinline))
這段代碼甚至不會出現在目標文件中。)這是來自clang
的相同:
0000000000400610 <_ZNV3Foo3barEv>:
400610: 50 push %rax
400611: 8b 47 04 mov 0x4(%rdi),%eax
400614: 83 f8 ff cmp $0xffffffff,%eax
400617: 74 0a je 400623 <_ZNV3Foo3barEv+0x13>
400619: 8b 07 mov (%rdi),%eax
40061b: 3b 47 04 cmp 0x4(%rdi),%eax
40061e: 0f 9f c0 setg %al
400621: 59 pop %rcx
400622: c3 retq
... # exception stuff
所以還有一個額外的閱讀,只是在cmp
指令中“內聯”。
相關--version
Mono C# compiler version 4.6.2.0
g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
我把你的代碼扔到了SharpLab ,得到了:
L0000: push rsi
L0001: sub rsp, 0x20
L0005: mov eax, [rcx+0xc]
L0008: cmp eax, 0xffffffff
L000b: jz L001e
L000d: mov ecx, [rcx+0x8]
L0010: cmp ecx, eax
L0012: setg al
L0015: movzx eax, al
L0018: add rsp, 0x20
L001c: pop rsi
L001d: ret
L001e: mov rcx, 0x7ffa2f8d4170
L0028: call 0x7ffa8f384690
L002d: mov rsi, rax
L0030: mov rcx, rsi
L0033: call System.Exception..ctor()
L0038: mov rcx, rsi
L003b: call 0x7ffa8f33a4f0
L0040: int3
我的程序集比你的更生疏,但我只能看到每個字段被訪問一次?
請注意,.NET Core JIT 是 2 層,而 SharpLab 僅顯示第一層,因此如果事實證明它處於熱門路徑上,則可能會進一步優化。
因此這看起來像 Mono 的東西?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.