[Bug target/77326] New: [avr] Invalid optimization using varargs and a weak function
matthijs at stdin dot nl
gcc-bugzilla@gcc.gnu.org
Mon Aug 22 18:50:00 GMT 2016
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77326
Bug ID: 77326
Summary: [avr] Invalid optimization using varargs and a weak
function
Product: gcc
Version: 5.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: matthijs at stdin dot nl
Target Milestone: ---
Created attachment 39483
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=39483&action=edit
Preprocessed source generated by avr-gcc foo.c -Dissue -save-temps
This bug was originally reported to the Arduino bug tracker[1], but seems to be
a avr-specific gcc bug.
A minimal program showing the problem:
#include <stddef.h>
#include <stdarg.h>
void test(void) __attribute__((weak));
void va_pseudo(int flag,...){
va_list ap;
va_start (ap, flag);
va_end (ap);
}
int main(void) {
#if defined(issue)
va_pseudo(1, 2, 3, 4);
#else
va_pseudo(1, 2, 3);
#endif
if(test!=NULL) {
test();
}
return 0;
}
When compiled with -O but without -Dissue, this produces the following
assembler:
$ avr-gcc foo.c -O; avr-objdump -d a.out
a.out: file format elf32-avr
Disassembly of section .text:
00000000 <va_pseudo>:
0: cf 93 push r28
2: df 93 push r29
4: cd b7 in r28, 0x3d ; 61
6: de b7 in r29, 0x3e ; 62
8: df 91 pop r29
a: cf 91 pop r28
c: 08 95 ret
0000000e <main>:
e: 1f 92 push r1
10: 83 e0 ldi r24, 0x03 ; 3
12: 8f 93 push r24
14: 1f 92 push r1
16: 82 e0 ldi r24, 0x02 ; 2
18: 8f 93 push r24
1a: 1f 92 push r1
1c: 81 e0 ldi r24, 0x01 ; 1
1e: 8f 93 push r24
20: ef df rcall .-34 ; 0x0 <va_pseudo>
22: 0f 90 pop r0
24: 0f 90 pop r0
26: 0f 90 pop r0
28: 0f 90 pop r0
2a: 0f 90 pop r0
2c: 0f 90 pop r0
2e: 80 e0 ldi r24, 0x00 ; 0
30: 90 e0 ldi r25, 0x00 ; 0
32: 89 2b or r24, r25
34: 09 f0 breq .+2 ; 0x38 <main+0x2a>
36: e4 df rcall .-56 ; 0x0 <va_pseudo>
38: 80 e0 ldi r24, 0x00 ; 0
3a: 90 e0 ldi r25, 0x00 ; 0
3c: 08 95 ret
Note the lines from 0x2e to 0x34, which implement the `if(test!=NULL)`, which
should of course always fail and skip the next `rcall`. Now, when compiling
this with -Dissue, the `or r24, r25` line gets dropped, making the generated
code invalid:
$ avr-gcc foo.c -O -Dissue; avr-objdump -d a.out | grep -B 2 breq
38: 80 e0 ldi r24, 0x00 ; 0
3a: 90 e0 ldi r25, 0x00 ; 0
3c: 09 f0 breq .+2 ; 0x40 <__SREG__+0x1>
The diff between without and with -Dissue looks like this (jump addresses have
been stripped to minimize the diff):
@@ -15,6 +15,9 @@ <va_pseudo>:
<main>:
1f 92 push r1
+ 84 e0 ldi r24, 0x04 ; 4
+ 8f 93 push r24
+ 1f 92 push r1
83 e0 ldi r24, 0x03 ; 3
8f 93 push r24
1f 92 push r1
@@ -24,16 +27,17 @@ <main>:
81 e0 ldi r24, 0x01 ; 1
8f 93 push r24
xx xx rcall ; <va_pseudo>
- 0f 90 pop r0
- 0f 90 pop r0
- 0f 90 pop r0
- 0f 90 pop r0
- 0f 90 pop r0
- 0f 90 pop r0
+ 8d b7 in r24, 0x3d ; 61
+ 9e b7 in r25, 0x3e ; 62
+ 08 96 adiw r24, 0x08 ; 8
+ 0f b6 in r0, 0x3f ; 63
+ f8 94 cli
+ 9e bf out 0x3e, r25 ; 62
+ 0f be out 0x3f, r0 ; 63
+ 8d bf out 0x3d, r24 ; 61
80 e0 ldi r24, 0x00 ; 0
90 e0 ldi r25, 0x00 ; 0
- 89 2b or r24, r25
xx xx breq ; <main+0x....>
xx xx rcall ; <va_pseudo>
80 e0 ldi r24, 0x00 ; 0
90 e0 ldi r25, 0x00 ; 0
As you can see, the extra vararg changes the stack cleanup from a number
of pops to direct manipulation of the stack pointer, which involves the
same registers (r24 and r25) as the `test` check.
When running without -O, this bug does not occur. Then, the check looks
like this:
$ avr-gcc foo.c -Dissue; avr-objdump -d a.out | grep -B 3 breq
50: 80 e0 ldi r24, 0x00 ; 0
52: 90 e0 ldi r25, 0x00 ; 0
54: 00 97 sbiw r24, 0x00 ; 0
56: 09 f0 breq .+2 ; 0x5a <__SREG__+0x1b>
Here, the check uses the (slightly slower) sbiw instruction, where the
-O version uses or. I suspect that the optimization that makes this
change is responsible for, or at least involved in the bug. I couldn't
pinpoint the exact optimization responsible, running without -O, but
with all the options that -O is documented to turn on did not produce
the bug.
The above was tested using:
Using built-in specs.
COLLECT_GCC=avr-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/avr/4.8.1/lto-wrapper
Target: avr
Configured with: ../src/configure -v --enable-languages=c,c++
--prefix=/usr/lib --infodir=/usr/share/info --mandir=/usr/share/man
--bindir=/usr/bin --libexecdir=/usr/lib --libdir=/usr/lib --enable-shared
--with-system-zlib --enable-long-long --enable-nls --without-included-gettext
--disable-libssp --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=avr
Thread model: single
gcc version 4.8.1 (GCC)
But the bug also occurs using:
Using built-in specs.
Reading specs from
/home/matthijs/pkg-x86_64-unknown-linux-gnu/bin/../lib/gcc/avr/5.1.0/device-specs/specs-avr2
COLLECT_GCC=/home/matthijs/pkg-x86_64-unknown-linux-gnu/bin/avr-gcc
COLLECT_LTO_WRAPPER=/home/matthijs/pkg-x86_64-unknown-linux-gnu/bin/../libexec/gcc/avr/5.1.0/lto-wrapper
Target: avr
Configured with: /home/admin/avr-gcc-5.1.0/gcc-5.1.0/configure
--disable-install-libiberty --disable-libssp --disable-libstdcxx-pch
--disable-libunwind-exceptions --disable-nls --enable-fixed-point
--enable-long-long --disable-werror --disable-__cxa_atexit
--enable-checking=release --enable-clocale=gnu
--enable-cloog-backend=isl --enable-gnu-unique-object
--with-avrlibc=yes
--with-dwarf2 --enable-languages=c,c++ --disable-libada --disable-doc
--enable-lto --enable-gold --disable-plugin
--prefix=/home/admin/avr-gcc-5.1.0/pkg-x86_64-unknown-linux-gnu/
--disable-shared --with-gnu-ld --host=x86_64-unknown-linux-gnu
--build=x86_64-unknown-linux-gnu --target=avr
Thread model: single
gcc version 5.1.0 (GCC)
More information about the Gcc-bugs
mailing list