https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119543
Bug ID: 119543
Summary: At -O1 and higher, GCC incorrectly optimizes isTmax
function to always return 0
Product: gcc
Version: 13.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: 2023152001 at email dot szu.edu.cn
Target Milestone: ---
Bug Description:
When compiling with -O1 or higher optimization levels, GCC incorrectly
optimizes a function that detects the maximum two's complement integer (Tmax,
0x7FFFFFFF) to always return 0, even for valid Tmax input.
Steps to Reproduce:
1. Save the following code to isTmax_bug.c:
int isTmax(int x) {
int temp = x + 1;
int tmin = 1 << 31; /* 0x80000000 - Minimum two's complement value */
int t = temp ^ tmin;
int y = !t;
return y;
}
int main() {
/* Should print 1 for Tmax (0x7FFFFFFF) */
return isTmax(0x7FFFFFFF);
}
2. Compile with -O0 (works correctly):
gcc -m32 -O0 isTmax_bug.c -o isTmax_O0
3. Compile with -O1 (incorrect optimization):
gcc -m32 -O1 isTmax_bug.c -o isTmax_O1
4. Run both programs:
./isTmax_O0 # Returns 1 (correct)
./isTmax_O1 # Returns 0 (incorrect)
GCC Version Information:
gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04)
Target: x86_64-linux-gnu
Assembly Code Comparison:
O0 optimization (correct):
isTmax:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
call __x86.get_pc_thunk.ax
addl $_GLOBAL_OFFSET_TABLE_, %eax
movl 8(%ebp), %eax
addl $1, %eax
movl %eax, -16(%ebp)
movl $-2147483648, -12(%ebp)
movl -16(%ebp), %eax
xorl -12(%ebp), %eax
movl %eax, -8(%ebp)
cmpl $0, -8(%ebp)
sete %al
movzbl %al, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
O1 optimization (incorrect):
isTmax:
movl $0, %eax
ret
Analysis:
This bug appears to be related to how the compiler handles signed integer
overflow. The function is designed to detect Tmax (0x7FFFFFFF) by checking if
(x+1)^0x80000000 == 0, which is true only when x+1 == 0x80000000 (i.e., x is
Tmax).
When x is 0x7FFFFFFF (Tmax), x+1 causes signed overflow, producing 0x80000000
(Tmin). The compiler may incorrectly assume this overflow case never happens
due to undefined behavior rules in C, leading to the wrong optimization of
always returning 0.
Temporary Workaround:
Either compile with -O0 or use an alternative implementation:
int isTmax(int x) {
int y = ~(x+1);
int t1 = !(x^y);
int t2 = !!(x+1);
return t1&t2;
}
This alternative implementation also detects Tmax correctly but avoids the
optimization issue.