s390-protos.h (s390_load_got): Update prototype.
authorUlrich Weigand <uweigand@de.ibm.com>
Sun, 27 Jun 2004 15:31:53 +0000 (15:31 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Sun, 27 Jun 2004 15:31:53 +0000 (15:31 +0000)
* config/s390/s390-protos.h (s390_load_got): Update prototype.
* config/s390/s390.c (struct machine_function): Add member base_reg.
(s390_decompose_address): Accept UNSPEC_LTREF.  Simplify logic.
(s390_split_branches): Annotate late pool references.
(annotate_constant_pool_refs): New function.
(find_constant_pool_ref): Work on annotated pool references.
(replace_constant_pool_ref): Likewise.  Use explicit base.
(replace_ltrel_base): Use explicit base.
(s390_mainpool_start): Reflect main_pool pattern change.
(s390_mainpool_finish): Use base register from main_pool.
Update calls to replace_ltrel_base and replace_constant_pool_ref.
(s390_chunkify_start): Use base_reg from struct machine_function.
(s390_chunkify_finish): Remove base_reg argument.  Update calls
to replace_ltrel_base and replace_constant_pool_ref.
(s390_reorg): Don't decide upon base register.  Update calls.
(s390_load_got): Remove MAYBE_DEAD handling.  Do not emit insns
but return sequence instead.
(s390_emit_prologue): Decide upon base register to use.  Annotate
all literal pool references.  Adapt to main_pool pattern change.
Update s390_load_got call; move MAYBE_DEAD handling here.
(s390_emit_epilogue): Annotate late literal pool references.
Remove barrier before register restore instruction.
* config/s390/s390.md (UNSPEC_LTREF): New constant.
("builtin_setjmp_receiver"): Update s390_load_got call.
("main_pool"): Explicitly reference base register.

From-SVN: r83735

gcc/ChangeLog
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.md

index 69f8d327c8133e550654ef4d8b3d9efbb1fd89c7..edfb656615c9af7816775e0c3031caf7372d7f95 100644 (file)
@@ -1,3 +1,31 @@
+2004-06-27  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * config/s390/s390-protos.h (s390_load_got): Update prototype.
+       * config/s390/s390.c (struct machine_function): Add member base_reg.
+       (s390_decompose_address): Accept UNSPEC_LTREF.  Simplify logic.
+       (s390_split_branches): Annotate late pool references.
+       (annotate_constant_pool_refs): New function.
+       (find_constant_pool_ref): Work on annotated pool references.
+       (replace_constant_pool_ref): Likewise.  Use explicit base.
+       (replace_ltrel_base): Use explicit base.
+       (s390_mainpool_start): Reflect main_pool pattern change.
+       (s390_mainpool_finish): Use base register from main_pool.
+       Update calls to replace_ltrel_base and replace_constant_pool_ref.
+       (s390_chunkify_start): Use base_reg from struct machine_function.
+       (s390_chunkify_finish): Remove base_reg argument.  Update calls
+       to replace_ltrel_base and replace_constant_pool_ref.
+       (s390_reorg): Don't decide upon base register.  Update calls.
+       (s390_load_got): Remove MAYBE_DEAD handling.  Do not emit insns
+       but return sequence instead.
+       (s390_emit_prologue): Decide upon base register to use.  Annotate
+       all literal pool references.  Adapt to main_pool pattern change.
+       Update s390_load_got call; move MAYBE_DEAD handling here.
+       (s390_emit_epilogue): Annotate late literal pool references.
+       Remove barrier before register restore instruction.
+       * config/s390/s390.md (UNSPEC_LTREF): New constant.
+       ("builtin_setjmp_receiver"): Update s390_load_got call.
+       ("main_pool"): Explicitly reference base register.
+
 2004-06-27  Roger Sayle  <roger@eyesopen.com>
 
        * fold-const.c (fold) <BIT_IOR_EXPR>: Optimize ~X|X and X|~X as -1.
index 16faf39fe26752cb03389bda555cf8931f590d4c..2b835264eb96cd12dcb9238d63671ff768600726 100644 (file)
@@ -24,7 +24,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 extern void optimization_options (int, int);
 extern void override_options (void);
 extern HOST_WIDE_INT s390_arg_frame_offset (void);
-extern void s390_load_got (int);
 extern void s390_emit_prologue (void);
 extern void s390_emit_epilogue (bool);
 extern void s390_function_profiler (FILE *, int);
@@ -92,6 +91,7 @@ extern void s390_initialize_trampoline (rtx, rtx, rtx);
 extern rtx s390_gen_rtx_const_DI (int, int);
 extern void s390_output_dwarf_dtprel (FILE*, int, rtx);
 extern int s390_agen_dep_p (rtx, rtx);
+extern rtx s390_load_got (void);
 
 #endif /* RTX_CODE */
 
index 21cf73e38e283164df77de9456fac905e40cc250..537148e17643d54b8a84fa1a874e636a8ccbce27 100644 (file)
@@ -217,6 +217,9 @@ struct machine_function GTY(())
   /* Size of stack frame.  */
   HOST_WIDE_INT frame_size;
 
+  /* Literal pool base register.  */
+  rtx base_reg;
+
   /* Some local-dynamic TLS symbol name.  */
   const char *some_ld_name;
 };
