You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MDK ARM编译器无优化下__forceinline函数执行更慢问题求助

问题:STM32F030上__forceinline函数比非内联函数执行时间更长

在STM32F030芯片上使用无优化的MDK ARM编译器时,发现被__forceinline声明的函数执行时间比未声明的更长,已通过示波器验证。简化后的示例代码如下:

static  void __forceinline inline_dbg()
{
    //cs down
    GPIOA->BRR = (uint32_t)GPIO_PIN_4;  
    while((GPIOB->IDR & GPIO_PIN_10) == 0){}
    //cs up 
    GPIOA->BSRR = (uint32_t)GPIO_PIN_4;
}

移除__forceinline后函数执行更快。查看反汇编发现,__forceinline函数中while((GPIOB->IDR & GPIO_PIN_10) == 0){}语句前有两个NOP,而未内联的函数中仅有一个NOP。

完整测试用例:

while(1)
{
    no_inline_dbg();
    inline_dbg();
}

static  void no_inline_dbg()
{
    //cs down
    GPIOA->BRR = (uint32_t)GPIO_PIN_4;
    while((GPIOB->IDR & GPIO_PIN_10) == 0){}
    //cs up
    GPIOA->BSRR = (uint32_t)GPIO_PIN_4;
}

static  __forceinline void inline_dbg()
{
    //cs down
    GPIOA->BRR = (uint32_t)GPIO_PIN_4;  
    while((GPIOB->IDR & GPIO_PIN_10) == 0){}
    //cs up 
    GPIOA->BSRR = (uint32_t)GPIO_PIN_4;
}

对应的反汇编代码:

0x0800CB98 F7FEF85E  BL.W     no_inline_dbg (0x0800AC58) 

-------------------THIS IS INLINE SECTION!!!!!!!
0x0800CB9C BF00      NOP
--------------cs down (chip select down)-------------      
0x0800CB9E 2010      MOVS     r0,#0x10
0x0800CBA0 2109      MOVS     r1,#0x09
0x0800CBA2 06C9      LSLS     r1,r1,#27
0x0800CBA4 6288      STR      r0,[r1,#0x28]
-----------------------------------------------
0x0800CBA6 BF00      NOP    //<---- WHY THERE IS TWO NOPS HERE???       
0x0800CBA8 BF00      NOP   
------------while((GPIOB->IDR & GPIO_PIN_10) == 0){}-------------   
0x0800CBAA 4807      LDR      r0,[pc,#28]  
0x0800CBAC 6900      LDR      r0,[r0,#0x10]
0x0800CBAE 2101      MOVS     r1,#0x01
0x0800CBB0 0289      LSLS     r1,r1,#10
0x0800CBB2 4008      ANDS     r0,r0,r1
0x0800CBB4 2800      CMP      r0,#0x00
0x0800CBB6 D0F8      BEQ      0x0800CBAA
---------------cs up (chip select up)------------
0x0800CBB8 2010      MOVS     r0,#0x10
0x0800CBBA 2109      MOVS     r1,#0x09
0x0800CBBC 06C9      LSLS     r1,r1,#27
0x0800CBBE 6188      STR      r0,[r1,#0x18]
------------------------------------------------
0x0800CBC0 BF00      NOP      
0x0800CBC2 E7E9      B        0x0800CB98

------------------THIS IS NOT INLINE SECTION!!!!!!
------------cs down (chip select down)-------------
0x0800AC58 2010      MOVS     r0,#0x10
0x0800AC5A 2109      MOVS     r1,#0x09
0x0800AC5C 06C9      LSLS     r1,r1,#27
0x0800AC5E 6288      STR      r0,[r1,#0x28]
----------------------------------------
0x0800AC60 BF00      NOP     
------------while((GPIOB->IDR & GPIO_PIN_10) == 0){}-----------
0x0800AC62 4806      LDR      r0,[pc,#24]  ; @0x0800AC7C
0x0800AC64 6900      LDR      r0,[r0,#0x10]
0x0800AC66 2101      MOVS     r1,#0x01
0x0800AC68 0289      LSLS     r1,r1,#10
0x0800AC6A 4008      ANDS     r0,r0,r1
0x0800AC6C 2800      CMP      r0,#0x00
0x0800AC6E D0F8      BEQ      0x0800AC62
--------------cs up (chip select up)-------------
0x0800AC70 2010      MOVS     r0,#0x10
0x0800AC72 2109      MOVS     r1,#0x09
0x0800AC74 06C9      LSLS     r1,r1,#27
0x0800AC76 6188      STR      r0,[r1,#0x18]
----------------goes to 0x0800CB9C-----------------
0x0800AC78 4770      BX       lr 

请问这是怎么回事?为何编译器会根据函数是否内联来修改函数内部代码?


解答

这是MDK ARM编译器在**无优化(-O0)**模式下的典型行为,核心原因是内联代码与非内联代码的代码对齐策略不同:

  1. 指令对齐需求
    STM32F030基于Cortex-M0内核,虽然内核本身支持半字/字节对齐的指令,但MDK编译器在无优化模式下,会为内联后的代码块添加额外NOP来满足隐含的对齐规则——比如将循环入口(while语句)对齐到4字节边界。
    观察反汇编:内联版本中while循环的起始地址0x0800CBAA是4字节对齐的(16进制末两位AA能被4整除),而前面的两个NOP就是为了把循环入口推到这个对齐位置。
    非内联函数中,while循环起始地址0x0800AC62不是4的倍数,编译器在无优化模式下仅做了半字对齐,只插入了一个NOP。

  2. 无优化模式的特殊性
    当开启优化(如-O1及以上)时,编译器会自动移除多余的NOP,同时优化指令顺序,内联函数的执行效率通常会高于非内联版本。但在-O0模式下,编译器优先保证代码原始结构和调试友好性,而非执行效率,因此会插入额外NOP维持对齐,哪怕这会拖慢执行速度。

  3. __forceinline的影响
    使用__forceinline后,函数代码被直接嵌入调用处,编译器会将嵌入后的代码块作为整体处理对齐规则,而非像独立函数那样仅考虑局部对齐。这就导致内联版本出现了额外的NOP,进而增加了执行时间。

总结:这种现象是无优化模式下编译器对齐策略差异导致的,并非内联本身的问题。若追求执行效率,建议开启合适的优化等级(如-O1),此时多余的NOP会被自动移除,内联函数的优势也会体现出来。

内容的提问来源于stack exchange,提问作者zulunation

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 13:37:09