让GCC优化手工装配

Ign*_*ams 8 assembly gcc 68hc11

在试图让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")
Run Code Online (Sandbox Code Playgroud)

他们工作得很好; 拆解后的二进制文件非常完美.

当我按顺序使用多个时,问题出现了:

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));
}
Run Code Online (Sandbox Code Playgroud)

这导致:

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
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*ven 9

gcc将始终发出您告诉它发出的汇编指令.因此,您不是明确地编写代码来加载具有您想要操作的值的寄存器,而是希望告诉gcc代表您执行此操作.您可以使用注册约束来执行此操作.

不幸的是6811代码生成器似乎不是gcc的标准部分---我没有发现手册中的文档.所以我不能指出你在文档的平台特定位.但是你需要阅读的通用位是:http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/Extended-Asm.html#Extended-Asm

语法很怪异,但摘要是:

asm("instructions" : outputs : inputs);
Run Code Online (Sandbox Code Playgroud)

... where inputsoutputs是约束列表,告诉gcc放在哪里的值.经典的例子是:

asm("fsinx %1,%0" : "=f" (result) : "f" (angle));
Run Code Online (Sandbox Code Playgroud)

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

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

asm("b" #op " " #offset ",%0 " #mask : "=Z" (i) : "0" (i));
Run Code Online (Sandbox Code Playgroud)

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

因为你已经告诉gcc你想要什么样的寄存器i,它可以将这些知识集成到它的寄存器分配器中,并找到以最少i的代码获得所需位置的最低成本方式.(有时没有额外的代码.)

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

(顺便说一下,我不知道6811代码,但是你忘了将op的结果放在某个地方吗?我希望看到一个stx匹配的ldx.)

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