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

Reply via email to