首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >除了ARMv7之前的拇指互通,有没有理由使用BX R而不是MOV pc,R?

除了ARMv7之前的拇指互通,有没有理由使用BX R而不是MOV pc,R?
EN

Stack Overflow用户
提问于 2020-08-09 08:00:42
回答 1查看 452关注 0票数 8

Linux defines an assembler macro在支持它的CPU上使用BX,这让我怀疑其中有一些性能原因。

This answerCortex-A7 MPCore Technical Reference Manual还指出,它有助于分支预测。

然而,我的基准测试工作并没有发现ARM1176、Cortex-A17、Cortex-A72和Neoverse-N1 cpus的性能差异。

因此,除了与Thumb代码互通之外,是否有任何理由在具有内存管理单元并实现32位ARM指令集的cpus上首选BX而不是MOV pc,

编辑后添加基准代码,全部对齐为64字节:

使用BXlr执行无用的计算并返回

代码语言:javascript
运行
复制
div_bx
        mov  r9, #2
        mul  lr, r9, lr
        udiv lr, lr, r9
        mul  lr, r9, lr
        udiv lr, lr, r9
        bx   lr

在另一个寄存器上执行无用的计算并使用BX返回

代码语言:javascript
运行
复制
div_bx2
        mov  r9, #2
        mul  r3, r9, lr
        udiv r3, r3, r9
        mul  r3, r9, r3
        udiv r3, r3, r9
        bx   lr

使用MOVlr执行无用的计算并返回

代码语言:javascript
运行
复制
div_mov
        mov  r9, #2
        mul  lr, r9, lr
        udiv lr, lr, r9
        mul  lr, r9, lr
        udiv lr, lr, r9
        mov  pc, lr

使用经典函数指针序列调用:

代码语言:javascript
运行
复制
movmov
        push {lr}
loop    mov  lr, pc
        mov  pc, r1
        mov  lr, pc
        mov  pc, r1
        mov  lr, pc
        mov  pc, r1
        mov  lr, pc
        mov  pc, r1
        subs r0, r0, #1
        bne  loop
        pop  {pc}

使用BLX调用

代码语言:javascript
运行
复制
blx
        push {lr}
loop    nop
        blx  r1
        nop
        blx  r1
        nop
        blx  r1
        nop
        blx  r1
        subs r0, r0, #1
        bne  loop
        pop  {pc}

移除nop%s会使速度变慢。

以秒为单位的每100000000次循环的结果:

代码语言:javascript
运行
复制
Neoverse-N1 r3p1 (AWS c6g.medium)
           mov+mov   blx 
div_bx        5.73  1.70 
div_mov       5.89  1.71 
div_bx2       2.81  1.69 

Cortex-A72 r0p3 (AWS a1.medium)
           mov+mov   blx 
div_bx        5.32  1.63 
div_mov       5.39  1.58 
div_bx2       2.79  1.63 

Cortex-A17 r0p1 (ASUS C100P)
           mov+mov   blx 
div_bx       12.52  5.69 
div_mov      12.52  5.75 
div_bx2       5.51  5.56 

我测试的3个ARMv7处理器似乎都将mov pc, lrbx lr识别为返回指令。然而,Raspberry Pi 1 with ARM1176被记录为有return prediction that recognises only BX lr和一些loads作为返回指令,但我没有找到返回预测的证据。

代码语言:javascript
运行
复制
header: .string "       Calle      BL       B  Difference"
format: .string "%12s %7i %7i %11i\n"
        .align

        .global main
main:   push    {r3-r5, lr}
        adr     r0, header
        bl      puts

        @ Warm up
        bl      clock
        mov     r0, #0x40000000
1:      subs    r0, r0, #1
        bne     1b
        bl      clock

        .macro  run_test test
2:      bl      1f
        nop
        bl      clock
        mov     r4, r0
        ldr     r0, =10000000
        .balign 64
3:      mov     lr, pc
        bl      1f
        nop
        mov     lr, pc
        bl      1f
        nop
        mov     lr, pc
        bl      1f
        nop
        subs    r0, r0, #1
        bne     3b
        bl      clock
        mov     r5, r0
        ldr     r0, =10000000

        .balign 64
5:      mov     lr, pc
        b       1f
        nop
        mov     lr, pc
        b       1f
        nop
        mov     lr, pc
        b       1f
        nop
        subs    r0, r0, #1
        bne     5b
        bl      clock
        sub     r2, r5, r4
        sub     r3, r0, r5
        sub     r0, r3, r2
        str     r0, [sp]
        adr     r1, 4f
        ldr     r0, =format
        bl      printf
        b       2f
        .ltorg
4:      .string "\test"
        .balign 64
