【问题标题】:ARM Deliberately Bloating Compiled Code?ARM故意膨胀编译代码?
【发布时间】:2014-06-11 17:40:48
【问题描述】:

在解决 Fastest Cortex M0+ Thumb 32x32=64 multiplication function? 中的问题时,我编写了以下 C 函数以查看它的编译方式:

uint64_t lmul(uint32_t a, uint32_t b){
    uint32_t hia = a >> 16,
        hib = b >> 16,
        loa = (uint32_t)(uint16_t)a,
        lob = (uint32_t)(uint16_t)b,
        low = loa * lob,
        mid1 = hia * lob,
        mid2 = loa * hib,
        mid = mid1 + mid2,
        high = hia * hib;

    if (mid < mid1)
        high += 0x10000;
    return ((uint64_t)high << 32) + ((uint64_t)mid << 16) + low;
}

在使用 ARM GCC 编译器 4.7.3 通过 CodeWarrior(我正在使用的飞思卡尔开发板附带)进行大小优化后,它变成了这样:

00000eac <lmul>:
     eac:   b570        push    {r4, r5, r6, lr}
     eae:   0c06        lsrs    r6, r0, #16
     eb0:   b280        uxth    r0, r0
     eb2:   0c0a        lsrs    r2, r1, #16
     eb4:   1c04        adds    r4, r0, #0
     eb6:   b289        uxth    r1, r1
     eb8:   434c        muls    r4, r1
     eba:   4350        muls    r0, r2
     ebc:   4371        muls    r1, r6
     ebe:   1843        adds    r3, r0, r1
     ec0:   4356        muls    r6, r2
     ec2:   428b        cmp r3, r1
     ec4:   d202        bcs.n   ecc <lmul+0x20>
     ec6:   2580        movs    r5, #128    ; 0x80
     ec8:   026a        lsls    r2, r5, #9
     eca:   18b6        adds    r6, r6, r2
     ecc:   0c19        lsrs    r1, r3, #16
     ece:   0418        lsls    r0, r3, #16
     ed0:   1c22        adds    r2, r4, #0
     ed2:   2300        movs    r3, #0
     ed4:   1c04        adds    r4, r0, #0
     ed6:   1c0d        adds    r5, r1, #0
     ed8:   18a4        adds    r4, r4, r2
     eda:   415d        adcs    r5, r3
     edc:   1c31        adds    r1, r6, #0
     ede:   1c18        adds    r0, r3, #0
     ee0:   1c22        adds    r2, r4, #0
     ee2:   1c2b        adds    r3, r5, #0
     ee4:   1812        adds    r2, r2, r0
     ee6:   414b        adcs    r3, r1
     ee8:   1c10        adds    r0, r2, #0
     eea:   1c19        adds    r1, r3, #0
     eec:   bd70        pop {r4, r5, r6, pc}

我无法理解编译器在函数的最后 40% 中做了什么。就像它只是为了增加函数的大小而播放音乐寄存器一样。这是众所周知的 ARM 做的事情,还是有一些奇怪的目的,我缺乏 ARM 组装专业知识来理解?

如果我在替换中没有犯任何错误,则函数的后半部分可以表示为:

 ecc:   0c19        lsrs    r1, r3, #16
 ece:   0418        lsls    r0, r3, #16
 ed2:   2300        movs    r3, #0
 ed8:   18a4        adds    r0, r0, r4
 eda:   415d        adcs    r1, r3
 ee6:   414b        adds    r1, r1, r6
 eec:   bd70        pop {r4, r5, r6, pc}

【问题讨论】:

  • 仅供参考,gcc explorer 上的 gcc 4.5.3 和 4.6.3 似乎没有这样做。
  • LOL +1 只为'音乐寄存器'
  • 一件事是我的帖子的前提,但我不完全确定,编译器实际上是来自 ARM 还是只是支持 ARM 的 GCC。我猜是前者,因为它在 CodeWarrior 中被列为“ARM Ltd. GCC Build Tools”,但我可能错了。据我了解,官方 ARM 编译器使用 GCC 前端,但后端不同。
  • 有各种 gcc 选项,例如 -dumpspecs 提供配置信息。在 gcc explorer 中,大约有 30 条 4.6.3 和 -mthumb -mcpu=cortex-m0 -Os 的指令。生成的代码看起来很可怕。我猜是演员阵容和一些模糊的溢出标准处理。你试过-ffast-math吗?
  • 谁能确认这发生在 vanilla GCC 4.7.3(即不是 CodeWarrior 附带的版本)中?

标签: c gcc assembly arm compiler-optimization


【解决方案1】:

我没有使用 CodeWarrior 工具链,但我决定使用 ARMCC 编译器 v 5.03.0.76 与 uVision 一起尝试。优化空间是默认选项(-Ospace),生成的代码仍然很丑陋……与你的并没有太大的不同。当我使用-O2 编译时,它看起来更像你所期望的:

0x0000008A B570      PUSH     {r4-r6,lr}
0x0000008C 0C02      LSRS     r2,r0,#16
0x0000008E 0C0C      LSRS     r4,r1,#16
0x00000090 B280      UXTH     r0,r0
0x00000092 B289      UXTH     r1,r1
0x00000094 4606      MOV      r6,r0
0x00000096 4615      MOV      r5,r2
0x00000098 434D      MULS     r5,r1,r5
0x0000009A 4360      MULS     r0,r4,r0
0x0000009C 434E      MULS     r6,r1,r6
0x0000009E 182B      ADDS     r3,r5,r0
0x000000A0 4362      MULS     r2,r4,r2
0x000000A2 42AB      CMP      r3,r5
0x000000A4 D202      BCS      0x000000AC
0x000000A6 2001      MOVS     r0,#0x01
0x000000A8 0400      LSLS     r0,r0,#16
0x000000AA 1812      ADDS     r2,r2,r0
0x000000AC 2400      MOVS     r4,#0x00
0x000000AE 0C19      LSRS     r1,r3,#16
0x000000B0 0418      LSLS     r0,r3,#16
0x000000B2 1900      ADDS     r0,r0,r4
0x000000B4 4151      ADCS     r1,r1,r2
0x000000B6 1980      ADDS     r0,r0,r6
0x000000B8 4161      ADCS     r1,r1,r4
0x000000BA BD70      POP      {r4-r6,pc}

您可以尝试使用不同的优化选项进行编译,但我建议您使用更新的编译器,正如 Marc Glisse 在他的评论中所说的那样。

【讨论】:

  • 所以我猜原始问题的答案是“否”:它似乎是 ARMCC 和 GCC 中的一个错误。
猜你喜欢
  • 1970-01-01
  • 2015-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-18
  • 1970-01-01
相关资源
最近更新 更多