为什么使用这个简单的代码生成了如此多的LDR和STR指令?

时间:2016-06-15 21:53:07

标签: gcc assembly arm compiler-optimization cortex-m

我有一个简单的C程序:

noexcept

我使用以下编译标志:

int main(){    
    unsigned int counter = 0;
    ++counter;
    ++counter;
    ++counter;
    return 0;
}

(为简洁起见,删除了一些-I指令)

请注意,我故意使用arm-none-eabi-gcc -c -mcpu=cortex-m4 -march=armv7e-m -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -DPART_TM4C123GH6PM -O0 -ffunction-sections -fdata-sections -g -gdwarf-3 -gstrict-dwarf -Wall -MD -std=c99 -c -MMD -MP -MF"main.d" -MT"main.o" -o"main.o" "../main.c" 来禁用优化,因为我有兴趣了解编译器要优化的内容。

这将编译为ARM Cortex-M4的以下程序集:

-O0

为什么生成了这么多6 unsigned int counter = 0; 00000396: 2300 movs r3, #0 00000398: 607B str r3, [r7, #4] 7 ++counter; 0000039a: 687B ldr r3, [r7, #4] 0000039c: 3301 adds r3, #1 0000039e: 607B str r3, [r7, #4] 8 ++counter; 000003a0: 687B ldr r3, [r7, #4] 000003a2: 3301 adds r3, #1 000003a4: 607B str r3, [r7, #4] 9 ++counter; 000003a6: 687B ldr r3, [r7, #4] 000003a8: 3301 adds r3, #1 000003aa: 607B str r3, [r7, #4] ldr r3, [r7, #4]条指令?为什么str r3, [r7, #4]甚至需要参与,我们不能只使用r7

2 个答案:

答案 0 :(得分:6)

没有优化(这显然是这样),所有编译器都必须做的是发出指令,这些指令会导致更高级语言定义的行为。完全孤立地对每一个陈述进行天真的对待是自由的,而这正是它在这里所做的事情;从编译器的角度来看:

  • 一个变量声明:那么,我需要一个地方来存储它,我可以通过创建一个堆栈帧(未显示,但r7在这里被用作帧指针)。
  • 新陈述:counter = 0; - 好的,我记得counter的存储位于本地堆栈框架中,因此我只选择一个临时寄存器,生成值0并将其存储在地点,工作完成。
  • 新陈述:++counter; - 就在那时,我记得counter的存储位于本地堆栈帧中,所以我选择了一个临时寄存器,用变量的值加载,增量它,然后通过存储结果更新变量的值。返回值未使用,请忘掉它。完成工作。
  • 新陈述:++counter; - 就在那时,我记得counter的存储位于本地堆栈帧中,所以我选择了一个临时寄存器,用变量的值加载,增量它,然后通过存储结果更新变量的值。返回值未使用,请忘掉它。任务完成。由于我是一个软件,我甚至无法理解Déjàvu的人类概念,更不用说体验它了。
  • 新陈述:++counter; - 就在那时......

等等。每个声明,完美地编译成精确正确的机器指令。 正是你要我做的。如果你想让我在更高层次上推断代码,并且如果我可以利用这些陈述之间的关系,你应该说些什么......

答案 1 :(得分:0)

如果计数器变量未声明为volatile,并且如果您设置了大小优化(-Os参数),则gcc将使用以下代码优化该代码 movs rn,#3 str rn,[可变地址]