使用非常规 for 循环的 Asm 更高效?

More efficient Asm with unconventional for-loop?

我一直在玩编译器资源管理器,试图更多地了解 ARM-Assembly。我正在使用 arm64 msvc v19.latest。我注意到我少了一个这样的分支:

int main(){
    for(unsigned i = 0; i<8;)
    i++;
    return 0;
}

与像这样编写 for 循环的“传统”方式相比:

int main(){
    for(unsigned i = 0; i<8;i++)
    ;
    return 0;
}

因此,以非常规方式编写 for 循环是否更有效?我将粘贴两个 asm 进行比较。先用非常规的方法:

        ;Flags[SingleProEpi] functionLength[52] RegF[0] RegI[0] H[0] frameChainReturn[UnChained] frameSize[16]

|main|  PROC
|$LN6|
        sub         sp,sp,#0x10
        mov         w8,#0
        str         w8,[sp]
|$LN2@main|
        ldr         w8,[sp]
        cmp         w8,#8
        bhs         |$LN3@main|
        ldr         w8,[sp]
        add         w8,w8,#1
        str         w8,[sp]
        b           |$LN2@main|
|$LN3@main|
        mov         w0,#0
        add         sp,sp,#0x10
        ret

        ENDP  ; |main|

和常规方式:

     ;Flags[SingleProEpi] functionLength[56] RegF[0] RegI[0] H[0] frameChainReturn[UnChained] frameSize[16]

|main|  PROC
|$LN6|
        sub         sp,sp,#0x10
        mov         w8,#0
        str         w8,[sp]
        b           |$LN4@main|
|$LN2@main|
        ldr         w8,[sp]
        add         w8,w8,#1
        str         w8,[sp]
|$LN4@main|
        ldr         w8,[sp]
        cmp         w8,#8
        bhs         |$LN3@main|
        b           |$LN2@main|
|$LN3@main|
        mov         w0,#0
        add         sp,sp,#0x10
        ret

        ENDP  ; |main|

如果您想要优化代码,请向您的编译器索取!检查未优化代码的优化程度是没有意义的。

-O3 完全消除循环。

Compiler Explorer demo: standard
Compiler Explorer demo: non-standard

如果我们在循环中添加一些有副作用的东西,我们会从这两种方法中得到完全相同的结果。

Compiler Explorer demo: standard
Compiler Explorer demo: non-standard

优化后的代码相当于

printf("%d\n", 1);
printf("%d\n", 2);
printf("%d\n", 3);
printf("%d\n", 4);
printf("%d\n", 5);
printf("%d\n", 6);
printf("%d\n", 7);
printf("%d\n", 8);

你的例子有两个问题:

  1. 编译器没有优化代码。
  2. 琐碎

ad 1. 未优化的代码不适合任何性能或输出汇编比较。

ad 2. 代码的琐碎性使您无法启用优化。您需要添加一些内容以防止编译器删除代码。

我会添加一些内存屏障 (gcc)

void foo(){
    for(unsigned i = 0; i<8;)
    {
        i++;
        asm("":"=r"(i):"m"(i));
    }
}

void bar(){
    for(unsigned i = 0; i<8;i++)
    {
        asm("":"=r"(i):"m"(i));
    }
}

生成的代码完全一样

foo:
        sub     sp, sp, #16
        mov     w0, 0
.L2:
        add     w0, w0, 1
        str     w0, [sp, 12]
        cmp     w0, 7
        bls     .L2
        add     sp, sp, 16
        ret
bar:
        sub     sp, sp, #16
        str     wzr, [sp, 12]
.L7:
        add     w0, w0, 1
        str     w0, [sp, 12]
        cmp     w0, 7
        bls     .L7
        add     sp, sp, 16
        ret

https://godbolt.org/z/zTjnjK