【问题标题】:Getting GCC to optimize hand assembly让 GCC 优化手动组装
【发布时间】:2013-09-12 22:48:39
【问题描述】:

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

#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) 自动优化出冗余堆栈操作?

【问题讨论】:

  • 5 年太晚了,我知道,但是为了完整起见:1. 对于即时模式,应该是 LDX #0x1000(操作码 CE 而不是 FE),2. 优化也应该保持一个 @ 987654327@ 指令,因为它们都加载了寄存器库,不需要为每条指令重复。

标签: gcc assembly 68hc11


【解决方案1】:

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

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

语法很奇怪,但总结是:

asm("instructions" : outputs : inputs);

...其中inputsoutputs 是约束列表,它们告诉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 代码,但您是否忘记将运算结果放在某个地方?我希望看到 stxldx 匹配。)

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

【讨论】:

  • 没有找到它并不奇怪; m68hc11 支持在 4.6 中已弃用,并在 4.7 中删除。完成后我实际上不需要X 的值; bset(位 SET)和bclr(位 CLeaR)只有零页和索引寻址模式,因此索引寄存器的保存、加载和恢复。我会检查文档,谢谢。
  • 经过一些实验,我现在确信这是正确的解决方案。我在索引寻址方面遇到了一些麻烦,但我会将其作为一个单独的问题发布。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-03
  • 1970-01-01
  • 1970-01-01
  • 2022-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多