如何控制 C 编译器优化的内容?
我正在使用 Silicon Labs IDE 和 SDCC 编译器用 C 语言编写嵌入式设备的固件。该器件架构基于 8051 系列。相关函数如下所示。该函数用于设置我的 MCU 上的端口以驱动步进电机。它由中断处理程序调用。大开关语句只是将端口设置为下一个电机步骤的正确值。该函数的底部部分查看来自霍尔效应传感器的输入和移动的多个步骤,以检测电机是否已停转。问题是,由于某种原因,第二个 IF 语句看起来像这样 if (StallDetector > (GapSize + 20)) { 处理StallEvent(); }
似乎总是被优化掉。如果我尝试在 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!
I am writing the firmware for an embedded device in C using the Silicon Labs IDE and the SDCC compiler. The device architecture is based on the 8051 family. The function in question is shown below. The function is used to set the ports on my MCU to drive a stepper motor. It gets called in by an interrupt handler. The big switch statement just sets the ports to the proper value for the next motor step. The bottom part of the function looks at an input from a hall effect sensor and a number of steps moved in order to detect if the motor has stalled. The problem is, for some reason the second IF statement that looks like this if (StallDetector > (GapSize + 20))
always seems to get optimized out. If I try to put a breakpoint at the
{
HandleStallEvent();
}HandleStallEvent()
call the IDE gives me a message saying "No Address Correlation to this line number". I am not really good enough at reading assembly to tell what it is doing but I have pasted a snippet from the asm output below. Any help would be much appreciated.
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
}
... and the asm output for the the bottom part of this function...
; 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
It looks to me like the compiler is NOT optimizing out this second if statement from the looks of the asm but if that is the case why does the IDE not allow me so set a breakpoint there? Maybe it's just a dumb IDE!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这被称为“尾调用优化”。
OperateStepper() 在调用 HandleStallEvent() 之后不会执行任何操作,因此返回它没有意义。您只需对 RET 执行 RET,这会浪费指令和堆栈槽。
阅读“Lambda:终极……”麻省理工学院人工智能实验室备忘录了解更多详细信息。
在 HandleStallEvent() 例程上设置断点,而不是在调用上。
It is called "tail call optimization".
OperateStepper() doesn't do anything after the call to HandleStallEvent(), so there is no point in returning to it. You'd just be doing a RET to a RET, which is a waste of an instruction AND a stack slot.
Read the "Lambda: The Ultimate ..." MIT AI Lab memos for more details.
Set your breakpoint on the HandleStallEvent() routine, rather than the call.
IF 语句没有被优化掉。这是它的代码。
我注意到在倒数第三行中,发生了一些有趣的事情。它没有对
HandleStallEvent
进行函数调用。它正在执行长跳转,因此它显然知道HandleStallEvent
无法返回。我还看到,在上面的两行中,它定义了将行号与跳转指令相关联的汇编程序符号。因此,它有一个第 678 行的符号。如果 IDE 不允许您在第 678 行设置断点,也许您可以获取第 678 行的十六进制地址,并将其设置在该十六进制地址处。您可能会尝试的另一件事是在该行之前插入一个局部变量定义,例如 int Breakhere = 1 ,然后看看这是否为您提供了一些可以中断的指令。顺便说一句,你可以看到CPU以8位数字来思考,所以如果你可以使用char而不是short,它将节省指令。节省的时间是否值得取决于机器执行此代码的时间百分比。
BTW2,如果你想榨取这只小狗的性能,我在做嵌入式工作时所依赖的是随机停止 IDE(或英特尔“蓝盒”ICE)。 以下是相关内容。
The IF statement is not being optimized out. This is the code for it.
I notice that in the 3rd-to-last line, something funny is happening. It is not doing a function call to
HandleStallEvent
. It is doing a long-jump, so it evidently knows thatHandleStallEvent
cannot return. I also see that in the two lines above that, it is defining assembler symbols that relate the line number to the jump instruction. So, it has a symbol for line 678. If the IDE won't let you set a breakpoint at line 678, perhaps you can get the hex address of line 678, and set it at the hex address. Another thing you might try could be to insert a local variable definition likeint breakhere = 1
before that line, and see if that gives you some instructions you can break at.BTW, you can see that the CPU thinks in terms of 8-bit numbers, so if you can use char instead of short, it will save instructions. Whether the time saved is worth it depends on what percent of time the machine is in this code.
BTW2, if you want to squeeze performance out of this puppy, what I relied on when I was doing embedded work was randomly halting the IDE (or the Intel "Blue Box" ICE). Here's something about that.
您通常可以使用#pragma 语句调整优化器。
我不知道你的编译器的确切语法,但你应该能够在你的编译器/ide 附带的文档中找到它。
像这样的东西
You can usually tweak the optimizer with #pragma statements.
I don't know the exact syntax for your compiler, but you should be able to find it in the docs which come with your compiler/ide.
Something like this
如何配置优化取决于编译器。 SDCC 的手册第 3.28 节列出了其优化选项。您可以在源代码级别使用命令行选项或编译指示。尝试全局禁用优化,看看是否能获得相同的效果。通常,在禁用优化的调试器中单步执行代码将消除无法设置断点的问题。如果这工作正常,您可以尝试使用编译指示在函数级别禁用可疑优化,以查看哪一个可能导致问题。
How optimizations can be configured is compiler dependent. The manual for SDCC has its optimization options listed under section 3.28. You can use both command line options or pragmas at the source code level. Try out disabling optimizations globally to see if you get the same effect. Normally stepping through code in a debugger with optimizations disabled will eliminate the problem of not being able to set a breakpoint. If this works fine you can try disabling suspect optimizations at the function level with pragmas to see which one might be causing the problem.