@@ -236,10 +239,11 @@ static int get_some_local_dynamic_name_1 (rtx *, void *);
 static int reg_used_in_mem_p (int, rtx);
 static int addr_generation_dependency_p (rtx, rtx);
 static int s390_split_branches (void);
+static void annotate_constant_pool_refs (rtx *x);
 static void find_constant_pool_ref (rtx, rtx *);
 static void replace_constant_pool_ref (rtx *, rtx, rtx);
 static rtx find_ltrel_base (rtx);
-static void replace_ltrel_base (rtx *, rtx);
+static void replace_ltrel_base (rtx *);
 static void s390_optimize_prolog (bool);
 static int find_unused_clobbered_reg (void);
 static void s390_frame_info (int, int);
@@ -2069,9 +2073,11 @@ s390_expand_plus_operand (register rtx target, register rtx src,
 static int
 s390_decompose_address (register rtx addr, struct s390_address *out)
 {
+  HOST_WIDE_INT offset = 0;
   rtx base = NULL_RTX;
   rtx indx = NULL_RTX;
   rtx disp = NULL_RTX;
+  rtx orig_disp;
   int pointer = FALSE;
   int base_ptr = FALSE;
   int indx_ptr = FALSE;
@@ -2119,16 +2125,69 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
   else
     disp = addr;               /* displacement */
 
+  /* Extract integer part of displacement.  */
+  orig_disp = disp;
+  if (disp)
+    {
+      if (GET_CODE (disp) == CONST_INT)
+       {
+         offset = INTVAL (disp);
+         disp = NULL_RTX;
+       }
+      else if (GET_CODE (disp) == CONST
+              && GET_CODE (XEXP (disp, 0)) == PLUS
+              && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
+       {
+         offset = INTVAL (XEXP (XEXP (disp, 0), 1));
+         disp = XEXP (XEXP (disp, 0), 0);
+       }
+    }
+
+  /* Strip off CONST here to avoid special case tests later.  */
+  if (disp && GET_CODE (disp) == CONST)
+    disp = XEXP (disp, 0);
+
+  /* We can convert literal pool addresses to
+     displacements by basing them off the base register.  */
+  if (disp && GET_CODE (disp) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (disp))
+    {
+      /* Either base or index must be free to hold the base register.  */
+      if (!base)
+        base = gen_rtx_REG (Pmode, BASE_REGISTER);
+      else if (!indx)
+        indx = gen_rtx_REG (Pmode, BASE_REGISTER);
+      else
+        return FALSE;
+
+      /* Mark up the displacement.  */
+      disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
+                            UNSPEC_LTREL_OFFSET);
+    }
 
   /* Validate base register.  */
   if (base)
     {
       if (GET_CODE (base) == UNSPEC)
-        {
-          if (XVECLEN (base, 0) != 1 || XINT (base, 1) != UNSPEC_LTREL_BASE)
+       switch (XINT (base, 1))
+         {
+         case UNSPEC_LTREF:
+           if (!disp)
+             disp = gen_rtx_UNSPEC (Pmode, 
+                                    gen_rtvec (1, XVECEXP (base, 0, 0)),
+                                    UNSPEC_LTREL_OFFSET);
+           else
+             return FALSE;
+
+           base = gen_rtx_REG (Pmode, BASE_REGISTER);
+           break;
+
+         case UNSPEC_LTREL_BASE:
+           base = gen_rtx_REG (Pmode, BASE_REGISTER);
+           break;
+
+         default:
            return FALSE;
-         base = gen_rtx_REG (Pmode, BASE_REGISTER);
-       }
+         }
 
       if (GET_CODE (base) != REG || GET_MODE (base) != Pmode)
        return FALSE;
@@ -2149,11 +2208,26 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
   if (indx)
     {
       if (GET_CODE (indx) == UNSPEC)
-        {
-          if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != UNSPEC_LTREL_BASE)
+       switch (XINT (indx, 1))
+         {
+         case UNSPEC_LTREF:
+           if (!disp)
+             disp = gen_rtx_UNSPEC (Pmode, 
+                                    gen_rtvec (1, XVECEXP (indx, 0, 0)),
+                                    UNSPEC_LTREL_OFFSET);
+           else
+             return FALSE;
+
+           indx = gen_rtx_REG (Pmode, BASE_REGISTER);
+           break;
+
+         case UNSPEC_LTREL_BASE:
+           indx = gen_rtx_REG (Pmode, BASE_REGISTER);
+           break;
+
+         default:
            return FALSE;
-         indx = gen_rtx_REG (Pmode, BASE_REGISTER);
-       }
+         }
 
       if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode)
        return FALSE;
@@ -2180,106 +2254,63 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
     }
 
   /* Validate displacement.  */
-  if (disp)
+  if (!disp)
     {
-      /* Allow integer constant in range.  */
-      if (GET_CODE (disp) == CONST_INT)
-        {
-         /* If the argument pointer is involved, the displacement will change
-            later anyway as the argument pointer gets eliminated.  This could
-            make a valid displacement invalid, but it is more likely to make
-            an invalid displacement valid, because we sometimes access the
-            register save area via negative offsets to the arg pointer.
-            Thus we don't check the displacement for validity here.  If after
-            elimination the displacement turns out to be invalid after all,
-            this is fixed up by reload in any case.  */
-         if (base != arg_pointer_rtx && indx != arg_pointer_rtx)
-           {
-             if (!DISP_IN_RANGE (INTVAL (disp)))
-               return FALSE;
-           }
-        }
+      /* If the argument pointer is involved, the displacement will change
+        later anyway as the argument pointer gets eliminated.  This could
+        make a valid displacement invalid, but it is more likely to make
+        an invalid displacement valid, because we sometimes access the
+        register save area via negative offsets to the arg pointer.
+        Thus we don't check the displacement for validity here.  If after
+        elimination the displacement turns out to be invalid after all,
+        this is fixed up by reload in any case.  */
+      if (base != arg_pointer_rtx && indx != arg_pointer_rtx)
+       if (!DISP_IN_RANGE (offset))
+         return FALSE;
+    }
+  else
+    {
+      /* All the special cases are pointers.  */
+      pointer = TRUE;
 
       /* In the small-PIC case, the linker converts @GOT
          and @GOTNTPOFF offsets to possible displacements.  */
-      else if (GET_CODE (disp) == CONST
-               && GET_CODE (XEXP (disp, 0)) == UNSPEC
-               && (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT
-                  || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF))
+      if (GET_CODE (disp) == UNSPEC
+          && (XINT (disp, 1) == UNSPEC_GOT
+             || XINT (disp, 1) == UNSPEC_GOTNTPOFF)
+         && offset == 0
+         && flag_pic == 1)
         {
-          if (flag_pic != 1)
-            return FALSE;
-
-         pointer = TRUE;
+         ;
         }
 
-      /* Accept chunkfied literal pool symbol references.  */
-      else if (GET_CODE (disp) == CONST
-               && GET_CODE (XEXP (disp, 0)) == MINUS
-               && GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF
-               && GET_CODE (XEXP (XEXP (disp, 0), 1)) == LABEL_REF)
+      /* Accept chunkified literal pool symbol references.  */
+      else if (GET_CODE (disp) == MINUS
+               && GET_CODE (XEXP (disp, 0)) == LABEL_REF
+               && GET_CODE (XEXP (disp, 1)) == LABEL_REF)
         {
-         pointer = TRUE;
+         ;
         }
 
-      /* Likewise if a constant offset is present.  */
-      else if (GET_CODE (disp) == CONST
-               && GET_CODE (XEXP (disp, 0)) == PLUS
-               && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT
-               && GET_CODE (XEXP (XEXP (disp, 0), 0)) == MINUS
-               && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 0)) == LABEL_REF
-               && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 1)) == LABEL_REF)
+      /* Accept literal pool references.  */
+      else if (GET_CODE (disp) == UNSPEC
+              && XINT (disp, 1) == UNSPEC_LTREL_OFFSET)
         {
-         pointer = TRUE;
+         orig_disp = gen_rtx_CONST (Pmode, disp);
+         if (offset)
+           {
+             /* If we have an offset, make sure it does not
+                exceed the size of the constant pool entry.  */
+             rtx sym = XVECEXP (disp, 0, 0);
+             if (offset >= GET_MODE_SIZE (get_pool_mode (sym)))
+               return FALSE;
+
+              orig_disp = plus_constant (orig_disp, offset);
+           }
         }
 
