gpt4 book ai didi

gcc - LLVM 中的内联 NOP 未优化

转载 作者:行者123 更新时间:2023-12-02 05:17:19 24 4
gpt4 key购买 nike

我正在研究 this overview 中的示例使用 GCC 编译内联 ARM 汇编的过程。我使用的是 llvm-gcc 4.2.1,而不是 GCC,并且正在编译以下 C 代码:

#include <stdio.h>
int main(void) {
printf("Volatile NOP\n");
asm volatile("mov r0, r0");
printf("Non-volatile NOP\n");
asm("mov r0, r0");
return 0;
}

使用以下命令:

llvm-gcc -emit-llvm -c -o compiled.bc input.c
llc -O3 -march=arm -o output.s compiled.bc

我的output.s ARM ASM 文件如下所示:

    .syntax unified
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.file "compiled.bc"
.text
.globl main
.align 2
.type main,%function
main: @ @main
@ BB#0: @ %entry
str lr, [sp, #-4]!
sub sp, sp, #16
str r0, [sp, #12]
ldr r0, .LCPI0_0
str r1, [sp, #8]
bl puts
@APP
mov r0, r0
@NO_APP
ldr r0, .LCPI0_1
bl puts
@APP
mov r0, r0
@NO_APP
mov r0, #0
str r0, [sp, #4]
str r0, [sp]
ldr r0, [sp, #4]
add sp, sp, #16
ldr lr, [sp], #4
bx lr
@ BB#1:
.align 2
.LCPI0_0:
.long .L.str

.align 2
.LCPI0_1:
.long .L.str1

.Ltmp0:
.size main, .Ltmp0-main

.type .L.str,%object @ @.str
.section .rodata.str1.1,"aMS",%progbits,1
.L.str:
.asciz "Volatile NOP"
.size .L.str, 13

.type .L.str1,%object @ @.str1
.section .rodata.str1.16,"aMS",%progbits,1
.align 4
.L.str1:
.asciz "Non-volatile NOP"
.size .L.str1, 17

这两个 NOP 位于各自的 @APP/@NO_APP 对之间。我的期望是,由于 -O3 标志,不带 volatile 关键字的 asm() 语句将被优化而不存在,但显然两个内联汇编语句都保留下来。

为什么 asm("mov r0, r0") 行无法被识别并作为 NOP 删除?

最佳答案

MysticalMārtiņš Možeiko描述了编译器没有优化代码;即,更改说明。编译器所做的优化是指令的调度时间。当您使用 volatile 时,编译器将不会重新调度。在您的示例中,重新调度将在printf之前或之后移动。

编译器可能进行的另一个优化是获取C值来为您注册。寄存器分配对于优化非常重要。。这不会优化汇编器,但允许编译器对函数内的其他代码执行合理的操作。

要查看 volatile 的效果,这里是一些示例代码,

int example(int test, int add)
{
int v1=5, v2=0;
int i=0;
if(test) {
asm volatile("add %0, %1, #7" : "=r" (v2) : "r" (v2));
i+= add * v1;
i+= v2;
} else {
asm ("add %0, %1, #7" : "=r" (v2) : "r" (v2));
i+= add * v1;
i+= v2;
}
return i;
}

除了 volatile 之外,这两个分支具有相同的代码。 gcc 4.7.2 为 ARM926 生成以下代码,

example:
cmp r0, #0
bne 1f /* branch if test set? */
add r1, r1, r1, lsl #2
add r0, r0, #7 /* add seven delayed */
add r0, r0, r1
bx lr
1: mov r0, #0 /* test set */
add r0, r0, #7 /* add seven immediate */
add r1, r1, r1, lsl #2
add r0, r0, r1
bx lr

注意:汇编器分支与“C”代码相反。由于管道的原因,第二个分支在某些处理器上速度较慢。编译器更喜欢这样

   add  r1, r1, r1, lsl #2
add r0, r0, r1

不按顺序执行。

Ethernut ARM Tutorial是一个极好的资源。然而,优化这个词有点过重了。编译器不会分析汇编程序,只会分析参数以及发出代码的位置。

关于gcc - LLVM 中的内联 NOP 未优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13675629/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com