微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么更改为thumb2中的低位寄存器会增加周期数?

如何解决为什么更改为thumb2中的低位寄存器会增加周期数?

我已经在我的thumb2汇编代码中将所有r10更改为r4。 正如预期的那样,尺寸确实有所缩小。
但是执行的周期增加了。尽管仍然有相同的说明,但现在只有少数几个是窄而不是宽的。

为什么会这样?

根本不使用任何中断,仅访问闪存和内存(在定时例程中)。

我已经在带有0个等待状态的Cortex-M4(STM32F411)上运行了我的代码,并带有或不带有预取和/或icache。我已经用DWT:CYCCNT进行了测量。 它从1902619到1908268周期增加了约0.2%。 (使用/不使用icache /预取时,这些周期会有所警惕。)

解决方法

正在测试的代码:

    ldr r2,[r0]

---- code under test ----
loop:   
    subs r1,#1
    bne loop
---- code under test ----

    ldr r3,[r0]
    subs r0,r2,r3
    bx lr

R0包含在操纵杆计数寄存器中的点,被测代码基本上是尽可能紧密且可重复地测量的。 Systick与DWT一样好,而且可能更容易。

我正在从ram跑,因为这是一个MCU,但更重要的是因为它是STM32,除了极少数例外,它在Flash前面有一个预取缓存,您不能禁用它也不能轻易破坏它,从而对PITA进行基准测试。

在低位寄存器和高位寄存器之间切换

add r3,r10,r11
add r3,r3,r4

c:  eb0a 030b   add.w   r3,sl,fp
c:  4423        add r3,r4

基本上是两个半字与一个半字。通过更改某些指令中的某些寄存器可能会导致指令大小更改,此指令大小更改会影响后续代码的对齐方式。

测试代码

  10:   6802        ldr r2,[r0,#0]

00000012 <loop>:
  12:   3901        subs    r1,#1
  14:   d1fd        bne.n   12 <loop>

  16:   6803        ldr r3,#0]
  18:   1ad0        subs    r0,r3
  1a:   4770        bx  lr

循环未在单词边界(0x12)上对齐

使用0x10000、0x10000、0x20000、0x30000循环(r1 = 0x10000,...)进行四次测试

给予

0005FFFD 
0005FFFD 
000BFFFD 
0011FFFD 

所以现在相同的机器代码在单词边界上对齐。

00000010 <loop>:
  10:   3901        subs    r1,#1
  12:   d1fd        bne.n   10 <loop>

00040001 
00040001 
00080001 
000C0001

每种情况下机器码都匹配

12: 3901        subs    r1,#1
14: d1fd        bne.n   12 <loop>

10: 3901        subs    r1,#1
12: d1fd        bne.n   10 <loop>

将对齐方式更改半个字,性能会发生巨大变化

自然地,每当进行任何ARM汇编语言编程时,您都应该始终掌握ARM文档:

“所有提取都在整个字范围内。每个字提取的指令数量取决于运行的代码和内存中代码的对齐方式。”

请注意,不同的Cortex-M内核可能不具有不同的提取选项,因为Cortex-M4表示一件事,而其他则没有不同。

为记录起见,上面的简单示例未在Flash中演示问题。 STM32产品具有闪存缓存(具有一些特殊的营销名称和商标,甚至还有专利),您通常无法关闭它。

这在Flash中有效

08000032 <loop>:
 8000032:   f3af 8000   nop.w
 8000036:   f3af 8000   nop.w
 800003a:   f3af 8000   nop.w
 800003e:   f3af 8000   nop.w
 8000042:   f3af 8000   nop.w
 8000046:   3901        subs    r1,#1
 8000048:   d1f3        bne.n   8000032 <loop>

00090000 
00090000 
00120000 
001B0000 

vs

08000030 <loop>:
 8000030:   f3af 8000   nop.w
 8000034:   f3af 8000   nop.w
 8000038:   f3af 8000   nop.w
 800003c:   f3af 8000   nop.w
 8000040:   f3af 8000   nop.w
 8000044:   3901        subs    r1,#1
 8000046:   d1f3        bne.n   8000030 <loop>
 
00080000 
00080000 
00100000 
00180000 
 

相同的机器代码,半字对齐方式更改。快12.5%。

某些非STM32的工作(在闪存中)要容易得多,因为它们没有花哨的缓存,并且/或者依赖于可以启用/禁用的ARM缓存。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。