-      /* We can convert literal pool addresses to
-         displacements by basing them off the base register.  */
       else
-        {
-          /* In some cases, we can accept an additional
-             small constant offset.  Split these off here.  */
-
-          unsigned int offset = 0;
-
-          if (GET_CODE (disp) == CONST
-              && GET_CODE (XEXP (disp, 0)) == PLUS
-              && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
-            {
-              offset = INTVAL (XEXP (XEXP (disp, 0), 1));
-              disp = XEXP (XEXP (disp, 0), 0);
-            }
-
-          /* Now we must have a literal pool address.  */
-          if (GET_CODE (disp) != SYMBOL_REF
-              || !CONSTANT_POOL_ADDRESS_P (disp))
-            return FALSE;
-
-          /* If we have an offset, make sure it does not
-             exceed the size of the constant pool entry.  */
-          if (offset && offset >= GET_MODE_SIZE (get_pool_mode (disp)))
-            return FALSE;
-
-          /* Either base or index must be free to
-             hold the base register.  */
-          if (base && indx)
-            return FALSE;
-
-          /* Convert the address.  */
-          if (base)
-            indx = gen_rtx_REG (Pmode, BASE_REGISTER);
-          else
-            base = gen_rtx_REG (Pmode, BASE_REGISTER);
-
-          disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
-                                UNSPEC_LTREL_OFFSET);
-          disp = gen_rtx_CONST (Pmode, disp);
-
-          if (offset)
-            disp = plus_constant (disp, offset);
-
-         pointer = TRUE;
-        }
+       return FALSE;
     }
 
   if (!base && !indx)
