Gcc 这是一个优化错误吗?
这是我的编译器在汇编程序中的一些输出。它是基于GCC v3.23的MPLAB C30 C编译器,用于dsPIC33FJ128GP802,一种16位中等高速DSP/MCUGcc 这是一个优化错误吗?,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
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