[英]ARM GCC removing required code during optimization
我有以下代碼,它執行從 16bpp 圖像到 1bpp 圖像的真正基本轉換,代碼按預期運行,直到我啟用編譯器優化,此時我只得到一個黑色圖像。
#define RSCALE 5014709
#define GSCALE 9848225
#define BSCALE 1912602
uint16_t _convertBufferTo1bit(uint8_t* buffer, uint16_t size)
{
uint8_t* dst_ptr = buffer;
uint8_t* end_ptr = buffer + size;
uint16_t pos = 0;
uint8_t r, g, b, i;
uint32_t lum;
while(buffer < end_ptr)
{
for(i = 8; i > 0; i--)
{
r = (*buffer & 0xF8);
g = ((*buffer & 0x07) << 5);
buffer += 1;
g |= (*buffer & 0x03);
b = ((*buffer & 0x1F) << 3);
buffer += 1;
lum = ((RSCALE * r) + (GSCALE * g) + (BSCALE * b));
if(lum > 0x7FFFFFFF)
{
//White
dst_ptr[pos] |= (1 << (i-1));
}
else
{
//black
dst_ptr[pos] &= ~(1 << (i-1));
}
}
pos++;
}
return pos;
}
查看反編譯的程序集時,我可以看到if(lum > 0x7FFFFFFF)
語句和所有相關計算已被編譯器刪除。 有人可以幫我理解為什么嗎?
-O0 -std=c++17 -Wall -Wextra
https://godbolt.org/z/GhPezzh33
-O1 -std=c++17 -Wall -Wextra
在這段代碼中:
lum = ((RSCALE * r) + (GSCALE * g) + (BSCALE * b));
if(lum > 0x7FFFFFFF)
RSCALE
、 GSCALE
和BSCALE
分別是5014709
、 9848225
和1912602
。 假設int
在正在使用的 C 實現中是 32 位,這些都是int
常量。
r
、 g
和b
都是uint8_t
類型,因此在乘法中它們被提升為int
。
然后((RSCALE * r) + (GSCALE * g) + (BSCALE * b))
是一個完全使用int
操作數產生int
結果的計算。 因此編譯器可以看到lum
被分配了一個int
結果的值,並且它有權假設結果在INT_MIN
到INT_MAX
的范圍內。 此外,它可以看到所有操作數都是非負數,因此不可能產生負數,將可能的范圍縮小到0
到INT_MAX
。 這排除了將負值分配給uint32_t
將導致換行到高值的可能性。 所以編譯器可能會假設lum > 0x7FFFFFFF
永遠不會是真的。
計算可能會溢出int
,然后行為未定義,並且仍然允許編譯器使用該假設。
要更正此問題,請將每個乘法的至少一個操作數更改為unsigned
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.