Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么.NET本机编译循环顺序相反?_C#_Assembly_X86_Micro Optimization_.net Native - Fatal编程技术网

C# 为什么.NET本机编译循环顺序相反?

C# 为什么.NET本机编译循环顺序相反?,c#,assembly,x86,micro-optimization,.net-native,C#,Assembly,X86,Micro Optimization,.net Native,我正在研究由.NET本机编译器执行的优化技术。 我创建了一个示例循环: for (int i = 0; i < 100; i++) { Function(); } 只是比举例来说要快 LOOP: inc esi cmp esi, 064h jl LOOP 但这真的是因为这一点吗?速度差异真的很显著吗。此外,add会影响零标志,因此无需使用另一条cmp指令。直接跳 这是一种著名的 反转:循环反转反转将值分配给索引变量

我正在研究由.NET本机编译器执行的优化技术。 我创建了一个示例循环:

        for (int i = 0; i < 100; i++)
        {
            Function();
        }
只是比举例来说要快

LOOP:
inc esi
cmp esi, 064h
jl LOOP
但这真的是因为这一点吗?速度差异真的很显著吗。此外,
add
会影响零标志,因此无需使用另一条
cmp
指令。直接跳

这是一种著名的

反转:循环反转反转将值分配给索引变量的顺序。这是一个微妙的优化,可以帮助消除依赖关系,从而实现其他优化。此外,某些体系结构在汇编语言级别使用循环结构,循环结构只在一个方向上计数(例如,如果不是零,则递减跳跃(DJNZ))


您可以看到其他编译器的结果。

您的结论是正确的:反向循环将以
0
为目标(当寄存器值达到
0
时,循环将结束),因此
Add
将设置条件分支中使用的零标志

这样,您就不需要专门的
Cmp
,这将导致:1)大小优化2)速度更快(从编译器程序员的决策和其他决策中得出结论)


这是编写循环目标
0
的非常常见的汇编技巧。我很惊讶您理解汇编程序,但不知道(询问)它。

使用立即值添加比INC快,而且您还跳过了CMP…所有这些都在3行代码中。然后是的,差异真的很显著(在大小和速度上)。想象一下,在一个真实世界的程序中,在大约30000个地方这样做……是的,速度更快,而且一般来说,优化器会在不改变程序语义的情况下应用任何可以使代码更快的优化。是的,因为您甚至不需要比较。正如您所看到的:)您已经用两种方式编写了代码。如果您想知道一种方法是否比另一种方法快,请运行它们。@EricLippert我并不懒惰,我也很乐意,但我现在在工作电脑上,没有任何工具可以运行或基准汇编代码:(我也没有管理员权限安装任何东西。
inc
add
慢一个时钟周期。在中比较它们。向下滚动到附录C,您可以看到每个x86/x64指令的延迟和吞吐量时间。1个时钟周期似乎不重要,但如果有数百或数千个循环,它将我加起来很快。@Icemani发现这些数字并没有反映他们所描述的微体系结构的真实情况(IvyBridge通过Skylake;见附录中前面的表格).A
dec/jnz
循环可以每周期运行1次迭代,并且作为其他dep链的一部分,
inc/dec
整数寄存器只有1个周期延迟。Intel可能通过Broadwell在IvyBridge上获得了2个周期延迟(但不是Skylake)从查看延迟到读取EFLAGS,可能包括需要标志合并的CF。但这对于dec/jnz来说不是问题,即使没有融合,或者
dec/setz
。我只有一个Skylake,所以无法测试:/@Icemanind:还要注意,这些都是延迟数;您参考的表中仍然列出了
0.25的inc/dec吞吐量周期,即每时钟4个周期。无论如何,Agner Fog的指令表基于实验测试,列出了1c延迟/0.25c吞吐量下的inc/dec。uops.info甚至测量了从输入到整数输出和到标志输出的延迟,在这两种情况下都发现了1个周期:。(不包括CF非输出)@Icemanind:只有当代码可能在Silvermont或Pentium 4上运行时,此处避免使用
dec
才有用。否则,对于主流Intel和AMD来说,这是对代码大小的浪费。
LOOP:
inc esi
cmp esi, 064h
jl LOOP