为什么.NET Native 以相反的顺序编译循环?

Why does .NET Native compile loop in reverse order?

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

        for (int i = 0; i < 100; i++)
        {
            Function();
        }

而且我已经用 Native 编译了它。然后我在 IDA 中用机器代码反汇编结果 .dll 文件。结果,我有:

(我去掉了一些不需要的行,所以不用担心地址行不一致)

我理解 add esi, 0FFFFFFFFh 的真正意思是 subtract one from esi and alter Zero Flag if needed,所以如果还没有达到零,我们可以跳到开头。

我不明白的是编译器为什么要反转循环?

我得出的结论是

LOOP:
add esi, 0FFFFFFFFh
jnz LOOP

只是比例如

LOOP:
inc esi
cmp esi, 064h
jl LOOP

但这真的是因为这个吗?速度差异真的很大吗?

inc might be slower than add because of the partial flag update。此外 add 影响零标志,因此您不需要使用另一个 cmp 指令。直接跳转就好了

这是一种著名的类型 loop optimization

reversal: Loop reversal reverses the order in which values are assigned to the index variable. This is a subtle optimization which can help eliminate dependencies and thus enable other optimizations. Also, certain architectures utilize looping constructs at Assembly language level that count in a single direction only (e.g. decrement-jump-if-not-zero (DJNZ)).

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

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

这样您就不需要专用的 Cmp,这导致:1) 大小优化 2) 它也更快(来自编译器程序员的决定和另一个 的结论)。

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