@@ -2289,7 +2320,7 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
     {
       out->base = base;
       out->indx = indx;
-      out->disp = disp;
+      out->disp = orig_disp;
       out->pointer = pointer;
     }
 
@@ -4058,6 +4089,7 @@ s390_split_branches (void)
          tmp = force_const_mem (Pmode, *label);
          tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
          INSN_ADDRESSES_NEW (tmp, -1);
+         annotate_constant_pool_refs (&PATTERN (tmp));
 
          target = temp_reg;
        }
@@ -4070,8 +4102,10 @@ s390_split_branches (void)
          target = force_const_mem (Pmode, target);
          tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn);
          INSN_ADDRESSES_NEW (tmp, -1);
+         annotate_constant_pool_refs (&PATTERN (tmp));
 
-          target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (target, 0)),
+          target = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XEXP (target, 0),
+                                                       cfun->machine->base_reg),
                                   UNSPEC_LTREL_BASE);
          target = gen_rtx_PLUS (Pmode, temp_reg, target);
        }
@@ -4083,11 +4117,115 @@ s390_split_branches (void)
   return new_literal;
 }
 
+/* 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)
+{
+  int i, j;
+  const char *fmt;
+
+  if (GET_CODE (*x) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (*x))
+    abort ();
+
+  /* Literal pool references can only occur inside a MEM ...  */
+  if (GET_CODE (*x) == MEM)
+    {
+      rtx memref = XEXP (*x, 0);
+
+      if (GET_CODE (memref) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (memref))
+       {
+         rtx base = cfun->machine->base_reg;
+         rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, memref, base),
+                                    UNSPEC_LTREF);
+
+         *x = replace_equiv_address (*x, addr);
+         return;
+       }
+
+      if (GET_CODE (memref) == CONST
+         && GET_CODE (XEXP (memref, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (memref, 0), 1)) == CONST_INT
+         && GET_CODE (XEXP (XEXP (memref, 0), 0)) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (memref, 0), 0)))
+       {
+         HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1));
+         rtx sym = XEXP (XEXP (memref, 0), 0);
+         rtx base = cfun->machine->base_reg;
+         rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base),
+                                    UNSPEC_LTREF);
+
+         *x = replace_equiv_address (*x, plus_constant (addr, off));
+         return;
+       }
+    }
+
+  /* ... or a load-address type pattern.  */
+  if (GET_CODE (*x) == SET)
+    {
+      rtx addrref = SET_SRC (*x);
+
+      if (GET_CODE (addrref) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (addrref))
+       {
+         rtx base = cfun->machine->base_reg;
+         rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addrref, base),
+                                    UNSPEC_LTREF);
+
+         SET_SRC (*x) = addr;
+         return;
+       }
+
+      if (GET_CODE (addrref) == CONST
+         && GET_CODE (XEXP (addrref, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (addrref, 0), 1)) == CONST_INT
+         && GET_CODE (XEXP (XEXP (addrref, 0), 0)) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (addrref, 0), 0)))
+       {
+         HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
+         rtx sym = XEXP (XEXP (addrref, 0), 0);
+         rtx base = cfun->machine->base_reg;
+         rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base),
+                                    UNSPEC_LTREF);
+
+         SET_SRC (*x) = plus_constant (addr, off);
+         return;
+       }
+    }
+
+  /* Annotate LTREL_BASE as well.  */
+  if (GET_CODE (*x) == UNSPEC
+      && XINT (*x, 1) == UNSPEC_LTREL_BASE)
+    {
+      rtx base = cfun->machine->base_reg;
+      *x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XVECEXP (*x, 0, 0), base),
+                                 UNSPEC_LTREL_BASE);
+      return;
+    }
+
+  fmt = GET_RTX_FORMAT (GET_CODE (*x));
+  for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+        {
+          annotate_constant_pool_refs (&XEXP (*x, i));
+        }
+      else if (fmt[i] == 'E')
+        {
+          for (j = 0; j < XVECLEN (*x, i); j++)
+            annotate_constant_pool_refs (&XVECEXP (*x, i, j));
+        }
+    }
+}
+
 
