Gcc 这是一个优化错误吗?

Gcc 这是一个优化错误吗?,gcc,compiler-construction,assembly,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 780

这是我的编译器在汇编程序中的一些输出。它是基于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
现在我不明白为什么它只计算W3的补码,而只有两个传递的参数(W0和W1-它使用W数组为具有较小参数的函数传递参数)。W3从未在计算中使用,也从未返回。事实上,它甚至看起来没有数据:函数没有存储任何数据,只有被调用方才会有一些数据(虽然函数不需要保留W0..W7,所以被调用方不应该依赖它)。为什么代码中包含它?这只是编译器的小故障或错误,还是我遗漏了什么


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

该函数的编码不是为了将计数限制为16(我猜您的意思是0到16),而是将计数限制为0或16

而不是

num &= 16
你也许想要

num > 16 ? (num & 15) : num
Re:问题是,因为函数是内联的,所以只能通过查看它的使用位置来回答。也许W3用于周围代码中的某些内容。或者它可能是一个“bug”,但它只影响性能,而不影响正确性

如果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错误(uint16字,整数)
35:                {
05AF4 608170和.w 0x0002,#16,0x0004
05AF6 DE0102 lsr 0x0000,0x0004,0x0004
05AF8 EA8081 com.w 0x0002,0x0002
05AFA 6080F0和.w 0x0002,#16,0x0002
05AFC DD0001 sl 0x0000,0x0002,0x0000
05AFE 700002 ior.w 0x0000,0x0004,0x0000
36:num&=16;//限制为16个移位

37:return(word>>num)|(word>num)|(word这可能是指令集设计中的一个怪癖。可能管道的工作方式是,在使用前一条指令的结果之前,您应该一直执行另一条
COM
指令。@Pascal Cuoq此处理器上没有这样的管道。可能它有两级管道(因此它可以操作提取-解码-执行-写入RISC循环),但它不依赖于以前的指令。它唯一的延迟来自分支和指令跳过。你能发布函数的原始C代码吗?16位寄存器的16位移位看起来很奇怪。不,这是计算模的一种快速方法。我认为,如果数大于16,处理器会重置。虽然这可能导致数据不正确,但不会重置/崩溃处理器。W3用于周围的代码中,但没有固定的用途;有关详细信息,请参阅我的问题。我担心编译器会忽略内联指令。有内联指令和没有内联指令的代码都是一样的。您可以使用&=15获得快速模16,但您需要的是无法使用&;h实现的模17但是,由于按16旋转与按0旋转相同,&=15实际上是您可能想要的。也许您的编译器较新并且有错误修复。您使用的是哪个版本?语言工具版本:pic30-as.exe v3.24、pic30-gcc.exe v3.24、pic30-ld.exe v3.24、pic30-ar.exe v3。24@DougCurrie,我有v3.23,所以我似乎落后于它一个版本蚂蚁很快就会升级。
num > 16 ? (num & 15) : num
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