https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127639
Bug ID: 127639
Summary: [SH] ICE in change_address_1 printing %T/%R/%S of an
indexed asm memory operand
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: kmehltretter at googlemail dot com
Target Milestone: ---
Created attachment 65709
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65709&action=edit
testcase, fails with -O2
The %T operand modifier (and %R or %S, whichever selects the word at
offset 4) crashes the SH backend when the memory operand of an inline
asm gets an indexed @(r0,Rn) address. There is no valid SH address for
"that address plus 4", and GCC hits an assertion instead of reporting
an error.
struct large { unsigned long buf[100]; };
void f(unsigned long long *p, const int *idx, unsigned long long v)
{
__asm__ __volatile__("mov.l %S0,%1\n\tmov.l %R0,%T1"
: : "r" (v), "m" (*(struct large *)(p + *idx))
: "memory");
}
$ sh4-linux-gnu-gcc -O2 -c pr-sh-T-ice.c
during RTL pass: final
pr-sh-T-ice.c: In function 'f':
pr-sh-T-ice.c:10:1: internal compiler error: in change_address_1, at
emit-rtl.cc:2299
Fails on trunk (17.0.0 20260928, 3f1743f5e, sh4-linux cross, -ml and
-mb), with 8.1.0, 11.2.1, 14.3.0 and 15.2.0 locally (both -ml and -mb,
-m2 and -m4), and with 9.5.0, 15.2.0 and 16.1.0 on Compiler Explorer.
-O0 does not fail. Trunk backtrace:
internal compiler error: in change_address_1, at emit-rtl.cc:2316
change_address_1 ../../src/gcc/emit-rtl.cc:2316
adjust_address_1 ../../src/gcc/emit-rtl.cc:2450
sh_print_operand ../../src/gcc/config/sh/sh.cc:1270
output_operand ../../src/gcc/final.cc:3650
output_asm_insn ../../src/gcc/final.cc:3539
final_scan_insn_1 ../../src/gcc/final.cc:2646
In the final pass the operand is
(mem:BLK (plus:SI (reg:SI 1 r1) (reg:SI 0 r0)) ...)
and sh_print_operand() handles 'T' (and 'R'/'S') on a MEM with
x = adjust_address (x, SImode, 4);
change_address_1() then asserts, because (plus (plus r1 r0) 4) is not a
valid address. The BLK mode matters: with a plain "m" (p[*idx])
(DImode) the address is not indexed and there is no ICE.
The asm is arguably wrong, since "m" does not promise an offsettable
address, and with "o" the testcase compiles. But GCC should report it,
for example through output_operand_lossage(), rather than ICE. PR116539
is the same kind of problem for an unknown modifier (a gcc_assert in
sh_print_operand() that should be output_operand_lossage()). Here the
modifier is valid but the operand cannot be printed with it.
This was found building Linux v7.3-rc4 for SH (j2_defconfig): the 64-bit
get_user()/put_user() asm in arch/sh/include/asm/uaccess_32.h prints %T
of an "m" operand of type struct __large_struct, and kernel/nstree.c
triggers the ICE with every GCC listed above.