使用非常规 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);
你的例子有两个问题:
- 编译器没有优化代码。
- 琐碎
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
我一直在玩编译器资源管理器,试图更多地了解 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);
你的例子有两个问题:
- 编译器没有优化代码。
- 琐碎
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