Bootstrapped and regtested on s390x-redhat-linux. r265490 allowed the compiler to choose in a more flexible way whether to use load or load-address-relative-long (LARL) instruction. When it chose LARL for literal pool references, the latter ones were rewritten by pass_s390_early_mach to use UNSPEC_LTREF, which assumes base register usage, which in turn is not compatible with LARL. The end result was an ICE because of unrecognizable insn.
UNSPEC_LTREF and friends are necessary in order to communicate the dependency on the base register to pass_sched2. When LARL is used, no base register is necessary, so in such cases the rewrite must be avoided. gcc/ChangeLog: 2018-10-26 Ilya Leoshkevich <i...@linux.ibm.com> PR target/87762 * config/s390/predicates.md (larl_operand): Use s390_symbol_larl_p () to reduce code duplication. * config/s390/s390-protos.h (s390_symbol_larl_p): New function. * config/s390/s390.c (s390_symbol_larl_p): New function. (s390_larl_pattern_p): New function. (annotate_constant_pool_refs): Do nothing for LARL, do not strip CONST. (annotate_constant_pool_refs_1): New helper function. (find_constant_pool_ref): Handle non-annotated literal pool references, which are usable with LARL. (replace_constant_pool_ref): Do nothing for LARL. (replace_constant_pool_ref_1): New helper function. --- gcc/config/s390/predicates.md | 9 +---- gcc/config/s390/s390-protos.h | 1 + gcc/config/s390/s390.c | 76 +++++++++++++++++++++++++++++------ 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md index 98a824e77b7..0e431302479 100644 --- a/gcc/config/s390/predicates.md +++ b/gcc/config/s390/predicates.md @@ -151,9 +151,7 @@ if (GET_CODE (op) == LABEL_REF) return true; if (SYMBOL_REF_P (op)) - return (!SYMBOL_FLAG_NOTALIGN2_P (op) - && SYMBOL_REF_TLS_MODEL (op) == 0 - && s390_rel_address_ok_p (op)); + return s390_symbol_larl_p (op); /* Everything else must have a CONST, so strip it. */ if (GET_CODE (op) != CONST) @@ -176,10 +174,7 @@ if (GET_CODE (op) == LABEL_REF) return true; if (SYMBOL_REF_P (op)) - return (!SYMBOL_FLAG_NOTALIGN2_P (op) - && SYMBOL_REF_TLS_MODEL (op) == 0 - && s390_rel_address_ok_p (op)); - + return s390_symbol_larl_p (op); /* Now we must have a @GOTENT offset or @PLT stub or an @INDNTPOFF TLS offset. */ diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index 45fce6ce865..6c36428b1c2 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -157,6 +157,7 @@ extern void s390_indirect_branch_via_thunk (unsigned int regno, rtx comparison_operator, enum s390_indirect_branch_type type); extern void s390_indirect_branch_via_inline_thunk (rtx execute_target); +extern bool s390_symbol_larl_p (rtx); #endif /* RTX_CODE */ /* s390-c.c routines */ diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 29a829f48ea..e7a6a1d9775 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -2816,6 +2816,25 @@ s390_decompose_constant_pool_ref (rtx *ref, rtx *disp, bool *is_ptr, return true; } +/* Return true iff SYMBOL_REF X can be used with a LARL instruction. */ + +bool +s390_symbol_larl_p (rtx x) +{ + return (!SYMBOL_FLAG_NOTALIGN2_P (x) + && SYMBOL_REF_TLS_MODEL (x) == 0 + && s390_rel_address_ok_p (x)); +} + +/* Return true iff X is a pattern describing a LARL instruction. */ + +static bool +s390_larl_pattern_p (rtx x) +{ + return (GET_CODE (x) == SET + && larl_operand (SET_SRC (x), VOIDmode)); +} + /* Decompose a RTL expression ADDR for a memory address into its components, returned in OUT. @@ -8111,11 +8130,8 @@ s390_first_cycle_multipass_dfa_lookahead (void) return 4; } -/* Annotate every literal pool reference in X by an UNSPEC_LTREF expression. - Fix up MEMs as required. */ - static void -annotate_constant_pool_refs (rtx *x) +annotate_constant_pool_refs_1 (rtx *x) { int i, j; const char *fmt; @@ -8184,7 +8200,8 @@ annotate_constant_pool_refs (rtx *x) rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base), UNSPEC_LTREF); - SET_SRC (*x) = plus_constant (Pmode, addr, off); + SET_SRC (*x) = gen_rtx_CONST (Pmode, + plus_constant (Pmode, addr, off)); return; } } @@ -8194,16 +8211,28 @@ annotate_constant_pool_refs (rtx *x) { if (fmt[i] == 'e') { - annotate_constant_pool_refs (&XEXP (*x, i)); + annotate_constant_pool_refs_1 (&XEXP (*x, i)); } else if (fmt[i] == 'E') { for (j = 0; j < XVECLEN (*x, i); j++) - annotate_constant_pool_refs (&XVECEXP (*x, i, j)); + annotate_constant_pool_refs_1 (&XVECEXP (*x, i, j)); } } } +/* Annotate every literal pool reference in X by an UNSPEC_LTREF expression. + Fix up MEMs as required. + Do nothing if X is a pattern describing a LARL instruction. */ + +static void +annotate_constant_pool_refs (rtx *x) +{ + if (s390_larl_pattern_p (*x)) + return; + annotate_constant_pool_refs_1 (x); +} + /* Find an annotated literal pool symbol referenced in RTX X, and store it at REF. Will abort if X contains references to more than one such pool symbol; multiple references to the same @@ -8223,6 +8252,18 @@ find_constant_pool_ref (rtx x, rtx *ref) && XINT (x, 1) == UNSPECV_POOL_ENTRY) return; + if (SYMBOL_REF_P (x) + && CONSTANT_POOL_ADDRESS_P (x) + && s390_symbol_larl_p (x)) + { + if (*ref == NULL_RTX) + *ref = x; + else + gcc_assert (*ref == x); + + return; + } + gcc_assert (GET_CODE (x) != SYMBOL_REF || !CONSTANT_POOL_ADDRESS_P (x)); @@ -8255,11 +8296,8 @@ find_constant_pool_ref (rtx x, rtx *ref) } } -/* Replace every reference to the annotated literal pool - symbol REF in X by its base plus OFFSET. */ - static void -replace_constant_pool_ref (rtx *x, rtx ref, rtx offset) +replace_constant_pool_ref_1 (rtx *x, rtx ref, rtx offset) { int i, j; const char *fmt; @@ -8290,16 +8328,28 @@ replace_constant_pool_ref (rtx *x, rtx ref, rtx offset) { if (fmt[i] == 'e') { - replace_constant_pool_ref (&XEXP (*x, i), ref, offset); + replace_constant_pool_ref_1 (&XEXP (*x, i), ref, offset); } else if (fmt[i] == 'E') { for (j = 0; j < XVECLEN (*x, i); j++) - replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset); + replace_constant_pool_ref_1 (&XVECEXP (*x, i, j), ref, offset); } } } +/* Replace every reference to the annotated literal pool + symbol REF in X by its base plus OFFSET. + Do nothing if X is a pattern describing a LARL instruction. */ + +static void +replace_constant_pool_ref (rtx *x, rtx ref, rtx offset) +{ + if (s390_larl_pattern_p (*x)) + return; + replace_constant_pool_ref_1 (x, ref, offset); +} + /* We keep a list of constants which we have to add to internal constant tables in the middle of large functions. */ -- 2.19.0