2011-01-22 115 views
4

这里是我编译器在汇编器中的一些输出。它是基于GCC v3.23的MPLAB C30 C编译器,用于dsPIC33FJ128GP802(一款16位中等高速DSP/MCU)。这是一个优化错误吗?

212:    inline uint16_t ror_16(uint16_t word, int num) 
213:    { 
078C4 608270  and.w w1,#16,w4 
078C6 DE0204  lsr w0,w4,w4 
078C8 780101  mov.w w1,w2 
078CA EA8102  com.w w2,w2 
078CC EA8183  com.w w3,w3 
078CE 610170  and.w w2,#16,w2 
078D0 DD0002  sl w0,w2,w0 
078D2 700004  ior.w w0,w4,w0 
214:    num &= 16; // limit to 16 shifts 
215:    return (word >> num) | (word << (16 - num)); 
216:    } 
078D4 060000  return 

特别我感兴趣的以下内容:

and.w w1,#16,w4   AND W1 with 16, storing result in W4 
lsr w0,w4,w4   Logical shift right W0 by W4 times storing result in W4 
mov.w w1,w2    Move W1 to W2 
com.w w2,w2    Logical complement of W2 stored in W2 
com.w w3,w3    Logical complement of W3 stored in W3 <-- This line is confusing me 
and.w w2,#16,w2   AND W2 with 16, storing result in W2 
sl w0,w2,w0    (Logical) shift left W0 left by W2 times storing result in W0 
ior.w w0,w4,w0   Inclusive OR of W0 and W4 stored in W0 
return     Return from function 

W0..W15是16上芯片16位寄存器的阵列。

有效地简化为(在原始RTL):

W4 := W1 & 16 
W4 := W0 LSR W4 
W1 := W2 
W2 := COM W2 
W3 := COM W3 
W2 := W2 & 16 
W0 := W0 SL W2 
W0 := W0 | W4 
return 

现在我在的时候只有两个传递的参数(W0和W1为什么它被计算W3的补困惑 - 它使用W数组用于将参数传递给具有较小参数的函数的函数)。W3从不用于计算,并且永不返回。事实上,它甚至没有数据:函数中没有任何内容存储,只有被调用者将有一些数据(虽然函数不需要保存W0..W7,因此被调用者不应该依靠它。)为什么它包含在代码中?它只是一个编译器故障或错误,或者我错过了什么?

这不仅仅是这个代码 - 我在代码的其他部分看到了同样的奇怪。即使设计用于计算诸如16位变量的补码之类的代码,似乎总是使用两个寄存器。它让我失去了!

+0

这可能是指令集设计一个怪癖。也许管道工作的方式是,在使用前一个结果之前,你应该总是执行另一个`COM`指令。 – 2011-01-22 22:01:34

+0

@Pascal Cuoq在这个处理器上没有这样的流水线。也许它有两级流水线(所以它可以操作读取 - 解码 - 执行 - 写入RISC周期),但它不依赖于前面的指令。它的唯一延迟来自分支机构和指令跳过。 – 2011-01-22 22:06:07

回答

2

功能不编码限制数量为16(我怀疑你的意思是0至16),但它限制为0或16

而不是

num &= 16 

,你或许需要

num > 16 ? (num & 15) : num 

回复:因为该函数是内联的,所以只能通过查看它的使用位置来回答。也许W3用于周围代码中的某些东西。或者它可能是一个“错误”,但它只有性能,而不是正确性和影响。如果num只能是0或16(如你的代码中那样),那么(16 - num)也只能是16或0,这就是为什么C30可以用补码和掩码做“减法”的原因。

仅供参考,当我没有内联,在C30我得到:

34:    uint16_t ror_16(uint16_t word, int num) 
35:    { 
05AF4 608170  and.w 0x0002,#16,0x0004 
05AF6 DE0102  lsr 0x0000,0x0004,0x0004 
05AF8 EA8081  com.w 0x0002,0x0002 
05AFA 6080F0  and.w 0x0002,#16,0x0002 
05AFC DD0001  sl 0x0000,0x0002,0x0000 
05AFE 700002  ior.w 0x0000,0x0004,0x0000 
36:     num &= 16; // limit to 16 shifts 
37:     return (word >> num) | (word << (16 - num)); 
38:    } 
05B00 060000  return 

我可能会编写这是

34:    uint16_t ror_16(uint16_t word, int num) 
35:    { 
05AF4 780100  mov.w 0x0000,0x0004 
36:     num &= 15; // mod 16 
05AF6 60806F  and.w 0x0002,#15,0x0000 
37:     return (num == 0) ? word : ((word >> num) | (word << (16 - num))); 
05AF8 320004  bra z, 0x005b02 
05AFA DE1080  lsr 0x0004,0x0000,0x0002 
05AFC 100070  subr.w 0x0000,#16,0x0000 
05AFE DD1000  sl 0x0004,0x0000,0x0000 
05B00 708100  ior.w 0x0002,0x0000,0x0004 
38:    } 
05B02 780002  mov.w 0x0004,0x0000 
05B04 060000  return