-/* Find a 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 symbol
-   are allowed, however.
+/* 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
+   symbol are allowed, however.
 
    The rtx pointed to by REF must be initialized to NULL_RTX
    by the caller before calling this routine.  */
@@ -4109,11 +4247,21 @@ find_constant_pool_ref (rtx x, rtx *ref)
 
   if (GET_CODE (x) == SYMBOL_REF
       && CONSTANT_POOL_ADDRESS_P (x))
+    abort ();
+
+  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_LTREF)
     {
+      rtx sym = XVECEXP (x, 0, 0);
+      if (GET_CODE (sym) != SYMBOL_REF
+         || !CONSTANT_POOL_ADDRESS_P (sym))
+       abort ();
+
       if (*ref == NULL_RTX)
-        *ref = x;
-      else if (*ref != x)
-        abort();
+       *ref = sym;
+      else if (*ref != sym)
+       abort ();
+
+      return;
     }
 
   fmt = GET_RTX_FORMAT (GET_CODE (x));
@@ -4131,11 +4279,11 @@ find_constant_pool_ref (rtx x, rtx *ref)
     }
 }
 
-/* Replace every reference to the literal pool symbol REF
-   in X by the address ADDR.  Fix up MEMs as required.  */
+/* 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 addr)
+replace_constant_pool_ref (rtx *x, rtx ref, rtx offset)
 {
   int i, j;
   const char *fmt;
@@ -4143,48 +4291,23 @@ replace_constant_pool_ref (rtx *x, rtx ref, rtx addr)
   if (*x == ref)
     abort ();
 
-  /* Literal pool references can only occur inside a MEM ...  */
-  if (GET_CODE (*x) == MEM)
+  if (GET_CODE (*x) == UNSPEC
+      && XINT (*x, 1) == UNSPEC_LTREF
+      && XVECEXP (*x, 0, 0) == ref)
     {
-      rtx memref = XEXP (*x, 0);
-
-      if (memref == ref)
-       {
-         *x = replace_equiv_address (*x, addr);
-         return;
-       }
-
-      if (GET_CODE (memref) == CONST
-         && GET_CODE (XEXP (memref, 0)) == PLUS
-         && GET_CODE (XEXP (XEXP (memref, 0), 1)) == CONST_INT
-         && XEXP (XEXP (memref, 0), 0) == ref)
-       {
-         HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1));
-         *x = replace_equiv_address (*x, plus_constant (addr, off));
-         return;
-       }
+      *x = gen_rtx_PLUS (Pmode, XVECEXP (*x, 0, 1), offset);
+      return;
     }
 
-  /* ... or a load-address type pattern.  */
-  if (GET_CODE (*x) == SET)
+  if (GET_CODE (*x) == PLUS
+      && GET_CODE (XEXP (*x, 1)) == CONST_INT
+      && GET_CODE (XEXP (*x, 0)) == UNSPEC
+      && XINT (XEXP (*x, 0), 1) == UNSPEC_LTREF
+      && XVECEXP (XEXP (*x, 0), 0, 0) == ref)
     {
-      rtx addrref = SET_SRC (*x);
-
-      if (addrref == ref)
-       {
-         SET_SRC (*x) = addr;
-         return;
-       }
-
-      if (GET_CODE (addrref) == CONST
-         && GET_CODE (XEXP (addrref, 0)) == PLUS
-         && GET_CODE (XEXP (XEXP (addrref, 0), 1)) == CONST_INT
-         && XEXP (XEXP (addrref, 0), 0) == ref)
-       {
-         HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
-         SET_SRC (*x) = plus_constant (addr, off);
-         return;
-       }
+      rtx addr = gen_rtx_PLUS (Pmode, XVECEXP (XEXP (*x, 0), 0, 1), offset);
+      *x = plus_constant (addr, INTVAL (XEXP (*x, 1)));
+      return;
     }
 
   fmt = GET_RTX_FORMAT (GET_CODE (*x));
