C# Roslyn为什么不优化多个增量?
我试图了解C# Roslyn为什么不优化多个增量?,c#,assembly,x86-64,compiler-optimization,roslyn,C#,Assembly,X86 64,Compiler Optimization,Roslyn,我试图了解Roslyn如何优化以下代码段: 代码 public int F(int n){ ++n; ++n; ++n; ++n; 返回n; } asm C.F(Int32) L0000: inc edx L0002: inc edx L0004: inc edx L0006: inc edx L0008: mov eax, edx L000a: ret 问题: 为什么Roslyn不像MSVC那样提前优化C编译器呢4
Roslyn
如何优化以下代码段:
代码
public int F(int n){
++n;
++n;
++n;
++n;
返回n;
}
asm
C.F(Int32)
L0000: inc edx
L0002: inc edx
L0004: inc edx
L0006: inc edx
L0008: mov eax, edx
L000a: ret
问题:
为什么Roslyn不像MSVC那样提前优化C编译器呢4 xINC
较慢(4个周期的延迟与1个周期的延迟相比,即使假设消除mov,也比吞吐量所需的多4个UOP;)
C
它的“等效物”:
int
f(无效*伪值,整数n){
++n;
++n;
++n;
++n;
返回n;
}
asm来自MSVC,或带有\uuuuu属性((ms\u abi))
的GCC使用与C\asm相同的Windows x64调用约定:
编译器确实进行了优化<代码>n是一个参数,因此无法修改。JIT编译器必须修改参数值的副本 如果该值在递增之前分配给变量,则Roslyn编译器将消除递增。从中,此C#代码: 将被翻译为
public int F(int i)
{
return i + 1 + 1 + 1 + 1;
}
并最终编译成以下汇编代码:
C.F(Int32)
L0000: lea eax, [edx+4]
L0003: ret
“
n
是一个参数,因此不能修改”-但是n
是Int32
,一种值类型。它不是通过-ref
-传递的,CLR抽象堆栈中的参数和局部变量的行为都是相同的,所以我不明白你为什么说“它不能修改”。@Dai是对的。“n是一个参数,所以它不能被修改”没有意义,并且也被OP的反汇编彻底失效(包含参数的寄存器明显递增,只是效率不高)。把它赋给另一个变量不会有什么区别。@Peter,我想你是对的。这就是为什么我称这个版本为“变通方法”。不过,知道至少有一些方法可以做到这一点是很好的。@Hrant:正如在对这个问题的评论中所讨论的(现在不幸地转到聊天),这个答案并不能解释它(所以你应该不接受它)。这不是C#或Windowsx64调用约定的工作方式。(如果int i
是由ref获取的(它不是),那么它的值不会在EDX中传递/返回;它将由指针传递。因此inc-EDX
纯粹是函数的私有部分,比mov+add或LEA更糟糕。)@PeterCordes您完全正确,但我认为这个答案总比没有好。而且我也不明白,当有非常有价值的信息可供阅读时,为什么要改为聊天;这段对话已经结束。
public int F(int i)
{
return i + 1 + 1 + 1 + 1;
}
C.F(Int32)
L0000: lea eax, [edx+4]
L0003: ret