8

为了使 GCC 不会在我每次执行|=or时生成加载-修改-存储操作&=,我定义了以下宏:

#define bset(base, offset, mask) bmanip(set, base, offset, mask)

#define bclr(base, offset, mask) bmanip(clr, base, offset, mask)

#define bmanip(op, base, offset, mask) \
asm("pshx");\
asm("ldx " #base);\
asm("b" #op " " #offset ",x " #mask);\
asm("pulx")

他们工作得很好;反汇编的二进制文件是完美的。

当我按顺序使用多个时,问题就来了:

inline void spi_init()
{
  bset(_io_ports, M6811_DDRD, 0x38);
  bset(_io_ports, M6811_PORTD, 0x20);
  bset(_io_ports, M6811_SPCR, (M6811_SPE | M6811_DWOM | M6811_MSTR));
}

这导致:

00002227 <spi_init>:
    2227:       3c              pshx
    2228:       fe 10 00        ldx     0x1000 <_io_ports>
    222b:       1c 09 38        bset    0x9,x, #0x38
    222e:       38              pulx
    222f:       3c              pshx
    2230:       fe 10 00        ldx     0x1000 <_io_ports>
    2233:       1c 08 20        bset    0x8,x, #0x20
    2236:       38              pulx
    2237:       3c              pshx
    2238:       fe 10 00        ldx     0x1000 <_io_ports>
    223b:       1c 28 70        bset    0x28,x, #0x70
    223e:       38              pulx
    223f:       39              rts

有没有办法让 GCC (3.3.6-m68hc1x-20060122) 自动优化冗余堆栈操作?

4

1 回答 1

10

gcc 将始终发出您告诉它发出的汇编指令。因此,与其显式编写代码来加载具有您想要操作的值的寄存器,不如告诉 gcc 代表您执行此操作。您可以使用寄存器约束来做到这一点。

不幸的是,6811 代码生成器似乎不是 gcc 的标准部分——我没有发现手册中的文档。因此,我无法指出文档中特定于平台的部分。但是您需要阅读的通用位在这里: http: //gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/Extended-Asm.html#Extended-Asm

语法很奇怪,但总结是:

asm("instructions" : outputs : inputs);

...whereinputsoutputs是约束列表,它们告诉 gcc 将什么值放在哪里。经典的例子是:

asm("fsinx %1,%0" : "=f" (result) : "f" (angle));

f表示命名值需要进入浮点寄存器;=表示它是一个输出;然后将寄存器的名称代入指令中。

所以,你可能会想要这样的东西:

asm("b" #op " " #offset ",%0 " #mask : "=Z" (i) : "0" (i));

...其中i是一个包含您要修改的值的变量。Z您需要在 6811 gcc 文档中查找 --- 这是一个约束,它代表一个对正在生成的 asm 指令有效的寄存器。表示输入与输出 0 共享一个寄存器,0用于读/写值。

因为你已经告诉 gcc 你想i成为什么寄存器,它可以将这些知识集成到它的寄存器分配器中,并找到成本最低的方法,i用最少的代码到达你需要的地方。(有时没有额外的代码。)

gcc 内联汇编非常扭曲和怪异,但非常强大。值得花一些时间彻底了解约束系统以充分利用它。

(顺便说一句,我不知道 6811 代码,但是您是否忘记将 op 的结果放在某个地方?我希望看到stx与 匹配的ldx。)

更新:哦,我知道现在bset在做什么 --- 它正在将结果写回内存位置,对吗?这仍然是可行的,但它有点更痛苦。您需要告诉 gcc 您正在修改该内存位置,以便它知道不依赖任何缓存值。您需要一个带有约束的输出参数m来表示该位置。检查文档。

于 2013-09-12T23:07:12.293 回答