I'm seeing incorrect code when -O1 or higher is used on AVR (atmega1284p). The compiler generates code that compares "x" to "y", instead of performing the subtraction and comparing against 0. This subtraction matters since "x" and "y" are signed 16-bit variables, and the math in the expression "x-y <= 0" stays as 16-bit in AVR (as opposed to being promoted to 32-bit ints in e.g. x86). gcc -v: Using built-in specs. Reading specs from /usr/local/avr/lib/gcc/avr/12.2.0/device-specs/specs-avr2 COLLECT_GCC=avr-gcc COLLECT_LTO_WRAPPER=/usr/local/avr/libexec/gcc/avr/12.2.0/lto-wrapper Target: avr Configured with: ../configure --target=avr --prefix=/usr/local/avr --disable-nls --enable-languages=c --disable-bootstrap --disable-libssp Thread model: single Supported LTO compression algorithms: zlib zstd gcc version 12.2.0 (GCC) Sample code: _Bool compare(short x, short y) { return (x-y <= 0); } Compiled using: gcc -O1 -mmcu=atmega1284p -c -o test.o test.c ASM result: 00000000 <compare>: 0: 9c 01 movw r18, r24 2: 81 e0 ldi r24, 0x01 ; 1 4: 62 17 cp r22, r18 <---- X compared directly to Y; no subtraction 6: 73 07 cpc r23, r19 8: 04 f4 brge .+0 ; 0xa <compare+0xa> a: 80 e0 ldi r24, 0x00 ; 0 0000000c <.L2>: c: 08 95 ret I instead expect to see a subtraction between r22:23 and r18:19, then a compare against r1 (zero). The following testcase causes an incorrect computation: compare(-30737, 24799) returns 1 on AVR; expected 0. (-30737 - (24799)) as signed 16-bit = 10000, which is not <= 0. For the record, changing the function to "return ((short)(x-y) <= 0)" produces the same incorrect code. Compiling the function without optimization correctly returns 0. It's possible other signed variable sizes besides 16-bit have the same problem, but I did not test this.
Pass the -Wstrict-overflow=4 option to GCC and see that compiler assumes no integer overlow will happen: test.c:3:12: warning: assuming signed overflow does not occur when simplifying 'X - Y <= 0' to 'X <= Y' [-Wstrict-overflow] 3 | return (x-y <= 0); Consider using "__builtin_sub_overflow" for a strictly defined behaviour when integer overflow happens.
Thank you, I hadn't thought of that at all. That was precisely my problem and I developed a work-around. Not a bug.