c - 您如何控制 C 编译器优化的内容?

标签 c optimization compiler-construction function sdcc

我正在使用 Silicon Labs IDE 和 SDCC 编译器用 C 语言为嵌入式设备编写固件。设备架构基于 8051 系列。有问题的功能如下所示。该函数用于设置我的 MCU 上的端口以驱动步进电机。它由中断处理程序调用。 big switch 语句只是将端口设置为下一个电机步的正确值。该函数的底部查看来自霍尔效应传感器的输入和移动的一些步数,以检测电机是否已停转。问题是,出于某种原因,第二个 IF 语句看起来像这样 if (StallDetector > (GapSize + 20)) { HandleStallEvent(); } 似乎总是被优化掉。如果我尝试在 HandleStallEvent() 调用处放置一个断点,IDE 会给我一条消息,指出“与此行号没有地址关联”。我不太擅长阅读汇编,无法分辨它在做什么,但我从下面的 asm 输出中粘贴了一个片段。任何帮助将不胜感激。

void OperateStepper(void)
{
    //static bit LastHomeMagState = HomeSensor;
    static bit LastPosMagState = PosSensor;
    if(PulseMotor)
    {
        if(MoveDirection == 1) // Go clockwise
        {
            switch(STEPPER_POSITION) 
            {
                case 'A': 
                     STEPPER_POSITION = 'B';
                     P1 = 0xFD;
                     break;
                case 'B':
                     STEPPER_POSITION = 'C';
                     P1 = 0xFF;
                     break;
                case 'C':
                     STEPPER_POSITION = 'D';
                     P1 = 0xFE;
                     break;
                case 'D':
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
                     break; 
                default:
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
            }   //end switch
        }
        else                // Go CounterClockwise
        {
            switch(STEPPER_POSITION) 
            {
                case 'A': 
                     STEPPER_POSITION = 'D';
                     P1 = 0xFE;
                     break;
                case 'B': 
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
                     break;
                case 'C': 
                     STEPPER_POSITION = 'B';
                     P1 = 0xFD;
                     break;
                case 'D': 
                     STEPPER_POSITION = 'C';
                     P1 = 0xFF;
                     break; 
                default: 
                     STEPPER_POSITION = 'A';
                     P1 = 0xFE;
            }   //end switch
        }   //end else

        MotorSteps++;
        StallDetector++;

        if(PosSensor != LastPosMagState)
        {
            StallDetector = 0;

            LastPosMagState = PosSensor;
        }
        else
        {
            if (PosSensor == ON) 
            {
                if (StallDetector > (MagnetSize + 20))
                {
                    HandleStallEvent();
                }
            }
            else if (PosSensor == OFF) 
            {
                if (StallDetector > (GapSize + 20))
                {
                    HandleStallEvent();
                }
            }
        }

    }   //end if PulseMotor
}

...以及此函数底部的 asm 输出...

;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:653: if(PosSensor != LastPosMagState)
    mov c,_P1_4
    jb  _OperateStepper_LastPosMagState_1_1,00158$
    cpl c
00158$:
    jc  00126$
    C$MotionControl.c$655$3$7 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:655: StallDetector = 0;
    clr a
    mov _StallDetector,a
    mov (_StallDetector + 1),a
    C$MotionControl.c$657$3$7 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:657: LastPosMagState = PosSensor;
    mov c,_P1_4
    mov _OperateStepper_LastPosMagState_1_1,c
    ret
00126$:
    C$MotionControl.c$661$2$8 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:661: if (PosSensor == ON) 
    jb  _P1_4,00123$
    C$MotionControl.c$663$4$9 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:663: if (StallDetector > (MagnetSize + 20))
    mov a,_MagnetSize
    mov r2,a
    rlc a
    subb    a,acc
    mov r3,a
    mov a,#0x14
    add a,r2
    mov r2,a
    clr a
    addc    a,r3
    mov r3,a
    clr c
    mov a,r2
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$
    C$MotionControl.c$665$5$10 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:665: HandleStallEvent();
    ljmp    _HandleStallEvent
00123$:
    C$MotionControl.c$668$2$8 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:668: else if (PosSensor == OFF) 
    jnb _P1_4,00130$
    C$MotionControl.c$670$4$11 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:670: if (StallDetector > (GapSize + 20))
    mov a,#0x14
    add a,_GapSize
    mov r2,a
    clr a
    addc    a,(_GapSize + 1)
    mov r3,a
    clr c
    mov a,r2
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$
    C$MotionControl.c$672$5$12 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:672: HandleStallEvent();
    C$MotionControl.c$678$2$1 ==.
    XG$OperateStepper$0$0 ==.
    ljmp    _HandleStallEvent
00130$:
    ret

在我看来,从 asm 的外观来看,编译器并未优化第二个 if 语句,但如果是这样,为什么 IDE 不允许我在此处设置断点?也许它只是一个愚蠢的 IDE!

最佳答案

这叫做“尾调用优化”。

OperateStepper() 在调用 HandleStallEvent() 之后没有做任何事情,因此没有必要返回它。您只是对 RET 执行 RET,这是对指令堆栈槽的浪费。

阅读“Lambda:终极......”麻省理工学院人工智能实验室备忘录了解更多详情。

在 HandleStallEvent() 例程而不是调用上设置断点。

关于c - 您如何控制 C 编译器优化的内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2648490/

相关文章:

c++ - 在 C 或 C++ 中实现 Prolog

fread() 可以检测空字符吗?

c++ - 在内存中处理一些长 vector 时如何不弄乱缓存?

c++ - C++ 中的动态与静态多态性 : which is preferable?

c - 常量 C 表达式是在编译时还是在运行时求值?

c# - 使用未初始化的变量 - 编译器已损坏

c++ - 由 clang 表示的 C++

c - 如何在minix操作系统中执行c文件

C - 链表 - 删除头部 - 段错误

c++ - 比较有符号比无符号整数更快