GCC在AVR上为简单的ISR产生不必要的寄存器推送

时间:2017-06-12 07:32:21

标签: c++ avr

我有一些简单的C ++程序,如果使用g ++编译,则会生成以下汇编程序文本。唯一的陈述是sbi,它不会影响任何状态标志。我想知道为什么G ++会产生r0r1这些无用的推/弹?

.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;
}

3 个答案:

答案 0 :(得分:2)

GCC推送所有使用过的寄存器。你唯一真正的办法是启用naked属性,它只会推送堆栈指针。或者改为汇编语言。

答案 1 :(得分:2)

简单回答:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=20296

  

在   困难在于,avr后端的当前架构没有   容易允许改进这种情况:每个指令模式(如“倍增   两个16位整数“或”符号 - 将16位变量扩展为32位“)   可以自由地假设可能会覆盖或更改r0和r1,除非它离开了   完成任务后,“ zero_reg ”为0。

     

解决这个问题,恕我直言,将需要重大的重构   后端。

这是对avr-backend的长期错误/增强请求。

答案 2 :(得分:0)

原因是您使用的是过时的编译器。 mentioned optimization已在v8(于2018年春季发布)中添加,请参见GCC v8 Release Notes

编译器现在生成高效的中断服务例程(ISR)序言和结语。这是通过使用新的AVR pseudo instruction __gcc_isr来实现的,它由GNU汇编程序支持和解析。