这是一个优化错误吗?

时间:2011-01-22 21:47:14

标签: gcc compiler-construction assembly

这是汇编程序中我的编译器的一些输出。它是基于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 - 它使用W数组将参数传递给具有较小参数的函数的函数)来计算W3的补码。)W3从未使用过在计算中,永远不会返回。事实上它似乎没有数据:函数中没有任何数据存储,只有被调用者会有一些数据(虽然不需要函数来保存W0..W7所以被调用者不应该依赖它。)为什么它包含在代码中?它只是一个编译器故障或错误,还是我错过了什么?

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

1 个答案:

答案 0 :(得分:2)

该函数未编码为将计数限制为16(我怀疑你的意思是0到16),但将其限制为0或16。

而不是

num &= 16

你可能想要

num > 16 ? (num & 15) : num

Re:问题,因为函数是内联的,所以只能通过查看它的使用位置来回答它。也许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