GCC为AVR上的简单ISR产生不必要的寄存器推送
GCC produces unneccessary register pushes for simple ISR on AVR
我有一些简单的C++程序,如果用g++编译,它会产生以下汇编程序文本。唯一的语句是sbi
,它不影响任何状态标志。我想知道为什么G++会产生r0
和r1
的这些无用的推/弹出?
.global __vector_14
.type __vector_14, @function
__vector_14:
push r1 ;
push r0 ;
in r0,__SREG__ ; ,
push r0 ;
clr __zero_reg__ ;
/* prologue: Signal */
/* frame size = 0 */
/* stack size = 3 */
.L__stack_usage = 3
sbi 0x1e,0 ; ,
/* epilogue start */
pop r0 ;
out __SREG__,r0 ; ,
pop r0 ;
pop r1 ;
reti
.size __vector_14, .-__vector_14
有没有办法让g++自动省略这些寄存器保存。我一般不想将ISR声明为ISR_NAKED
。
编辑:这是相应的C++代码(-Os或-O3):
#include <avr/interrupt.h>
struct AppFlags final {
bool expired : 1;
} __attribute__((packed));
int main() {
}
ISR(TIMER0_COMPA_vect) {
auto f = reinterpret_cast<volatile AppFlags*>(0x3e);
f->expired = true;
}
原因是您使用的是过时的编译器。上述优化已添加到v8(2018年春季发布)中,请参阅GCC v8发布说明:
编译器现在生成高效的中断服务例程(ISR)序言和尾声。这是通过使用GNU汇编程序支持和解决的新AVR伪指令__gcc_isr来实现的。
简单答案:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=20296
困难在于,目前avr后端的架构没有很容易允许改进这种情况:每个指令模式(如"multiply两个16位整数"或"符号将16位变量扩展到32位")可以自由地假设它可能覆盖或更改r0和r1,除非它离开">zero_reg"在完成任务后使用0。
要解决这个问题,IMHO需要对后端。
这是对avr后端的一个长期错误/增强请求。
GCC推送所有使用的寄存器。您唯一真正的办法是启用naked
属性,它只会推送堆栈指针。或者更改为汇编语言。
GCC版本8之前没有优化ISR序言和尾声。GCC 8及更高版本现在在使用某些优化级别(如-Os
)进行编译或提供-mgas-isr-prologues
时,会发出包含ISR主体的__gcc_isr
伪指令。
GNU汇编程序(来自不太过时的binutils版本)理解这些伪指令,并扫描__gcc_isr 1
和__gcc_isr 2
之间的指令(通过),以决定r0(tmp寄存器)、r1(零寄存器)和SREG(状态寄存器)中的哪一个需要保存和恢复。
因此,对于您的示例,我得到了一个非常小的objdump(当使用GCC 11.1编译时):
$ avr-objdump -d foo.o
[..]
00000000 <__vector_14>:
0: f0 9a sbi 0x1e, 0 ; 30
2: 18 95 reti
[..]
当我告诉GCC只发出汇编时,我们看到伪指令:
$ avr-g++ -c -S -Os -mmcu=atmega328p foo.c -fno-exceptions
$ cat foo.s
[..]
.global __vector_14
.type __vector_14, @function
__vector_14:
__gcc_isr 1
/* prologue: Signal */
/* frame size = 0 */
/* stack size = 0...3 */
.L__stack_usage = 0 + __gcc_isr.n_pushed
sbi 0x1e,0
/* epilogue start */
__gcc_isr 2
reti
__gcc_isr 0,r0
[..]
- 本质:使用__128寄存器
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 用callgrind追踪不必要的副本
- 在模拟器中使用并集来模拟CPU寄存器有多合适
- "变量":函数中函数作用域不允许初始化的自动或寄存器变量'naked'
- C 包装器C++库周围没有不必要的头文件
- 被调用方如何知道参数是通过寄存器而不是堆栈传递的
- GCC为AVR上的简单ISR产生不必要的寄存器推送
- 如何在不使用复合文字的情况下从标量初始化 AltiVec 寄存器
- 英特尔 Pin:分析例程检测 ah 寄存器而不是 RSP (REG_STACK_PTR)
- 在x86_64模式下,64 位数字不适合寄存器整数
- 是否可以在不使用汇编的情况下告诉clang哪些寄存器用于代码的某些部分
- 如何在 Windows 异常处理程序中设置 MMX 寄存器以模拟不受支持的 3DNow! 说明
- Eclipse 中的 Arduino 端口寄存器不起作用
- 如何在不违反严格的混叠规则的情况下访问内存映射的多字节寄存器
- 按照每个通用寄存器的用途对 x86 程序集进行编码是必要还是更容易
- 为什么编译器对原始/std数组使用XMM寄存器,而对向量不使用?
- libOpenCL.so使用VFP寄存器参数,而输出不使用
- 为什么我们不能总是在 C 中使用寄存器存储类?
- 如何在64位(而不是任何80位寄存器)中强制所有双精度