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.

Reply via email to