@@ -4192,12 +4315,12 @@ replace_constant_pool_ref (rtx *x, rtx ref, rtx addr)
     {
       if (fmt[i] == 'e')
         {
-          replace_constant_pool_ref (&XEXP (*x, i), ref, addr);
+          replace_constant_pool_ref (&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, addr);
+            replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset);
         }
     }
 }
@@ -4238,10 +4361,10 @@ find_ltrel_base (rtx x)
   return NULL_RTX;
 }
 
-/* Replace any occurrence of UNSPEC_LTREL_BASE in X with BASE.  */
+/* Replace any occurrence of UNSPEC_LTREL_BASE in X with its base.  */
 
 static void
-replace_ltrel_base (rtx *x, rtx base)
+replace_ltrel_base (rtx *x)
 {
   int i, j;
   const char *fmt;
@@ -4249,7 +4372,7 @@ replace_ltrel_base (rtx *x, rtx base)
   if (GET_CODE (*x) == UNSPEC
       && XINT (*x, 1) == UNSPEC_LTREL_BASE)
     {
-      *x = base;
+      *x = XVECEXP (*x, 0, 1);
       return;
     }
 
@@ -4258,12 +4381,12 @@ replace_ltrel_base (rtx *x, rtx base)
     {
       if (fmt[i] == 'e')
         {
-          replace_ltrel_base (&XEXP (*x, i), base);
+          replace_ltrel_base (&XEXP (*x, i));
         }
       else if (fmt[i] == 'E')
         {
           for (j = 0; j < XVECLEN (*x, i); j++)
-            replace_ltrel_base (&XVECEXP (*x, i, j), base);
+            replace_ltrel_base (&XVECEXP (*x, i, j));
         }
     }
 }
@@ -4302,11 +4425,11 @@ struct constant_pool
 };
 
 static struct constant_pool * s390_mainpool_start (void);
-static void s390_mainpool_finish (struct constant_pool *, rtx base_reg);
+static void s390_mainpool_finish (struct constant_pool *);
 static void s390_mainpool_cancel (struct constant_pool *);
 
-static struct constant_pool * s390_chunkify_start (rtx base_reg);
-static void s390_chunkify_finish (struct constant_pool *, rtx base_reg);
+static struct constant_pool * s390_chunkify_start (void);
+static void s390_chunkify_finish (struct constant_pool *);
 static void s390_chunkify_cancel (struct constant_pool *);
 
 static struct constant_pool *s390_start_pool (struct constant_pool **, rtx);
