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.