我在嵌入式项目中使用MIPS CPU(PIC32),但我开始质疑我的选择。 我知道像MIPS这样的RISC CPU会生成比预期更多的指令,但我不认为它会是这样的。以下是反汇编列表中的代码段:
225: LATDSET = 0x0040;
sw s1,24808(s2)
sw s4,24808(s2)
sw s4,24808(s2)
sw s1,24808(s2)
sw s4,24808(s3)
sw s4,24808(s3)
sw s1,24808(s3)
226: {
227: porte = PORTE;
lw t1,24848(s4)
andi v0,t1,0xffff
lw v1,24848(s6)
andi ra,v1,0xffff
lw v1,24848(s6)
andi ra,v1,0xffff
lw v0,24848(s6)
andi t2,v0,0xffff
lw a2,24848(s5)
andi v1,a2,0xffff
lw t2,24848(s5)
andi v1,t2,0xffff
lw v0,24848(s5)
andi t2,v0,0xffff
228: if (porte & 0x0004)
andi t2,v0,0x4
andi s8,ra,0x4
andi s8,ra,0x4
andi ra,t2,0x4
andi a1,v1,0x4
andi a2,v1,0x4
andi a2,t2,0x4
229: pst_bytes_somi[0] |= sliding_bit;
or t3,t4,s0
xori a3,t2,0x0
movz t3,s0,a3
addu s0,t3,zero
or t3,t4,s1
xori a3,s8,0x0
movz t3,s1,a3
addu s1,t3,zero
or t3,t4,s1
xori a3,s8,0x0
movz t3,s1,a3
addu s1,t3,zero
or v1,t4,s0
xori a3,ra,0x0
movz v1,s0,a3
addu s0,v1,zero
or a0,t4,s2
xori a3,a1,0x0
movz a0,s2,a3
addu s2,a0,zero
or t3,t4,s2
xori a3,a2,0x0
movz t3,s2,a3
addu s2,t3,zero
or v1,t4,s0
xori a3,a2,0x0
movz v1,s0,a3
这似乎是一些疯狂的指令,用于在固定地址进行简单的读/写和测试变量。在不同的CPU上,我可能会将每个C语句降低到大约1..3条指令,而不需要使用手写的asm。显然,时钟频率相当高,但它不比我在不同CPU(例如dsPIC)中的时钟频率高10倍。
我将优化设置为最大值。我的C编译器很糟糕(这是gcc 3.4.4)?或者这是典型的MIPS?
答案 0 :(得分:6)
终于找到了答案。反汇编列表完全是误导性的。编译器正在进行循环展开,我们在每个C语句下看到的实际上是指令数量的8倍,因为它正在展开循环8x。说明不在连续的地址!在编译器选项中关闭循环展开会产生以下结果:
225: LATDSET = 0x0040;
sw s3,24808(s2)
226: {
227: porte = PORTE;
lw t1,24848(s5)
andi v0,t1,0xffff
228: if (porte & 0x0004)
andi t2,v0,0x4
229: pst_bytes_somi[0] |= sliding_bit;
or t3,t4,s0
xori a3,t2,0x0
movz t3,s0,a3
addu s0,t3,zero
230:
对每个人都感到恐慌。
答案 1 :(得分:3)
我认为你的编译器行为不端...... 检查一下这个陈述:
228: if (porte & 0x0004)
andi t2,v0,0x4 (1)
andi s8,ra,0x4 (2)
andi s8,ra,0x4 (3)
andi ra,t2,0x4 (4)
andi a1,v1,0x4 (5)
andi a2,v1,0x4 (6)
andi a2,t2,0x4 (7)
很明显,有些指令基本上什么都不做。指令(3)没有像s8中的存储那样新的指令(2)计算出相同的结果。 指令(6)也没有效果,因为它被下一条指令(7)覆盖, 我相信任何进行静态分析阶段的编译器至少会删除指令(3)和(6)。
类似的分析将适用于您的代码的其他部分。例如,在第一个语句中,您可以看到一些寄存器(v0和v0)加载了两次相同的值。
我认为你的编译器在优化编译代码方面做得不好。
答案 2 :(得分:2)
MIPS基本上是RISC设计愚蠢的一切的体现。目前,x86(和x86_64)已经从RISC中吸收了几乎所有有价值的想法,并且ARM已经发展到比传统RISC更高效,同时仍然忠于保持小型系统指令集的RISC概念。 p>
要回答这个问题,我会说你疯狂选择MIPS,或者更重要的是,选择MIPS而不先学习一下MIPS ISA以及为什么它如此糟糕以及你需要多少效率低下如果你想使用它。在大多数情况下,我会选择ARM用于低功耗/嵌入式系统,如果能够承受更多的功耗,我会选择更好的Intel Atom。
编辑:实际上,你可能会疯狂的第二个原因......从评论来看,你似乎正在使用16位整数。你不应该在C中使用小于int
的类型,除非在数组中或在大量分配的结构中(以数组或其他方式,如链表/树/等)。 。使用小类型将永远不会带来任何好处,除了节省空间(这与你拥有大量这种类型的值之前无关),并且几乎肯定比使用“普通”类型效率低。在MIPS的情况下,差异是极端的。切换到int
,看看问题是否消失。
答案 3 :(得分:0)
我唯一可以想到的可能是,也许,编译器可能会注入额外的无意义指令,以便以更慢的数据总线速度来提高CPU的速度。即使这种解释也不够,因为存储/加载指令同样具有冗余。
由于编译器是可疑的,不要忘记将注意力集中到编译器上可能会使您失去一种隧道视觉。也许错误在工具链的其他部分也是潜在的。
你从哪里获得编译器?我发现一些“简单”的资源经常会发布一些非常糟糕的工具。我的嵌入式开发朋友通常会编译他们自己的工具链,有时很多更好的结果。
答案 4 :(得分:0)
我尝试使用CodeSourcery MIPS GCC 4.4-303和-O4编译以下代码。我用uint32_t和uint16_t尝试了它:
#include <stdint.h>
void foo(uint32_t PORTE, uint32_t pst_bytes_somi[], uint32_t sliding_bit) {
uint32_t LATDSET = 0x0040;
{
uint32_t porte = PORTE;
if (porte & 0x0004)
pst_bytes_somi[0] |= sliding_bit;
if (porte & LATDSET)
pst_bytes_somi[1] |= sliding_bit;
}
}
这是使用uint32_t整数的反汇编:
uint32_t porte = PORTE;
if (porte & 0x0004)
0: 30820004 andi v0,a0,0x4
4: 10400004 beqz v0,18 <foo+0x18>
8: 00000000 nop
./foo32.c:7
pst_bytes_somi[0] |= sliding_bit;
c: 8ca20000 lw v0,0(a1)
10: 00461025 or v0,v0,a2
14: aca20000 sw v0,0(a1)
./foo32.c:8
if (porte & LATDSET)
18: 30840040 andi a0,a0,0x40
1c: 10800004 beqz a0,30 <foo+0x30>
20: 00000000 nop
./foo32.c:9
pst_bytes_somi[1] |= sliding_bit;
24: 8ca20004 lw v0,4(a1)
28: 00463025 or a2,v0,a2
2c: aca60004 sw a2,4(a1)
30: 03e00008 jr ra
34: 00000000 nop
这是使用uint16_t整数的反汇编:
if (porte & 0x0004)
4: 30820004 andi v0,a0,0x4
8: 10400004 beqz v0,1c <foo+0x1c>
c: 30c6ffff andi a2,a2,0xffff
./foo16.c:7
pst_bytes_somi[0] |= sliding_bit;
10: 94a20000 lhu v0,0(a1)
14: 00c21025 or v0,a2,v0
18: a4a20000 sh v0,0(a1)
./foo16.c:8
if (porte & LATDSET)
1c: 30840040 andi a0,a0,0x40
20: 10800004 beqz a0,34 <foo+0x34>
24: 00000000 nop
./foo16.c:9
pst_bytes_somi[1] |= sliding_bit;
28: 94a20002 lhu v0,2(a1)
2c: 00c23025 or a2,a2,v0
30: a4a60002 sh a2,2(a1)
34: 03e00008 jr ra
38: 00000000 nop
正如您所看到的,每个C语句都映射为两到三条指令。使用16位整数使该函数只有一个指令更长。
答案 5 :(得分:-1)
您是否启用了编译器优化?未经优化的代码有很多冗余。