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

            Bug ID: 126985
           Summary: GCC 16.1.0 sparc64 ICE while compiling LLVM 22:
                    LABEL_REF in UNSPEC_MOVE_GOTDATA rejected by
                    sparc_delegitimize_address
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: bootstrap
          Assignee: unassigned at gcc dot gnu.org
          Reporter: kirill at korins dot ky
  Target Milestone: ---

GCC 16.1.0 crashes during RTL combine while compiling LLVM 22 for
sparc64 PIC:

  during RTL pass: combine
  internal compiler error: in sparc_delegitimize_address, at
config/sparc/sparc.cc

The SPARC backend has a contract mismatch.
sparc_legitimize_pic_address accepts SYMBOL_REF or LABEL_REF:

  if (GET_CODE (orig) == SYMBOL_REF
      || (GET_CODE (orig) == LABEL_REF
          && !can_use_mov_pic_label_ref (orig)))

For large PIC, it passes orig unchanged to the GOTDATA instruction:

  gen_movdi_pic_gotdata_op (reg, pic_offset_table_rtx, address, orig)

The pattern declares the final operand as symbolic_operand:

  (match_operand 3 "symbolic_operand" "")

symbolic_operand accepts SYMBOL_REF, LABEL_REF, and CONST; a LABEL_REF
in UNSPEC_MOVE_GOTDATA is therefore valid RTL.

During combine, sparc_delegitimize_address extracts orig, then wrongly
asserts that it is a SYMBOL_REF:

  case UNSPEC_MOVE_GOTDATA:
    x = XVECEXP (x, 0, 2);
    gcc_assert (GET_CODE (x) == SYMBOL_REF);
    break;

A LABEL_REF trips this assertion.

UNSPEC_MOVE_PIC has the same mismatch: its generators receive
SYMBOL_REF or LABEL_REF, but the delegitimizer groups it with
UNSPEC_TLSLE and requires SYMBOL_REF for both.

Separate the PIC and TLS cases:

  case UNSPEC_MOVE_PIC:
    x = XVECEXP (x, 0, 0);
    gcc_assert (GET_CODE (x) == SYMBOL_REF
                || GET_CODE (x) == LABEL_REF);
    break;

  case UNSPEC_TLSLE:
    x = XVECEXP (x, 0, 0);
    gcc_assert (GET_CODE (x) == SYMBOL_REF);
    break;

  case UNSPEC_MOVE_GOTDATA:
    x = XVECEXP (x, 0, 2);
    gcc_assert (GET_CODE (x) == SYMBOL_REF
                || GET_CODE (x) == LABEL_REF);
    break;

This aligns the PIC consumers with their generators while preserving
UNSPEC_TLSLE's SYMBOL_REF invariant.

Reply via email to