https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116498
Bug ID: 116498
Summary: gnat enters busy wait trying to compile for
msp430-none-elf with -mlarge flag
Product: gcc
Version: 12.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: ada
Assignee: unassigned at gcc dot gnu.org
Reporter: alancf0 at gmail dot com
CC: dkm at gcc dot gnu.org
Target Milestone: ---
Target: msp430-none-elf
Created attachment 59009
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=59009&action=edit
source files for compiler command
Hello,
First some platform information:
Host: x86_64-linux-gnu (Debian bookworm)
Host complier: gcc 12.2.0
The gcc / gnat at issue is also gcc 12.2.0, configured as:
../configure --prefix=/home/acf/msp430tools --target=msp430-none-elf
--with-newlib --disable-libada --disable-libstdcxx-pch --without-headers
--with-include=../../newlib-4.4.0.20231231/include/ --disable-nls
target_alias=msp430-none-elf --enable-languages=c,ada,c++,lto
This is used with binutils 2.43.1
../configure --prefix=/home/acf/msp430tools --target=msp430-none-elf
And newlib 4.4.0.20231231
../configure --prefix=/home/acf/msp430tools --target=msp430-none-elf
--disable-newlib-supplied-syscalls --enable-newlib-reent-small
--disable-newlib-fseek-optimization --disable-newlib-wide-orient
--enable-newlib-nano-formatted-io --disable-newlib-io-float
--enable-newlib-nano-malloc --disable-newlib-unbuf-stream-opt
--enable-lite-exit --enable-newlib-global-atexit --disable-nls
binutils and newlib build and install as usual; I build gcc with:
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc
make -C gcc cross-gnattools ada.all.cross
make install-gcc
Once gcc is installed, I try to build a file (note the -msmall , selecting
16-bit pointers):
$ /home/acf/msp430tools/bin/msp430-none-elf-gcc -c -x ada -gnatA -gnat2005 -g
-gnatg -gnatec=../gnat.adc -O0 --RTS=../rts/boards/arm -msmall
/home/acf/ada_test/rts/boards/arm/adainclude/system.ads
$
... gcc / gnat compiles file and exits quickly ...
I try to build the same file again with -mlarge (selecting 20-bit pointers)
$ /home/acf/msp430tools/bin/msp430-none-elf-gcc -c -x ada -gnatA -gnat2005 -g
-gnatg -gnatec=../gnat.adc -O0 --RTS=../rts/boards/arm -mlarge
/home/acf/ada_test/rts/boards/arm/adainclude/system.ads
... gcc / gnat hangs forever ...
^C
$
Running under gdb and breaking after a couple of seconds quickly reveals the
problem:
$ gdb /home/acf/msp430tools/bin/msp430-none-elf-gcc
GNU gdb (Debian 13.1-3) 13.1
Copyright (C) 2023 Free Software Foundation, Inc.
[...deleted...]
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /home/acf/msp430tools/bin/msp430-none-elf-gcc...
(gdb) set follow-fork-mode child
(gdb) run -c -x ada -gnatA -gnat2005 -g -gnatg -gnatec=../gnat.adc -O0
--RTS=../rts/boards/arm -mlarge
/home/acf/ada_test/rts/boards/arm/adainclude/system.ads
Starting program: /home/acf/msp430tools/bin/msp430-none-elf-gcc -c -x ada
-gnatA -gnat2005 -g -gnatg -gnatec=../gnat.adc -O0 --RTS=../rts/boards/arm
-mlarge /home/acf/ada_test/rts/boards/arm/adainclude/system.ads
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Attaching after Thread 0x7ffff7db2740 (LWP 1825980) vfork to child process
1825983]
[New inferior 2 (process 1825983)]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Detaching vfork parent process 1825980 after child exec]
[Inferior 1 (process 1825980) detached]
process 1825983 is executing new program:
/home/acf/msp430tools/libexec/gcc/msp430-none-elf/12.2.0/gnat1
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
^C
Thread 2.1 "gnat1" received signal SIGINT, Interrupt.
[Switching to Thread 0x7ffff7c17ac0 (LWP 1825983)]
default_valid_pointer_mode (mode=...) at ../../gcc/machmode.h:421
421 ALWAYS_INLINE CONSTEXPR operator machine_mode () const { return
m_mode; }
(gdb) next
1553 return (mode == ptr_mode || mode == Pmode);
(gdb)
validate_size (uint_size=<optimized out>, gnu_type=<optimized out>,
gnat_object=gnat_object@entry=526, kind=<optimized out>, component_p=<optimized
out>, zero_ok=<optimized out>,
s1=0x18ed708 "size for %s too small{, minimum allowed is ^}", s2=0x194371e
"&") at ../../gcc/ada/gcc-interface/decl.cc:9299
9299 p_mode = GET_MODE_WIDER_MODE (p_mode).require ();
(gdb)
9298 while (!targetm.valid_pointer_mode (p_mode))
(gdb)
9299 p_mode = GET_MODE_WIDER_MODE (p_mode).require ();
(gdb)
9298 while (!targetm.valid_pointer_mode (p_mode))
(gdb)
9299 p_mode = GET_MODE_WIDER_MODE (p_mode).require ();
(gdb)
9298 while (!targetm.valid_pointer_mode (p_mode))
(gdb)
9299 p_mode = GET_MODE_WIDER_MODE (p_mode).require ();
(gdb)
9298 while (!targetm.valid_pointer_mode (p_mode))
(gdb)
9299 p_mode = GET_MODE_WIDER_MODE (p_mode).require ();
(gdb)
The context from the source around decl.cc:9299
/* If this is an access type or a fat pointer, the minimum size is that given
by the smallest integral mode that's valid for pointers. */
if (TREE_CODE (gnu_type) == POINTER_TYPE || TYPE_IS_FAT_POINTER_P (gnu_type))
{
scalar_int_mode p_mode = NARROWEST_INT_MODE;
while (!targetm.valid_pointer_mode (p_mode))
p_mode = GET_MODE_WIDER_MODE (p_mode).require ();
old_size = bitsize_int (GET_MODE_BITSIZE (p_mode));
}
It appears we start at "NARROWEST_INT_MODE" and select a wider mode until we
find one which is a valid pointer mode. Checking the 'mode_wider' table, it
appears that when -mlarge is used, the pointer mode cannot be reached using
this algorithm. Instead the sequence shown below is taken, ending with the VOID
mode being visited repeatedly
const unsigned char mode_wider[NUM_MACHINE_MODES] =
{
E_VOIDmode, /* VOID */ <--------|
E_VOIDmode, /* BLK */ |
E_VOIDmode, /* CC */ |
E_QImode, /* BI */ |
E_HImode, /* QI */ >---| | <- NARROWEST_INT_MODE
E_SImode, /* HI */ <---| >---| |
E_DImode, /* SI */ >---| <---| |
E_TImode, /* DI */ <---| >--------|
E_VOIDmode, /* TI */ <- Pmode (pointer)
E_SImode, /* PSI */
E_HQmode, /* QQ */
...
Changing
scalar_int_mode p_mode = NARROWEST_INT_MODE;
to
scalar_int_mode p_mode = Pmode;
results in gcc / gnat exiting with an error. Disabling several more checks
further down in validate_size() results in gcc finishing without error and
generating a binary. Of course I have no idea if the generated code is correct;
probably not.
Many of these checks / errors seem to indicate a lack of support in gnat for
pointer sizes which are not a multiple of 8 bits, such as "size for ... must be
multiple of Storage_Unit". This will obviously not be the case on platforms
like msp430x with -mlarge where void* is 20 bits, and Storage_Unit is 8 bits.
Are such platforms simply unsupported by gnat? In which case I suppose an error
should be introduced earlier to avoid the busywait. It is also oddly asymmetric
that the compiler can build binaries on the same platform with the -msmall
memory model (with a 16-bit pointer) but not with -mlarge (with a 20-bit
pointer).
NB: I have no experience with gcc internals so maybe be careful when reading my
analysis ;)
Thanks for reading!
All the best,
Alan