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

Mikael Pettersson <mikpelinux at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |mikpelinux at gmail dot com

--- Comment #5 from Mikael Pettersson <mikpelinux at gmail dot com> ---
Further reduced test case:

> cat pr108640v2.i 
int x;
void iorsi3(void) { x |= (1 << 16); }
> gcc/xgcc -Bgcc -O1 -S pr108640v2.i
during RTL pass: final
../pr108640v2.i: In function 'iorsi3':
../pr108640v2.i:2:38: internal compiler error: in change_address_1, at
emit-rtl.cc:2299
    2 | void iorsi3(void) { x |=  (1 << 16); }
      |                                      ^
0x40dc15 change_address_1
        /mnt/scratch/other/mikpe-gcc.git/gcc/emit-rtl.cc:2299
0x668f79 adjust_address_1(rtx_def*, machine_mode, poly_int<1u, long>, int, int,
int, poly_int<1u, long>)
        /mnt/scratch/other/mikpe-gcc.git/gcc/emit-rtl.cc:2433
0xd3ae93 output_iorsi3(rtx_def**)
        /mnt/scratch/other/mikpe-gcc.git/gcc/config/m68k/m68k.cc:5513
...

In output_iorsi3() the m68k backend wants to change "x |= (1 << 16)" to
"*(((char *) &x) + 1) |= 1". It calls adjust_address() to offset x by 1, but it
keeps the mode as SImode (4-byte). This address expr reaches
m68k_legitimate_constant_address_p(). On the uclinux target
M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P is 1 so it calls
offset_within_block_p(x, 4) which fails because that is out of bounds, causing
the assert in change_address_1() to fail.

The other m68k targets don't define M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P so
this works there.

The bug is that the adjust_address() call should have specified QImode as mode
since the resulting address is to be used in a 1-byte RMW operation. It gets it
right in the nearby code which rewrites to a HImode (2-byte) RMW.

output_andsi3() and output_xorsi3() have the exact same bug.

I have a patch.

Reply via email to