@@ -4560,8 +4683,9 @@ s390_mainpool_start (void)
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
       if (GET_CODE (insn) == INSN
-         && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
-         && XINT (PATTERN (insn), 1) == UNSPECV_MAIN_POOL)
+         && GET_CODE (PATTERN (insn)) == SET
+         && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC_VOLATILE
+         && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPECV_MAIN_POOL)
        {
          if (pool->pool_insn)
            abort ();
@@ -4599,12 +4723,12 @@ s390_mainpool_start (void)
 
 /* POOL holds the main literal pool as collected by s390_mainpool_start.
    Modify the current function to output the pool constants as well as
-   the pool register setup instruction.  BASE_REG is the register to
-   be used as pool base register.  */
+   the pool register setup instruction.  */
 
 static void
-s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
+s390_mainpool_finish (struct constant_pool *pool)
 {
+  rtx base_reg = SET_DEST (PATTERN (pool->pool_insn));
   rtx insn;
 
   /* If the pool is empty, we're done.  */
@@ -4684,7 +4808,7 @@ s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
       if (INSN_P (insn))
-       replace_ltrel_base (&PATTERN (insn), base_reg);
+       replace_ltrel_base (&PATTERN (insn));
 
       if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
         {
@@ -4694,7 +4818,6 @@ s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
             {
               addr = s390_find_constant (pool, get_pool_constant (pool_ref),
                                                get_pool_mode (pool_ref));
-              addr = gen_rtx_PLUS (Pmode, base_reg, addr);
               replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
               INSN_CODE (insn) = -1;
             }
@@ -4718,14 +4841,13 @@ s390_mainpool_cancel (struct constant_pool *pool)
 }
 
 
-/* Chunkify the literal pool.  BASE_REG is to be used as pool
-   register.  */
+/* Chunkify the literal pool.  */
 
 #define S390_POOL_CHUNK_MIN    0xc00
 #define S390_POOL_CHUNK_MAX    0xe00
 
 static struct constant_pool *
-s390_chunkify_start (rtx base_reg)
+s390_chunkify_start (void)
 {
   struct constant_pool *curr_pool = NULL, *pool_list = NULL;
   int extra_size = 0;
@@ -4952,7 +5074,8 @@ s390_chunkify_start (rtx base_reg)
 
   for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
     {
-      rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
+      rtx new_insn = gen_reload_base (cfun->machine->base_reg, 
+                                     curr_pool->label);
       rtx insn = curr_pool->first_insn;
       INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
     }
@@ -4966,7 +5089,8 @@ s390_chunkify_start (rtx base_reg)
        struct constant_pool *pool = s390_find_pool (pool_list, insn);
        if (pool)
          {
-           rtx new_insn = gen_reload_base (base_reg, pool->label);
+           rtx new_insn = gen_reload_base (cfun->machine->base_reg, 
+                                           pool->label);
            INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
          }
       }
@@ -4985,11 +5109,10 @@ s390_chunkify_start (rtx base_reg)
 
 /* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
    After we have decided to use this list, finish implementing
-   all changes to the current function as required.  BASE_REG is
-   to be used as pool base register.  */
+   all changes to the current function as required.  */
 
 static void
-s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
+s390_chunkify_finish (struct constant_pool *pool_list)
 {
   struct constant_pool *curr_pool = NULL;
   rtx insn;
@@ -5000,7 +5123,7 @@ s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
       if (INSN_P (insn))
-       replace_ltrel_base (&PATTERN (insn), base_reg);
+       replace_ltrel_base (&PATTERN (insn));
 
       curr_pool = s390_find_pool (pool_list, insn);
       if (!curr_pool)
@@ -5014,7 +5137,6 @@ s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
             {
               addr = s390_find_constant (curr_pool, get_pool_constant (pool_ref),
                                                     get_pool_mode (pool_ref));
-              addr = gen_rtx_PLUS (Pmode, base_reg, addr);
               replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
               INSN_CODE (insn) = -1;
             }
@@ -5273,7 +5395,6 @@ s390_optimize_prolog (bool base_used)
 static void
 s390_reorg (void)
 {
-  rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
   bool base_used = false;
   bool pool_overflow = false;
 
@@ -5282,12 +5403,6 @@ s390_reorg (void)
   split_all_insns_noflow ();
 
 
-  /* In small leaf functions, try to use an unused call-clobbered
-     register as base register to avoid save/restore overhead.  */
-  if (current_function_is_leaf && !regs_ever_live[5])
-    base_reg = gen_rtx_REG (Pmode, 5);
-
-
   /* Install the main literal pool and the associated base
      register load insns.
 
@@ -5335,7 +5450,7 @@ s390_reorg (void)
 
       /* If literal pool overflowed, start to chunkify it.  */
       if (pool_overflow)
-        pool = s390_chunkify_start (base_reg);
+        pool = s390_chunkify_start ();
 
       /* Split out-of-range branches.  If this has created new
         literal pool entries, cancel current chunk list and
@@ -5354,13 +5469,13 @@ s390_reorg (void)
       /* If we made it up to here, both conditions are satisfied.
         Finish up literal pool related changes.  */
       if ((pool_overflow || pool->size > 0)
-          && REGNO (base_reg) == BASE_REGISTER)
+          && REGNO (cfun->machine->base_reg) == BASE_REGISTER)
        base_used = true;
 
       if (pool_overflow)
-       s390_chunkify_finish (pool, base_reg);
+       s390_chunkify_finish (pool);
       else
-       s390_mainpool_finish (pool, base_reg);
+       s390_mainpool_finish (pool);
 
       break;
     }
@@ -5649,49 +5764,47 @@ restore_gprs (rtx base, int offset, int first, int last)
   return insn;
 }
 
-/* Emit code to load the GOT register.  If MAYBE_DEAD is true,
-   annotate generated insns with REG_MAYBE_DEAD notes.  */
+/* Return insn sequence to load the GOT register.  */
 
 static GTY(()) rtx got_symbol;
-void
-s390_load_got (int maybe_dead)
+rtx
+s390_load_got (void)
 {
+  rtx insns;
+
   if (!got_symbol)
     {
       got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
       SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL;
     }
 
+  start_sequence ();
+
   if (TARGET_CPU_ZARCH)
     {
-      rtx insn = emit_move_insn (pic_offset_table_rtx, got_symbol);
-      if (maybe_dead)
-        REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
-                                             REG_NOTES (insn));
+      emit_move_insn (pic_offset_table_rtx, got_symbol);
     }
   else
     {
-      rtx offset, insn;
+      rtx offset;
 
       offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol),
                               UNSPEC_LTREL_OFFSET);
       offset = gen_rtx_CONST (Pmode, offset);
       offset = force_const_mem (Pmode, offset);
 
