2011-01-22 119 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