- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在处理 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(我正在使用的 Freescale 开发板附带的)编译它并进行大小优化后,它变成了这个:
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}
最佳答案
我没有使用过 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 在他的评论中所述。
关于c - ARM故意膨胀编译代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23302753/
首先是我的对象: public class Group { private final ObservableList sourceList; private final Obser
我有一个 Circle 类和一个 Rectangle 类。我现在想创建一个类 FunnyObject,每个类都由一个圆和两个矩形组成。 如果我这样做: class FunnyObject:public
我正在阅读一篇博文 here关于用 node.js 创建一个刮板并遇到了一些有趣的 javascript,我无法完全理解。这正是我想在我的脚本中使用的东西,但作为一个新手,我不想在不知道它们首先做什么
我不明白为什么在成功之后我为什么看不到脚本中的错误(我用谷歌搜索,它只是给出了关于jquery get脚本成功/错误时错误处理的很多答案)。 如果我使用“any” js脚本执行此操作 $.getScr
我目前正在为我公司正在开发的设备( radio 编码器)开发单元测试。 可以通过 SNMP(仅限 v1)访问各种统计信息,其中您可以获得由于各种原因丢弃的 UDP 数据报的数量。 我希望能够发送一个包
这是一个令人费解的问题。我运行良好的 ASP.NET 3.5 应用程序突然开始出现超时错误... System.Data.SqlClient.SqlException:超时已过。操作完成前超时时间已过
我正在尝试掌握 C++ 内存管理的窍门,并尝试使用无限循环的新语句故意使我的程序崩溃。据我了解,这只会在内存堆上保留越来越多的空间。但是我的程序不会崩溃。在 Windows 任务管理器中监控它,它将使
我是一名优秀的程序员,十分优秀!