-      insn = emit_move_insn (pic_offset_table_rtx, offset);
-      if (maybe_dead)
-       REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
-                                            REG_NOTES (insn));
+      emit_move_insn (pic_offset_table_rtx, offset);
 
       offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)),
                               UNSPEC_LTREL_BASE);
       offset = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset);
 
-      insn = emit_move_insn (pic_offset_table_rtx, offset);
-      if (maybe_dead)
-       REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
-                                            REG_NOTES (insn));
+      emit_move_insn (pic_offset_table_rtx, offset);
     }
+
+  insns = get_insns ();
+  end_sequence ();
+  return insns;
 }
 
 /* Expand the prologue into a bunch of separate insns.  */
@@ -5712,6 +5825,17 @@ s390_emit_prologue (void)
       || regs_ever_live[RETURN_REGNUM])
     cfun->machine->save_return_addr_p = 1;
 
+  /* Decide which register to use as literal pool base.  In small leaf 
+     functions, try to use an unused call-clobbered register as base 
+     register to avoid save/restore overhead.  */
+
+  if (current_function_is_leaf && !regs_ever_live[5])
+    cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
+  else
+    cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
+
+  regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
+
   /* Compute frame info.  Note that at this point, we assume the base 
      register and -on S/390- the return register always need to be saved.
      This is done because the usage of these registers might change even 
@@ -5727,6 +5851,17 @@ s390_emit_prologue (void)
                                  || cfun->machine->save_return_addr_p;
   regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
 
+  /* Annotate all constant pool references to let the scheduler know
+     they implicitly use the base register.  */
+
+  push_topmost_sequence ();
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      annotate_constant_pool_refs (&PATTERN (insn));
+
+  pop_topmost_sequence ();
+
   /* Choose best register to use for temp use within prologue.
      See below for why TPF must use the register 1.  */
 
@@ -5744,7 +5879,7 @@ s390_emit_prologue (void)
 
   /* Dummy insn to mark literal pool slot.  */
 
-  emit_insn (gen_main_pool ());
+  emit_insn (gen_main_pool (cfun->machine->base_reg));
 
   /* Save fprs for variable args.  */
 
@@ -5790,6 +5925,7 @@ s390_emit_prologue (void)
            frame_off = force_const_mem (Pmode, frame_off);
 
           insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
+         annotate_constant_pool_refs (&PATTERN (insn));
        }
 
       RTX_FRAME_RELATED_P (insn) = 1;
@@ -5854,7 +5990,19 @@ s390_emit_prologue (void)
   /* Set up got pointer, if needed.  */
 
   if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
-    s390_load_got(true);
+    {
+      rtx insns = s390_load_got ();
+
+      for (insn = insns; insn; insn = NEXT_INSN (insn))
+       {
+         annotate_constant_pool_refs (&PATTERN (insn));
+
+         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
+                                               REG_NOTES (insn));
+       }
+
+      emit_insn (insns);
+    }
 
   if (TARGET_TPF_PROFILING)
     {
@@ -5965,6 +6113,7 @@ s390_emit_epilogue (bool sibcall)
            frame_off = force_const_mem (Pmode, frame_off);
 
          insn = emit_insn (gen_add2_insn (frame_pointer, frame_off));
+         annotate_constant_pool_refs (&PATTERN (insn));
        }
     }
 
@@ -6044,12 +6193,6 @@ s390_emit_epilogue (bool sibcall)
            }
        }
 
-      /* ??? As references to the base register are not made
-        explicit in insn RTX code, we have to add a barrier here
-        to prevent incorrect scheduling.  */
-
-      emit_insn (gen_blockage());
-
       insn = restore_gprs (frame_pointer, offset,
                           cfun->machine->first_restore_gpr,
                           cfun->machine->last_restore_gpr);
index b907d102cb5658c23f83415fed10ab8add75a407..e2a026215227ada2831c976275ac4d73168298ad 100644 (file)
@@ -92,6 +92,7 @@
    ; Literal pool
    (UNSPEC_RELOAD_BASE         210)
    (UNSPEC_MAIN_BASE           211)
+   (UNSPEC_LTREF               212)
 
    ; TLS relocation specifiers
    (UNSPEC_TLSGD               500)
   [(match_operand 0 "" "")]
   "flag_pic"
 {
-  s390_load_got (false);
+  emit_insn (s390_load_got ());
   emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
   DONE;
 })
    (set_attr "type"    "larl")])
 
 (define_insn "main_pool"
-  [(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)]
-  ""
+  [(set (match_operand 0 "register_operand" "=a")
+        (unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL))]
+  "GET_MODE (operands[0]) == Pmode"
   "* abort ();"
   [(set_attr "op_type" "NN")])