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

时间:2010-04-15 19:47:24

标签: c optimization compiler-construction function sdcc

我正在使用Silicon Labs IDE和SDCC编译器在C语言中编写嵌入式设备的固件。器件架构基于8051系列。有问题的功能如下所示。该功能用于设置MCU上的端口以驱动步进电机。它被一个中断处理程序调用。 big switch语句只是将端口设置为下一个电机步骤的正确值。该功能的底部部分查看来自霍尔效应传感器的输入和移动的多个步骤,以便检测电机是否已停止。问题是,由于某种原因,看起来像if (StallDetector > (GapSize + 20)) { HandleStallEvent(); }的第二个IF语句似乎总是被优化出来。如果我尝试在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!

4 个答案:

答案 0 :(得分:5)

它被称为“尾调用优化”。

在调用HandleStallEvent()之后,OperateStepper()没有做任何事情,因此返回它没有意义。你只是对RET做一个RET,这是浪费指令 AND 一个堆栈插槽。

阅读“Lambda:The Ultimate ...”MIT AI Lab备忘录了解更多详情。

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

答案 1 :(得分:3)

IF声明未进行优化。这是它的代码。

    C$MotionControl.c$670$4$11 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:670: if (StallDetector > (GapSize + 20))
    mov a,#0x14       ; r2,r3 = 20 + GapSize
    add a,_GapSize    ; (adding a 16-bit number in two 8-bit steps)
    mov r2,a
    clr a
    addc    a,(_GapSize + 1)
    mov r3,a
    clr c
    mov a,r2          ; subtracting in two 8-bit steps
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$        ; jump if carry not set (fall through if carry set)
    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    ; it knows HandleStallEvent does not return!
00130$:                            ; or rather, it knows this handler cannot return, so there's no need to call.
    ret

我注意到在倒数第3行,发生了一些有趣的事情。它没有对HandleStallEvent进行函数调用。它正在进行长跳,所以它显然知道HandleStallEvent无法返回。我还看到,在上面的两行中,它定义了将行号与跳转指令相关联的汇编符号。因此,它具有第678行的符号。如果IDE不允许您在第678行设置断点,也许您可​​以获取第678行的十六进制地址,并将其设置为十六进制地址。您可能尝试的另一件事可能是在该行之前插入一个本地变量定义,如int breakhere = 1,并查看是否为您提供了一些可以解决的说明。

顺便说一下,您可以看到CPU根据8位数字进行考虑,因此如果您可以使用char而不是short,它将保存指令。节省的时间是否值得,取决于机器在此代码中的时间百分比。

BTW2,如果你想从这只小狗中挤出性能,我在做嵌入式工作时所依赖的是随机停止IDE(或英特尔“蓝盒子”ICE)。 Here's something about that.

答案 2 :(得分:1)

您通常可以使用#pragma语句调整优化程序。 我不知道编译器的确切语法,但您应该能够在编译器/ ide附带的文档中找到它。

像这样的东西

#pragma optimize( "", off )
//now the function which should not be optimized
#pragma optimize( "", on )

答案 3 :(得分:1)

如何配置优化是依赖于编译器的。 SDCC的manual的优化选项列在第3.28节。您可以在源代码级别使用命令行选项或编译指示。尝试全局禁用优化以查看是否获得相同的效果。通常在禁用优化的情况下逐步调试调试器中的代码将消除无法设置断点的问题。如果这样可以正常工作,您可以尝试使用编译指示在函数级别禁用可疑优化,以查看哪个可能导致问题。