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