【问题标题】:Mono csharp AOT OptimizationsMono csharp AOT 优化
【发布时间】:2020-02-27 13:54:37
【问题描述】:

我开始学习 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

因此,指令50b51851c 似乎表明读取仍在重复发生,即使它可以被优化。我的问题是,我做错了什么,这是错过了优化机会,还是这里有其他问题(不进行这种优化的一些充分理由)?我现在无法访问 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)

【问题讨论】:

    标签: c# c++ mono compiler-optimization


    【解决方案1】:

    我把你的代码扔到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 的东西?

    【讨论】:

    • 对我来说很合适。我得去看看SharpLab。我希望有更多优化知识的人会来说“好吧,某种架构导致这种优化被推迟”或“这三个编译器都使用算法 X 来检查某事”。
    • 我认为您可能需要 mono 团队中的某个人来解释为什么编译器选择不进行特定优化。 This page 链接到聊天频道,并说您可以在 GitHub 上打开问题并提出问题,所以这些可能是更好的路线
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-04
    • 2010-12-30
    • 1970-01-01
    相关资源
    最近更新 更多