https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109650

            Bug ID: 109650
           Summary: avr-gcc incorrect code with -Os
           Product: gcc
           Version: 12.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: thierer at web dot de
  Target Milestone: ---

Created attachment 54942
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=54942&action=edit
preprocessed input file

The attached file imho creates invalid code with avr-gcc 12.2.0 when compiling
with "-Os". The same code works with either different optimization settings or
avr-gcc 11.3.0 (haven't tried any other versions).

The misbehaving code is this function:

static bool test_func(uint8_t p1, uint8_t p2) {
  if (p1 == 0 || p1 > 7)
    return false;

  if      (p1 < 3) return p2 <= 8;
  else if (p1 < 5) return p2 <= 6;
  else if (p1 < 7) return p2 <= 4;
  else             return p2 <= 2;
}

It should return false for all values of p2 if p1 is 0 or > 7 and the result
should depend on p2 for inbetween values of p1.

The code contains a lot of boilerplate for sending a showcase output over
USART0. This is the result for values of 0 <= p2 < 10 (columns) for 0 < p1 < 9
(rows):

  0123456789
0 ??????????
1 XXXXXXXXX?
2 XXXXXXXXX?
3 XXXXXX????
4 XXXXXX????
5 XXXX??????
6 XXXX??????
7 XX????????
8 ??????????

"X" means test_func() returned true, "?" false. The result for p1 in [0,1,2,8]
is correct, all the other results are off (too low) by 1. For example, for p1
== 3 the function should return true for all p2 <= 6, but it only does for <=
5.

I'm not too familiar with AVR assembly, but the problem seems to be that the
comparisons that calculate the result value all use the same brlo (branch if
lower) instruction at .L34, but the compiler fails to compensate for the
"lower" instead of "lower or equal" for all but the first (<= 8) condition:

.L21:
        cpi r17,lo8(7)
        brsh .L25
        cpi r28,lo8(3)
        brsh .L12
        cpi r29,lo8(9)          ; this correctly compares to 9 == 8+1
.L34:
        brlo .L27
.L25:
        ldi r24,lo8(63)
.L11:

[...]

.L12:
        cpi r28,lo8(5)
        brsh .L15
        cpi r29,lo8(6)          ; but this does not (should be 6+1 == 7)
        rjmp .L34
.L15:
        cpi r28,lo8(7)
        breq .L17
        cpi r29,lo8(4)          ; neither does this (should be 4+1 == 5)
        rjmp .L34
.L17:
        cpi r29,lo8(2)          ; nor this (should be 2+1 == 3)
        rjmp .L34
.L27:


Tested with the respective Arch Linux x86_64 avr-gcc packages.

Output of "avr-gcc -v":

> avr-gcc -v -save-temps -Wall -Wextra -mmcu=atmega1284p -Os 
> --param=min-pagesize=0 avr-bug.c
Using built-in specs.
Reading specs from /usr/lib/gcc/avr/12.2.0/device-specs/specs-atmega1284p
COLLECT_GCC=avr-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/avr/12.2.0/lto-wrapper
Target: avr
Configured with: /build/avr-gcc/src/gcc-12.2.0/configure
--disable-install-libiberty --disable-libssp --disable-libstdcxx-pch
--disable-libunwind-exceptions --disable-linker-build-id --disable-nls
--disable-werror --disable-__cxa_atexit --enable-checking=release
--enable-clocale=gnu --enable-gnu-unique-object --enable-gold
--enable-languages=c,c++ --enable-ld=default --enable-lto --enable-plugin
--enable-shared --infodir=/usr/share/info --libdir=/usr/lib
--libexecdir=/usr/lib --mandir=/usr/share/man --prefix=/usr --target=avr
--with-as=/usr/bin/avr-as --with-gnu-as --with-gnu-ld --with-ld=/usr/bin/avr-ld
--with-plugin-ld=ld.gold --with-system-zlib --with-isl
--enable-gnu-indirect-function
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 12.2.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra'  '-Os'
'--param=min-pagesize=0' '-mdouble=32' '-mlong-double=64'
'-specs=device-specs/specs-atmega1284p' '-mmcu=avr51' '-dumpdir' 'a-'
 /usr/lib/gcc/avr/12.2.0/cc1 -E -quiet -v -imultilib avr51
-D__AVR_ATmega1284P__ -D__AVR_DEVICE_NAME__=atmega1284p avr-bug.c -mn-flash=2
-mno-skip-bug -mdouble=32 -mlong-double=64 -mmcu=avr51 -Wall -Wextra -Os
-fpch-preprocess -o a-avr-bug.i
ignoring nonexistent directory
"/usr/lib/gcc/avr/12.2.0/../../../../avr/sys-include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/avr/12.2.0/include
 /usr/lib/gcc/avr/12.2.0/include-fixed
 /usr/lib/gcc/avr/12.2.0/../../../../avr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra'  '-Os'
'--param=min-pagesize=0' '-mdouble=32' '-mlong-double=64'
'-specs=device-specs/specs-atmega1284p' '-mmcu=avr51' '-dumpdir' 'a-'
 /usr/lib/gcc/avr/12.2.0/cc1 -fpreprocessed a-avr-bug.i -mn-flash=2
-mno-skip-bug -quiet -dumpdir a- -dumpbase avr-bug.c -dumpbase-ext .c
-mdouble=32 -mlong-double=64 -mmcu=avr51 -Os -Wall -Wextra -version
--param=min-pagesize=0 -o a-avr-bug.s
GNU C17 (GCC) version 12.2.0 (avr)
        compiled by GNU C version 12.1.1 20220730, GMP version 6.2.1, MPFR
version 4.1.0-p13, MPC version 1.2.1, isl version isl-0.26-GMP

warning: MPFR header version 4.1.0-p13 differs from library version 4.2.0.
warning: MPC header version 1.2.1 differs from library version 1.3.1.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C17 (GCC) version 12.2.0 (avr)
        compiled by GNU C version 12.1.1 20220730, GMP version 6.2.1, MPFR
version 4.1.0-p13, MPC version 1.2.1, isl version isl-0.26-GMP

warning: MPFR header version 4.1.0-p13 differs from library version 4.2.0.
warning: MPC header version 1.2.1 differs from library version 1.3.1.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 00c69299beaa7f88846ded0b751d0e18
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra'  '-Os'
'--param=min-pagesize=0' '-mdouble=32' '-mlong-double=64'
'-specs=device-specs/specs-atmega1284p' '-mmcu=avr51' '-dumpdir' 'a-'
 /usr/bin/avr-as -v -mmcu=avr51 -mgcc-isr -mno-skip-bug -o a-avr-bug.o
a-avr-bug.s
GNU assembler version 2.40 (avr) using BFD version (GNU Binutils) 2.40
COMPILER_PATH=/usr/lib/gcc/avr/12.2.0/:/usr/lib/gcc/avr/12.2.0/:/usr/lib/gcc/avr/:/usr/lib/gcc/avr/12.2.0/:/usr/lib/gcc/avr/
LIBRARY_PATH=/usr/lib/gcc/avr/12.2.0/avr51/:/usr/lib/gcc/avr/12.2.0/../../../../avr/lib/avr51/:/usr/lib/gcc/avr/12.2.0/:/usr/lib/gcc/avr/12.2.0/../../../../avr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra'  '-Os'
'--param=min-pagesize=0' '-mdouble=32' '-mlong-double=64'
'-specs=device-specs/specs-atmega1284p' '-mmcu=avr51' '-dumpdir' 'a.'
 /usr/lib/gcc/avr/12.2.0/collect2 -plugin
/usr/lib/gcc/avr/12.2.0/liblto_plugin.so
-plugin-opt=/usr/lib/gcc/avr/12.2.0/lto-wrapper -plugin-opt=-fresolution=a.res
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lm
-plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-latmega1284p -mavr51
-Tdata 0x800100
/usr/lib/gcc/avr/12.2.0/../../../../avr/lib/avr51/crtatmega1284p.o
-L/usr/lib/gcc/avr/12.2.0/avr51
-L/usr/lib/gcc/avr/12.2.0/../../../../avr/lib/avr51 -L/usr/lib/gcc/avr/12.2.0
-L/usr/lib/gcc/avr/12.2.0/../../../../avr/lib a-avr-bug.o --start-group -lgcc
-lm -lc -latmega1284p --end-group
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra'  '-Os'
'--param=min-pagesize=0' '-mdouble=32' '-mlong-double=64'
'-specs=device-specs/specs-atmega1284p' '-mmcu=avr51' '-dumpdir' 'a.'

Reply via email to