这是我的编译器在汇编器中的一些输出。它是 MPLAB C30 C 编译器,基于 GCC v3.23,用于 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 位变量的补码之类的代码,似乎也总是使用两个寄存器。它让我迷失了!
最佳答案
该函数未编码为将计数限制为 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
关于gcc - 这是优化错误吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4770822/