1:
        .endm

        run_test mov
        mov     lr, lr
        mov     pc, lr

        run_test bx
        mov     lr, lr
        bx      lr

        run_test mov_mov
        mov     r2, lr
        mov     pc, r2

        run_test mov_bx
        mov     r2, lr
        bx      r2

        run_test pp_mov_mov
        push    {r1-r11, lr}
        pop     {r1-r11, lr}
        mov     r12, lr
        mov     pc, r12

        run_test pp_mov_bx
        push    {r1-r11, lr}
        pop     {r1-r11, lr}
        mov     r12, lr
        bx      r12

        run_test pp_mov_mov_f
        push    {r0-r11}
        pop     {r0-r11}
        mov     r12, lr
        mov     pc, r12

        run_test pp_mov_bx_f
        push    {r0-r11}
        pop     {r0-r11}
        mov     r12, lr
        bx      r12

        run_test pp_mov
        push    {r1-r11, lr}
        pop     {r1-r11, lr}
        mov     r12, lr
        mov     pc, lr

        run_test pp_bx
        push    {r1-r11, lr}
        pop     {r1-r11, lr}
        mov     r12, lr
        bx      lr

        run_test pp_mov_f
        push    {r0-r11}
        pop     {r0-r11}
        mov     r12, lr
        bx      lr

        run_test pp_bx_f
        push    {r0-r11}
        pop     {r0-r11}
        mov     r12, lr
        bx      lr

        run_test add_mov
        nop
        add     r2, lr, #4
        mov     pc, r2

        run_test add_bx
        nop
        add     r2, lr, #4
        bx      r2

2:      pop     {r3-r5, pc}

Cortex-A17的结果与预期一致:

代码语言:javascript
运行
复制
       Calle      BL       B  Difference
         mov   94492  255882      161390
          bx   94673  255752      161079
     mov_mov  255872  255806         -66
      mov_bx  255902  255796        -106
  pp_mov_mov  506079  506132          53
   pp_mov_bx  506108  506262         154
pp_mov_mov_f  439339  439436          97
 pp_mov_bx_f  439437  439776         339
      pp_mov  247941  495527      247586
       pp_bx  247891  494873      246982
    pp_mov_f  230846  422626      191780
     pp_bx_f  230850  422772      191922
     add_mov  255997  255896        -101
      add_bx  255900  256288         388

然而,在我的Raspberry Pi1和ARM1176上运行来自Raspbery的Linux 5.4.51+时,并没有显示出可预测指令的优势:

代码语言:javascript
运行
复制
       Calle      BL       B  Difference
         mov  464367  464372           5
          bx  464343  465104         761
     mov_mov  464346  464417          71
      mov_bx  464280  464577         297
  pp_mov_mov 1073684 1074169         485
   pp_mov_bx 1074009 1073832        -177
pp_mov_mov_f  769160  768757        -403
 pp_mov_bx_f  769354  769368          14
      pp_mov  885585 1030520      144935
       pp_bx  885222 1032396      147174
    pp_mov_f  682139  726129       43990
     pp_bx_f  682431  725210       42779
     add_mov  494061  493306        -755
      add_bx  494080  493093        -987
EN

回答 1

Stack Overflow用户

发布于 2020-08-09 08:20:30

如果您正在测试mov pc, ...总是跳转到同一返回地址的简单情况,那么常规的间接分支预测可能会做得很好。

我猜bx lr可能会使用一个返回地址预测器,该预测器假定匹配的调用/返回(blx / bx lr)来正确地预测各个调用点的返回,也不会浪费正常的间接分支预测器中的空间。

要检验这一假设,请尝试如下所示

代码语言:javascript
运行
复制
testfunc:
   bx lr         @ or mov pc,lr

caller:
 mov  r0, #100000000
.p2align 4
 .loop:
  blx   testfunc
  blx   testfunc     # different return address than the previous blx
  blx   testfunc
  blx   testfunc
  subs   r0, #1
  bne   .loop

如果我的假设是正确的,我预测mov pc, lr在这方面将比bx lr慢。

(可能需要更复杂的目标地址模式(在本例中为callsites),以混淆某些CPU上的间接分支预测。一些CPU有一个返回地址预测器,它只能记住1个目标地址,但稍微复杂一些的预测器可以处理4个地址的简单重复模式。)

(这只是一个猜测,我没有任何使用这些芯片的经验,但是返回地址预测器的通用cpu体系结构技术是众所周知的,我读到过它在实践中用于多个ISA。我知道x86肯定会使用它:http://blog.stuffedcow.net/2018/04/ras-microbenchmarks/不匹配的call/ret绝对是个问题。)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63321275

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档