gpt4 book ai didi

c++ - GCC 根据数组索引值生成不同的代码

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:45:30 26 4
gpt4 key购买 nike

此代码( ARM ):

void blinkRed(void)
{
for(;;)
{
bb[0x0008646B] ^= 1;
sys.Delay_ms(14);
}
}

...编译为以下 asm 代码:​​

08000470:   ldr r4, [pc, #20]       ; (0x8000488 <blinkRed()+24>) // r4 = 0x422191ac
08000472: ldr r6, [pc, #24] ; (0x800048c <blinkRed()+28>)
08000474: movs r5, #14
08000476: ldr r3, [r4, #0]
08000478: eor.w r3, r3, #1
0800047c: str r3, [r4, #0]
0800047e: mov r0, r6
08000480: mov r1, r5
08000482: bl 0x80001ac <CSTM32F100C6::Delay_ms(unsigned int)>
08000486: b.n 0x8000476 <blinkRed()+6>

没关系。

但是,如果我只是更改数组索引 (-0x400)...

void blinkRed(void)
{
for(;;)
{
bb[0x0008606B] ^= 1;
sys.Delay_ms(14);
}
}

...我没有那么优化的代码:

08000470:   ldr r4, [pc, #24]       ; (0x800048c <blinkRed()+28>) // r4 = 0x42218000
08000472: ldr r6, [pc, #28] ; (0x8000490 <blinkRed()+32>)
08000474: movs r5, #14
08000476: ldr.w r3, [r4, #428] ; 0x1ac
0800047a: eor.w r3, r3, #1
0800047e: str.w r3, [r4, #428] ; 0x1ac
08000482: mov r0, r6
08000484: mov r1, r5
08000486: bl 0x80001ac <CSTM32F100C6::Delay_ms(unsigned int)>
0800048a: b.n 0x8000476 <blinkRed()+6>

不同之处在于,在第一种情况下,r4 会立即加载目标地址 (0x422191ac),然后使用 2 字节指令执行对内存的访问,但在第二种情况 r4 加载了一些中间值地址 (0x42218000),然后使用 4 字节指令执行内存访问,偏移量 (+0x1ac) 到目标地址 (0x422181ac)。

为什么编译器会这样做?

我使用:arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -g2 -Wall -O1 -std=gnu++14 -fno-exceptions -fno-use-cxa-atexit -fstrict-volatile-bitfields - c -DSTM32F100C6T6B -DSTM32F10X_LD_VL

bb 是:

__attribute__ ((section(".bitband"))) volatile u32 bb[0x00800000];

.ld中定义为:在 MEMORY 部分:

BITBAND(rwx): ORIGIN = 0x42000000, LENGTH = 0x02000000

SECTIONS 部分:

.bitband (NOLOAD) :
SUBALIGN(0x02000000)
{
KEEP(*(.bitband))
} > BITBAND

最佳答案

我会认为它是 -O1 的人工制品/缺失的优化机会。

如果我们查看使用-O-生成的加载bb[...]的代码,可以更详细地理解:

第一种情况:

movw    r2, #:lower16:bb
movt r2, #:upper16:bb
movw r3, #37292
movt r3, 33
adds r3, r2, r3
ldr r3, [r3, #0]

第二种情况:

movw    r3, #:lower16:bb
movt r3, #:upper16:bb
add r3, r3, #2195456 ; 0x218000 = 4*0x86000
add r3, r3, #428
ldr r3, [r3, #0]

第二种情况的代码更好,可以这样做,因为常量可以用两条加法指令相加(如果索引为 0x0008646B 则不是这种情况)。

-O1 只进行不耗时的优化。所以很明显,它很早就合并了 add 和 ldr,所以它稍后错过了用一台 pc 相对 ldr 加载整个地址的机会。

使用 -O2(或 -fgcse)编译,代码看起来像预期的那样。

关于c++ - GCC 根据数组索引值生成不同的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30151625/

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