diff mbox series

S/390: Allow LARL of literal pool entries

Message ID 20181029092145.6243-1-iii@linux.ibm.com
State New
Headers show
Series S/390: Allow LARL of literal pool entries | expand

Commit Message

Ilya Leoshkevich Oct. 29, 2018, 9:21 a.m. UTC
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  <iii@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 mbox series

Patch

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.  */