S/390: More literal pool overflow fixes

Ulrich Weigand Ulrich.Weigand@de.ibm.com
Tue Oct 15 09:41:00 GMT 2002


Hello,

I've committed the following patch to fix a couple of problems
that could occur if a literal pool overflow happened.

The core problems with the existing code were that it didn't
consider the cases where a literal pool overflow could be
caused by the additional literal generated by the branch-splitting
pass.  Also, the use of register 14 as temp register could in
certain rare cases interfere with the use of reg 14 to implement
__builtin_return_address.

This patch should finally solve the problem completely; in any
case it survives a full bootstrap and regression test with the
maximum literal pool size artificially reduced to 16 bytes
(instead of the real 4096 bytes), so this should have flushed
out most potential problems ...

The approach taken here was to only change code that is involved
with literal pool overflow handling; this is to avoid potentially
introducing problems at this point in the 3.3 release process.
Some of the issues are more cleanly fixed by moving some changes
to the common code, but this will be done for 3.4.


ChangeLog:

      * config/s390/s390.c (s390_split_branches): Add return
      value.  Add parameters TEMP_REG and TEMP_USED.  Use unspec 104.

      (find_base_register_in_addr): New function.
      (find_base_register_ref): New function.
      (replace_base_register_ref): New function.

      (struct constant_pool): Add members pool_insn, insns, and anchor.
      Remove member last_insn.
      (s390_start_pool): Initialize them.
      (s390_end_pool): Emit pool placeholder insn.
      (s390_add_pool_insn): New function.
      (s390_find_pool): Use insns bitmap instead of addresses.
      (s390_dump_pool): Replace placeholder insn.  Emit anchor.
      Replace unspec 104 by local-pool-relative references.
      (s390_output_constant_pool): Output anchor label if required.
      (s390_output_symbolic_const): Handle unspec 104 and 105.
      (s390_add_pool): Remove, replace by ...
      (s390_add_constant, s390_find_constant): ... these new functions.
      (s390_add_anchor): New function.

      (s390_chunkify_pool): Delete, replace by ...
      (s390_chunkify_start, s390_chunkify_finish,
      s390_chunkify_cancel): ... these new functions.
      (s390_optimize_prolog): Add parameter TEMP_REGNO.
      Recompute register live data for special registers.
      (s390_fixup_clobbered_return_reg): New function.
      (s390_machine_dependent_reorg): Rewrite to use new
      s390_chunkify_... routines.

      config/s390/s390.md ("reload_base"): Rename to ...
      ("reload_base_31"): ... this.
      ("reload_base_64"): New insn.
      ("reload_base2"): Remove.
      ("reload_anchor"): New insn.
      ("pool"): New insn.

      s390.c (s390_pool_overflow): Remove.
      s390.h (s390_pool_overflow): Likewise.
      s390.md ("cjump", "icjump", "doloop_si"): Remove s390_pool_overflow.


Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.56
diff -c -p -r1.56 s390.c
*** gcc/config/s390/s390.c    24 Sep 2002 16:05:49 -0000    1.56
--- gcc/config/s390/s390.c    15 Oct 2002 15:02:22 -0000
*************** static int general_s_operand PARAMS ((rt
*** 130,140 ****
  static int s390_decompose_address PARAMS ((rtx, struct s390_address *));
  static int reg_used_in_mem_p PARAMS ((int, rtx));
  static int addr_generation_dependency_p PARAMS ((rtx, rtx));
! static void s390_split_branches PARAMS ((void));
  static void find_constant_pool_ref PARAMS ((rtx, rtx *));
  static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx));
! static void s390_chunkify_pool PARAMS ((void));
! static void s390_optimize_prolog PARAMS ((void));
  static int find_unused_clobbered_reg PARAMS ((void));
  static void s390_frame_info PARAMS ((struct s390_frame *));
  static rtx save_fpr PARAMS ((rtx, int, int));
--- 130,143 ----
  static int s390_decompose_address PARAMS ((rtx, struct s390_address *));
  static int reg_used_in_mem_p PARAMS ((int, rtx));
  static int addr_generation_dependency_p PARAMS ((rtx, rtx));
! static int s390_split_branches PARAMS ((rtx, bool *));
  static void find_constant_pool_ref PARAMS ((rtx, rtx *));
  static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx));
! static int find_base_register_in_addr PARAMS ((struct s390_address *));
! static bool find_base_register_ref PARAMS ((rtx));
! static void replace_base_register_ref PARAMS ((rtx *, rtx));
! static void s390_optimize_prolog PARAMS ((int));
! static bool s390_fixup_clobbered_return_reg PARAMS ((rtx));
  static int find_unused_clobbered_reg PARAMS ((void));
  static void s390_frame_info PARAMS ((struct s390_frame *));
  static rtx save_fpr PARAMS ((rtx, int, int));
*************** s390_output_symbolic_const (file, x)
*** 2569,2577 ****
--- 2572,2585 ----
        switch (XINT (x, 1))
          {
          case 100:
+         case 104:
        s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
            fprintf (file, "-.LT%d", current_function_funcdef_no);
        break;
+         case 105:
+           fprintf (file, ".LT%d-", current_function_funcdef_no);
+       s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
+       break;
      case 110:
        s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
        fprintf (file, "@GOT12");
*************** s390_adjust_priority (insn, priority)
*** 2985,2996 ****
  }


! /* Split all branches that exceed the maximum distance.  */

! static void
! s390_split_branches ()
  {
!   rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
    rtx insn, pat, tmp, target;
    rtx *label;

--- 2993,3011 ----
  }


! /* Split all branches that exceed the maximum distance.
!    Returns true if this created a new literal pool entry.
!
!    Code generated by this routine is allowed to use
!    TEMP_REG as temporary scratch register.  If this is
!    done, TEMP_USED is set to true.  */

! static int
! s390_split_branches (temp_reg, temp_used)
!      rtx temp_reg;
!      bool *temp_used;
  {
!   int new_literal = 0;
    rtx insn, pat, tmp, target;
    rtx *label;

*************** s390_split_branches ()
*** 3030,3036 ****
        if (get_attr_length (insn) <= (TARGET_64BIT ? 6 : 4))
      continue;

!       regs_ever_live[RETURN_REGNUM] = 1;

        if (TARGET_64BIT)
      {
--- 3045,3051 ----
        if (get_attr_length (insn) <= (TARGET_64BIT ? 6 : 4))
      continue;

!       *temp_used = 1;

        if (TARGET_64BIT)
      {
*************** s390_split_branches ()
*** 3041,3046 ****
--- 3056,3062 ----
      }
        else if (!flag_pic)
      {
+       new_literal = 1;
        tmp = force_const_mem (Pmode, *label);
        tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
        INSN_ADDRESSES_NEW (tmp, -1);
*************** s390_split_branches ()
*** 3049,3055 ****
      }
        else
      {
!       tmp = gen_rtx_UNSPEC (SImode, gen_rtvec (1, *label), 100);
        tmp = gen_rtx_CONST (SImode, tmp);
        tmp = force_const_mem (SImode, tmp);
        tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
--- 3065,3072 ----
      }
        else
      {
!       new_literal = 1;
!       tmp = gen_rtx_UNSPEC (SImode, gen_rtvec (1, *label), 104);
        tmp = gen_rtx_CONST (SImode, tmp);
        tmp = force_const_mem (SImode, tmp);
        tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
*************** s390_split_branches ()
*** 3062,3067 ****
--- 3079,3086 ----
        if (!validate_change (insn, label, target, 0))
      abort ();
      }
+
+   return new_literal;
  }


*************** replace_constant_pool_ref (x, ref, addr)
*** 3179,3184 ****
--- 3198,3350 ----
      }
  }

+ /* Check whether ADDR is an address that uses the base register,
+    without actually constituting a literal pool access.  (This happens
+    in 31-bit PIC mode, where the base register is used as anchor for
+    relative addressing of local symbols.)
+
+    Returns 1 if the base register occupies the base slot,
+    returns 2 if the base register occupies the index slot,
+    returns 0 if the address is not of this form.  */
+
+ static int
+ find_base_register_in_addr (addr)
+      struct s390_address *addr;
+ {
+   /* If DISP is complex, we might have a literal pool reference.  */
+   if (addr->disp && GET_CODE (addr->disp) != CONST_INT)
+     return 0;
+
+   if (addr->base && REG_P (addr->base) && REGNO (addr->base) == BASE_REGISTER)
+     return 1;
+
+   if (addr->indx && REG_P (addr->indx) && REGNO (addr->indx) == BASE_REGISTER)
+     return 2;
+
+   return 0;
+ }
+
+ /* Return true if X contains an address that uses the base register,
+    without actually constituting a literal pool access.  */
+
+ static bool
+ find_base_register_ref (x)
+      rtx x;
+ {
+   bool retv = FALSE;
+   struct s390_address addr;
+   int i, j;
+   const char *fmt;
+
+   /* Addresses can only occur inside a MEM ...  */
+   if (GET_CODE (x) == MEM)
+     {
+       if (s390_decompose_address (XEXP (x, 0), &addr)
+       && find_base_register_in_addr (&addr))
+     return TRUE;
+     }
+
+   /* ... or a load-address type pattern.  */
+   if (GET_CODE (x) == SET && GET_CODE (SET_DEST (x)) == REG)
+     {
+       if (s390_decompose_address (SET_SRC (x), &addr)
+       && find_base_register_in_addr (&addr))
+     return TRUE;
+     }
+
+   fmt = GET_RTX_FORMAT (GET_CODE (x));
+   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+     {
+       if (fmt[i] == 'e')
+         {
+           retv |= find_base_register_ref (XEXP (x, i));
+         }
+       else if (fmt[i] == 'E')
+         {
+           for (j = 0; j < XVECLEN (x, i); j++)
+             retv |= find_base_register_ref (XVECEXP (x, i, j));
+         }
+     }
+
+   return retv;
+ }
+
+ /* If X contains an address that uses the base register,
+    without actually constituting a literal pool access,
+    replace the base register with REPL in all such cases.
+
+    Handles both MEMs and load address patterns.  */
+
+ static void
+ replace_base_register_ref (x, repl)
+      rtx *x;
+      rtx repl;
+ {
+   struct s390_address addr;
+   rtx new_addr;
+   int i, j, pos;
+   const char *fmt;
+
+   /* Addresses can only occur inside a MEM ...  */
+   if (GET_CODE (*x) == MEM)
+     {
+       if (s390_decompose_address (XEXP (*x, 0), &addr)
+       && (pos = find_base_register_in_addr (&addr)))
+     {
+       if (pos == 1)
+         addr.base = repl;
+       else
+         addr.indx = repl;
+
+       new_addr = addr.base;
+       if (addr.indx)
+         new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.indx);
+       if (addr.disp)
+         new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.disp);
+
+       *x = replace_equiv_address (*x, new_addr);
+       return;
+     }
+     }
+
+   /* ... or a load-address type pattern.  */
+   if (GET_CODE (*x) == SET && GET_CODE (SET_DEST (*x)) == REG)
+     {
+       if (s390_decompose_address (SET_SRC (*x), &addr)
+       && (pos = find_base_register_in_addr (&addr)))
+     {
+       if (pos == 1)
+         addr.base = repl;
+       else
+         addr.indx = repl;
+
+       new_addr = addr.base;
+       if (addr.indx)
+         new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.indx);
+       if (addr.disp)
+         new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.disp);
+
+       SET_SRC (*x) = new_addr;
+       return;
+     }
+     }
+
+   fmt = GET_RTX_FORMAT (GET_CODE (*x));
+   for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
+     {
+       if (fmt[i] == 'e')
+         {
+           replace_base_register_ref (&XEXP (*x, i), repl);
+         }
+       else if (fmt[i] == 'E')
+         {
+           for (j = 0; j < XVECLEN (*x, i); j++)
+             replace_base_register_ref (&XVECEXP (*x, i, j), repl);
+         }
+     }
+ }
+
+
  /* We keep a list of constants we which we have to add to internal
     constant tables in the middle of large functions.  */

*************** struct constant_pool
*** 3210,3226 ****
  {
    struct constant_pool *next;
    rtx first_insn;
!   rtx last_insn;

    struct constant *constants[NR_C_MODES];
    rtx label;
    int size;
  };

  static struct constant_pool *s390_start_pool PARAMS ((struct constant_pool **, rtx));
  static void s390_end_pool PARAMS ((struct constant_pool *, rtx));
  static struct constant_pool *s390_find_pool PARAMS ((struct constant_pool *, rtx));
! static rtx s390_add_pool PARAMS ((struct constant_pool *, rtx, enum machine_mode));
  static rtx s390_dump_pool PARAMS ((struct constant_pool *));
  static void s390_free_pool PARAMS ((struct constant_pool *));

--- 3376,3401 ----
  {
    struct constant_pool *next;
    rtx first_insn;
!   rtx pool_insn;
!   bitmap insns;

    struct constant *constants[NR_C_MODES];
    rtx label;
    int size;
+   bool anchor;
  };

+ static struct constant_pool * s390_chunkify_start PARAMS ((rtx, bool *));
+ static void s390_chunkify_finish PARAMS ((struct constant_pool *, rtx));
+ static void s390_chunkify_cancel PARAMS ((struct constant_pool *));
+
  static struct constant_pool *s390_start_pool PARAMS ((struct constant_pool **, rtx));
  static void s390_end_pool PARAMS ((struct constant_pool *, rtx));
+ static void s390_add_pool_insn PARAMS ((struct constant_pool *, rtx));
  static struct constant_pool *s390_find_pool PARAMS ((struct constant_pool *, rtx));
! static void s390_add_constant PARAMS ((struct constant_pool *, rtx, enum machine_mode));
! static rtx s390_find_constant PARAMS ((struct constant_pool *, rtx, enum machine_mode));
! static void s390_add_anchor PARAMS ((struct constant_pool *));
  static rtx s390_dump_pool PARAMS ((struct constant_pool *));
  static void s390_free_pool PARAMS ((struct constant_pool *));

*************** s390_start_pool (pool_list, insn)
*** 3242,3250 ****

    pool->label = gen_label_rtx ();
    pool->first_insn = insn;
!   pool->last_insn = NULL_RTX;
    pool->size = 0;
!
    for (prev = pool_list; *prev; prev = &(*prev)->next)
      ;
    *prev = pool;
--- 3417,3427 ----

    pool->label = gen_label_rtx ();
    pool->first_insn = insn;
!   pool->pool_insn = NULL_RTX;
!   pool->insns = BITMAP_XMALLOC ();
    pool->size = 0;
!   pool->anchor = FALSE;
!
    for (prev = pool_list; *prev; prev = &(*prev)->next)
      ;
    *prev = pool;
*************** s390_start_pool (pool_list, insn)
*** 3252,3265 ****
    return pool;
  }

! /* End range of instructions covered by POOL at INSN.  */

  static void
  s390_end_pool (pool, insn)
       struct constant_pool *pool;
       rtx insn;
  {
!   pool->last_insn = insn;
  }

  /* Return pool out of POOL_LIST that covers INSN.  */
--- 3429,3459 ----
    return pool;
  }

! /* End range of instructions covered by POOL at INSN and emit
!    placeholder insn representing the pool.  */

  static void
  s390_end_pool (pool, insn)
       struct constant_pool *pool;
       rtx insn;
  {
!   rtx pool_size = GEN_INT (pool->size + 8 /* alignment slop */);
!
!   if (!insn)
!     insn = get_last_insn ();
!
!   pool->pool_insn = emit_insn_after (gen_pool (pool_size), insn);
!   INSN_ADDRESSES_NEW (pool->pool_insn, -1);
! }
!
! /* Add INSN to the list of insns covered by POOL.  */
!
! static void
! s390_add_pool_insn (pool, insn)
!      struct constant_pool *pool;
!      rtx insn;
! {
!   bitmap_set_bit (pool->insns, INSN_UID (insn));
  }

  /* Return pool out of POOL_LIST that covers INSN.  */
*************** s390_find_pool (pool_list, insn)
*** 3269,3301 ****
       struct constant_pool *pool_list;
       rtx insn;
  {
-   int addr = INSN_ADDRESSES (INSN_UID (insn));
    struct constant_pool *pool;

-   if (addr == -1)
-     return NULL;
-
    for (pool = pool_list; pool; pool = pool->next)
!     if (INSN_ADDRESSES (INSN_UID (pool->first_insn)) <= addr
!         && (pool->last_insn == NULL_RTX
!             || INSN_ADDRESSES (INSN_UID (pool->last_insn)) > addr))
        break;

    return pool;
  }

! /* Add constant VAL of mode MODE to the constant pool POOL.
!    Return an RTX describing the distance from the start of
!    the pool to the location of the new constant.  */

! static rtx
! s390_add_pool (pool, val, mode)
       struct constant_pool *pool;
       rtx val;
       enum machine_mode mode;
  {
    struct constant *c;
-   rtx offset;
    int i;

    for (i = 0; i < NR_C_MODES; i++)
--- 3463,3486 ----
       struct constant_pool *pool_list;
       rtx insn;
  {
    struct constant_pool *pool;

    for (pool = pool_list; pool; pool = pool->next)
!     if (bitmap_bit_p (pool->insns, INSN_UID (insn)))
        break;

    return pool;
  }

! /* Add constant VAL of mode MODE to the constant pool POOL.  */

! static void
! s390_add_constant (pool, val, mode)
       struct constant_pool *pool;
       rtx val;
       enum machine_mode mode;
  {
    struct constant *c;
    int i;

    for (i = 0; i < NR_C_MODES; i++)
*************** s390_add_pool (pool, val, mode)
*** 3317,3329 ****
        pool->constants[i] = c;
        pool->size += GET_MODE_SIZE (mode);
      }

!   offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
!                        gen_rtx_LABEL_REF (Pmode, pool->label));
    offset = gen_rtx_CONST (Pmode, offset);
    return offset;
  }

  /* Dump out the constants in POOL.  */

  static rtx
--- 3502,3555 ----
        pool->constants[i] = c;
        pool->size += GET_MODE_SIZE (mode);
      }
+ }

! /* Find constant VAL of mode MODE in the constant pool POOL.
!    Return an RTX describing the distance from the start of
!    the pool to the location of the new constant.  */
!
! static rtx
! s390_find_constant (pool, val, mode)
!      struct constant_pool *pool;
!      rtx val;
!      enum machine_mode mode;
! {
!   struct constant *c;
!   rtx offset;
!   int i;
!
!   for (i = 0; i < NR_C_MODES; i++)
!     if (constant_modes[i] == mode)
!       break;
!   if (i == NR_C_MODES)
!     abort ();
!
!   for (c = pool->constants[i]; c != NULL; c = c->next)
!     if (rtx_equal_p (val, c->value))
!       break;
!
!   if (c == NULL)
!     abort ();
!
!   offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
!                                  gen_rtx_LABEL_REF (Pmode, pool->label));
    offset = gen_rtx_CONST (Pmode, offset);
    return offset;
  }

+ /* Set 'anchor' flag in POOL.  */
+
+ static void
+ s390_add_anchor (pool)
+      struct constant_pool *pool;
+ {
+   if (!pool->anchor)
+     {
+       pool->anchor = TRUE;
+       pool->size += 4;
+     }
+ }
+
  /* Dump out the constants in POOL.  */

  static rtx
*************** s390_dump_pool (pool)
*** 3334,3364 ****
    rtx insn;
    int i;

-   /* Select location to put literal pool.  */
-   if (TARGET_64BIT)
-     insn = get_last_insn ();
-   else
-     insn = pool->last_insn? pool->last_insn : get_last_insn ();
-
    /* Pool start insn switches to proper section
       and guarantees necessary alignment.  */
    if (TARGET_64BIT)
!     insn = emit_insn_after (gen_pool_start_64 (), insn);
    else
!     insn = emit_insn_after (gen_pool_start_31 (), insn);
    INSN_ADDRESSES_NEW (insn, -1);

    insn = emit_label_after (pool->label, insn);
    INSN_ADDRESSES_NEW (insn, -1);

    /* Dump constants in descending alignment requirement order,
       ensuring proper alignment for every constant.  */
    for (i = 0; i < NR_C_MODES; i++)
      for (c = pool->constants[i]; c; c = c->next)
        {
      insn = emit_label_after (c->label, insn);
      INSN_ADDRESSES_NEW (insn, -1);
!     insn = emit_insn_after (gen_consttable[i] (c->value), insn);
      INSN_ADDRESSES_NEW (insn, -1);
        }

--- 3560,3606 ----
    rtx insn;
    int i;

    /* Pool start insn switches to proper section
       and guarantees necessary alignment.  */
    if (TARGET_64BIT)
!     insn = emit_insn_after (gen_pool_start_64 (), pool->pool_insn);
    else
!     insn = emit_insn_after (gen_pool_start_31 (), pool->pool_insn);
    INSN_ADDRESSES_NEW (insn, -1);

    insn = emit_label_after (pool->label, insn);
    INSN_ADDRESSES_NEW (insn, -1);

+   /* Emit anchor if we need one.  */
+   if (pool->anchor)
+     {
+       rtx anchor = gen_rtx_LABEL_REF (VOIDmode, pool->label);
+       anchor = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, anchor), 105);
+       anchor = gen_rtx_CONST (VOIDmode, anchor);
+       insn = emit_insn_after (gen_consttable_si (anchor), insn);
+       INSN_ADDRESSES_NEW (insn, -1);
+     }
+
    /* Dump constants in descending alignment requirement order,
       ensuring proper alignment for every constant.  */
    for (i = 0; i < NR_C_MODES; i++)
      for (c = pool->constants[i]; c; c = c->next)
        {
+     /* Convert 104 unspecs to pool-relative references.  */
+     rtx value = c->value;
+     if (GET_CODE (value) == CONST
+         && GET_CODE (XEXP (value, 0)) == UNSPEC
+         && XINT (XEXP (value, 0), 1) == 104
+         && XVECLEN (XEXP (value, 0), 0) == 1)
+       {
+         value = gen_rtx_MINUS (Pmode, XVECEXP (XEXP (value, 0), 0, 0),
+                          gen_rtx_LABEL_REF (VOIDmode, pool->label));
+         value = gen_rtx_CONST (VOIDmode, value);
+       }
+
      insn = emit_label_after (c->label, insn);
      INSN_ADDRESSES_NEW (insn, -1);
!     insn = emit_insn_after (gen_consttable[i] (value), insn);
      INSN_ADDRESSES_NEW (insn, -1);
        }

*************** s390_dump_pool (pool)
*** 3373,3378 ****
--- 3615,3623 ----
    insn = emit_barrier_after (insn);
    INSN_ADDRESSES_NEW (insn, -1);

+   /* Remove placeholder insn.  */
+   remove_insn (pool->pool_insn);
+
    return insn;
  }

*************** s390_free_pool (pool)
*** 3395,3459 ****
      }
      }

    free (pool);
  }

- /* Used in s390.md for branch length calculation.  */
- int s390_pool_overflow = 0;

! /* Chunkify the literal pool if required.  */

  #define S390_POOL_CHUNK_MIN 0xc00
  #define S390_POOL_CHUNK_MAX 0xe00

! static void
! s390_chunkify_pool ()
  {
!   rtx base_reg = gen_rtx_REG (Pmode,
!                       TARGET_64BIT? BASE_REGISTER : RETURN_REGNUM);

    struct constant_pool *curr_pool = NULL, *pool_list = NULL;
    int extra_size = 0;
    bitmap far_labels;
    rtx insn;

    /* Do we need to chunkify the literal pool?  */

    if (get_pool_size () < S390_POOL_CHUNK_MAX)
!     return;
!
!   if (!TARGET_64BIT)
!     regs_ever_live[RETURN_REGNUM] = 1;

    /* We need correct insn addresses.  */

    shorten_branches (get_insns ());

-
    /* Scan all insns and move literals to pool chunks.
!      Replace all occurrances of literal pool references
!      by explicit references to pool chunk entries.  */

    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      {
!       if (GET_CODE (insn) == INSN)
      {
!       rtx addr, pool_ref = NULL_RTX;
        find_constant_pool_ref (PATTERN (insn), &pool_ref);
        if (pool_ref)
          {
            if (!curr_pool)
            curr_pool = s390_start_pool (&pool_list, insn);

!           addr = s390_add_pool (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;
          }
      }

        if (!curr_pool
        || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
            || INSN_ADDRESSES (INSN_UID (insn)) == -1)
--- 3640,3725 ----
      }
      }

+   BITMAP_XFREE (pool->insns);
    free (pool);
  }


! /* Chunkify the literal pool if required.
!
!    Code generated by this routine is allowed to use
!    TEMP_REG as temporary scratch register.  If this is
!    done, TEMP_USED is set to true.  */

  #define S390_POOL_CHUNK_MIN 0xc00
  #define S390_POOL_CHUNK_MAX 0xe00

! static struct constant_pool *
! s390_chunkify_start (temp_reg, temp_used)
!      rtx temp_reg;
!      bool *temp_used;
  {
!   rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);

    struct constant_pool *curr_pool = NULL, *pool_list = NULL;
    int extra_size = 0;
    bitmap far_labels;
    rtx insn;

+   rtx (*gen_reload_base) PARAMS ((rtx, rtx)) =
+     TARGET_64BIT? gen_reload_base_64 : gen_reload_base_31;
+
+
    /* Do we need to chunkify the literal pool?  */

    if (get_pool_size () < S390_POOL_CHUNK_MAX)
!     return NULL;

    /* We need correct insn addresses.  */

    shorten_branches (get_insns ());

    /* Scan all insns and move literals to pool chunks.
!      Also, emit anchor reload insns before every insn that uses
!      the literal pool base register as anchor pointer.  */

    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      {
!       if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
      {
!       rtx pool_ref = NULL_RTX;
        find_constant_pool_ref (PATTERN (insn), &pool_ref);
        if (pool_ref)
          {
            if (!curr_pool)
            curr_pool = s390_start_pool (&pool_list, insn);

!           s390_add_constant (curr_pool, get_pool_constant (pool_ref),
!                                 get_pool_mode (pool_ref));
!           s390_add_pool_insn (curr_pool, insn);
!         }
!
!       else if (!TARGET_64BIT && flag_pic
!                    && find_base_register_ref (PATTERN (insn)))
!         {
!           rtx new = gen_reload_anchor (temp_reg, base_reg);
!           new = emit_insn_before (new, insn);
!           INSN_ADDRESSES_NEW (new, INSN_ADDRESSES (INSN_UID (insn)));
!           extra_size += 8;
!           *temp_used = 1;
!
!           if (!curr_pool)
!           curr_pool = s390_start_pool (&pool_list, new);

!           s390_add_anchor (curr_pool);
!           s390_add_pool_insn (curr_pool, insn);
          }
      }

+       if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CODE_LABEL)
+     if (curr_pool)
+       s390_add_pool_insn (curr_pool, insn);
+
        if (!curr_pool
        || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
            || INSN_ADDRESSES (INSN_UID (insn)) == -1)
*************** s390_chunkify_pool ()
*** 3464,3470 ****
        if (curr_pool->size < S390_POOL_CHUNK_MAX)
          continue;

!       s390_end_pool (curr_pool, insn);
        curr_pool = NULL;
      }
        else
--- 3730,3736 ----
        if (curr_pool->size < S390_POOL_CHUNK_MAX)
          continue;

!       s390_end_pool (curr_pool, NULL_RTX);
        curr_pool = NULL;
      }
        else
*************** s390_chunkify_pool ()
*** 3477,3487 ****
           Those will have an effect on code size, which we need to
           consider here.  This calculation makes rather pessimistic
           worst-case assumptions.  */
!       if (GET_CODE (insn) == CODE_LABEL
!           || GET_CODE (insn) == JUMP_INSN)
          extra_size += 6;
-       else if (GET_CODE (insn) == CALL_INSN)
-         extra_size += 4;

        if (chunk_size < S390_POOL_CHUNK_MIN
            && curr_pool->size < S390_POOL_CHUNK_MIN)
--- 3743,3750 ----
           Those will have an effect on code size, which we need to
           consider here.  This calculation makes rather pessimistic
           worst-case assumptions.  */
!       if (GET_CODE (insn) == CODE_LABEL)
          extra_size += 6;

        if (chunk_size < S390_POOL_CHUNK_MIN
            && curr_pool->size < S390_POOL_CHUNK_MIN)
*************** s390_chunkify_pool ()
*** 3497,3508 ****

        /* ... so if we don't find one in time, create one.  */
            else if ((chunk_size > S390_POOL_CHUNK_MAX
!                || curr_pool->size > S390_POOL_CHUNK_MAX)
!               && (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN))
          {
-           int addr = INSN_ADDRESSES (INSN_UID (insn));
                rtx label, jump, barrier;

            label = gen_label_rtx ();
            jump = emit_jump_insn_after (gen_jump (label), insn);
            barrier = emit_barrier_after (jump);
--- 3760,3781 ----

        /* ... so if we don't find one in time, create one.  */
            else if ((chunk_size > S390_POOL_CHUNK_MAX
!                || curr_pool->size > S390_POOL_CHUNK_MAX))
          {
                rtx label, jump, barrier;

+           /* We can insert the barrier only after a 'real' insn.  */
+           if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
+           continue;
+           if (get_attr_length (insn) == 0)
+           continue;
+
+           /* Don't separate insns created by s390_split_branches.  */
+           if (GET_CODE (insn) == INSN
+             && GET_CODE (PATTERN (insn)) == SET
+             && rtx_equal_p (SET_DEST (PATTERN (insn)), temp_reg))
+           continue;
+
            label = gen_label_rtx ();
            jump = emit_jump_insn_after (gen_jump (label), insn);
            barrier = emit_barrier_after (jump);
*************** s390_chunkify_pool ()
*** 3510,3517 ****
            JUMP_LABEL (jump) = label;
            LABEL_NUSES (label) = 1;

!           INSN_ADDRESSES_NEW (jump, addr+1);
!           INSN_ADDRESSES_NEW (barrier, addr+1);
            INSN_ADDRESSES_NEW (insn, -1);

            s390_end_pool (curr_pool, barrier);
--- 3783,3790 ----
            JUMP_LABEL (jump) = label;
            LABEL_NUSES (label) = 1;

!           INSN_ADDRESSES_NEW (jump, -1);
!           INSN_ADDRESSES_NEW (barrier, -1);
            INSN_ADDRESSES_NEW (insn, -1);

            s390_end_pool (curr_pool, barrier);
*************** s390_chunkify_pool ()
*** 3521,3530 ****
      }
      }

!   /* Dump out all literal pools.  */
!
!   for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
!     s390_dump_pool (curr_pool);


    /* Find all labels that are branched into
--- 3794,3801 ----
      }
      }

!   if (curr_pool)
!     s390_end_pool (curr_pool, NULL_RTX);


    /* Find all labels that are branched into
*************** s390_chunkify_pool ()
*** 3563,3582 ****

            if (GET_CODE (pat) == SET)
              {
!           rtx label = 0;
!
!               if (GET_CODE (SET_SRC (pat)) == LABEL_REF)
!             {
!               label = XEXP (SET_SRC (pat), 0);
!             }
!               else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
!             {
!               if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
!                 label = XEXP (XEXP (SET_SRC (pat), 1), 0);
!               else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF)
!                 label = XEXP (XEXP (SET_SRC (pat), 2), 0);
!             }
!
            if (label)
            {
                if (s390_find_pool (pool_list, label)
--- 3834,3840 ----

            if (GET_CODE (pat) == SET)
              {
!           rtx label = JUMP_LABEL (insn);
            if (label)
            {
                if (s390_find_pool (pool_list, label)
*************** s390_chunkify_pool ()
*** 3617,3635 ****
    /* Insert base register reload insns before every pool.  */

    for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
!     if (TARGET_64BIT)
!       {
!     rtx pool_ref = gen_rtx_LABEL_REF (Pmode, curr_pool->label);
!     rtx new_insn = gen_rtx_SET (Pmode, base_reg, pool_ref);
!     rtx insn = curr_pool->first_insn;
!         INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
!       }
!     else
!       {
!     rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
!     rtx insn = curr_pool->first_insn;
!         INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
!       }

    /* Insert base register reload insns at every far label.  */

--- 3875,3885 ----
    /* Insert base register reload insns before every pool.  */

    for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
!     {
!       rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
!       rtx insn = curr_pool->first_insn;
!       INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
!     }

    /* Insert base register reload insns at every far label.  */

*************** s390_chunkify_pool ()
*** 3640,3699 ****
      struct constant_pool *pool = s390_find_pool (pool_list, insn);
      if (pool)
        {
!         if (TARGET_64BIT)
!           {
!           rtx pool_ref = gen_rtx_LABEL_REF (Pmode, pool->label);
!           rtx new_insn = gen_rtx_SET (Pmode, base_reg, pool_ref);
!             INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
!           }
!         else
!           {
!           rtx new_insn = gen_reload_base (base_reg, pool->label);
!             INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
!           }
        }
        }

-   /* Insert base register reload insns after every call if necessary.  */

!   if (REGNO (base_reg) == RETURN_REGNUM)
!     for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
!       if (GET_CODE (insn) == CALL_INSN)
!      {
!        struct constant_pool *pool = s390_find_pool (pool_list, insn);
!        if (pool)
!          {
!            rtx new_insn = gen_reload_base2 (base_reg, pool->label);
!            INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
!          }
!       }


    /* Recompute insn addresses.  */

-   s390_pool_overflow = 1;
    init_insn_lengths ();
    shorten_branches (get_insns ());
-   s390_pool_overflow = 0;

!   /* Insert base register reload insns after far branches.  */

!   if (!TARGET_64BIT)
!     for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
!       if (GET_CODE (insn) == JUMP_INSN
!       && GET_CODE (PATTERN (insn)) == SET
!       && get_attr_length (insn) >= 12)
!     {
!       struct constant_pool *pool = s390_find_pool (pool_list, insn);
!       if (pool)
          {
!           rtx new_insn = gen_reload_base (base_reg, pool->label);
!           INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
          }
      }


!   /* Free all memory.  */

    while (pool_list)
      {
--- 3890,4026 ----
      struct constant_pool *pool = s390_find_pool (pool_list, insn);
      if (pool)
        {
!         rtx new_insn = gen_reload_base (base_reg, pool->label);
!         INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
        }
        }


!   BITMAP_XFREE (far_labels);


    /* Recompute insn addresses.  */

    init_insn_lengths ();
    shorten_branches (get_insns ());

!   return pool_list;
! }

! /* 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.
!
!    Code generated by this routine is allowed to use
!    TEMP_REG as temporary scratch register.  */
!
! static void
! s390_chunkify_finish (pool_list, temp_reg)
!      struct constant_pool *pool_list;
!      rtx temp_reg;
! {
!   rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
!   struct constant_pool *curr_pool = NULL;
!   rtx insn;
!
!
!   /* Replace all literal pool references.  */
!
!   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
!     {
!       curr_pool = s390_find_pool (pool_list, insn);
!       if (!curr_pool)
!     continue;
!
!       if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
!         {
!           rtx addr, pool_ref = NULL_RTX;
!           find_constant_pool_ref (PATTERN (insn), &pool_ref);
!           if (pool_ref)
!             {
!               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;
!             }
!
!       else if (!TARGET_64BIT && flag_pic
!                    && find_base_register_ref (PATTERN (insn)))
          {
!           replace_base_register_ref (&PATTERN (insn), temp_reg);
          }
+         }
+     }
+
+   /* Dump out all literal pools.  */
+
+   for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
+     s390_dump_pool (curr_pool);
+
+   /* Free pool list.  */
+
+   while (pool_list)
+     {
+       struct constant_pool *next = pool_list->next;
+       s390_free_pool (pool_list);
+       pool_list = next;
+     }
+ }
+
+ /* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
+    We have decided we cannot use this list, so revert all changes
+    to the current function that were done by s390_chunkify_start.  */
+
+ static void
+ s390_chunkify_cancel (pool_list)
+      struct constant_pool *pool_list;
+ {
+   struct constant_pool *curr_pool = NULL;
+   rtx insn;
+
+   /* Remove all pool placeholder insns.  */
+
+   for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
+     {
+       /* Did we insert an extra barrier?  Remove it.  */
+       rtx barrier = PREV_INSN (curr_pool->pool_insn);
+       rtx jump = barrier? PREV_INSN (barrier) : NULL_RTX;
+       rtx label = NEXT_INSN (curr_pool->pool_insn);
+
+       if (jump && GET_CODE (jump) == JUMP_INSN
+       && barrier && GET_CODE (barrier) == BARRIER
+       && label && GET_CODE (label) == CODE_LABEL
+       && GET_CODE (PATTERN (jump)) == SET
+       && SET_DEST (PATTERN (jump)) == pc_rtx
+       && GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF
+       && XEXP (SET_SRC (PATTERN (jump)), 0) == label)
+     {
+       remove_insn (jump);
+       remove_insn (barrier);
+       remove_insn (label);
      }

+       remove_insn (curr_pool->pool_insn);
+     }
+
+   /* Remove all base/anchor register reload insns.  */
+
+   for (insn = get_insns (); insn; )
+     {
+       rtx next_insn = NEXT_INSN (insn);
+
+       if (GET_CODE (insn) == INSN
+       && GET_CODE (PATTERN (insn)) == SET
+       && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
+       && (XINT (SET_SRC (PATTERN (insn)), 1) == 210
+           || XINT (SET_SRC (PATTERN (insn)), 1) == 211))
+     remove_insn (insn);
+
+       insn = next_insn;
+     }

!   /* Free pool list.  */

    while (pool_list)
      {
*************** s390_chunkify_pool ()
*** 3701,3708 ****
        s390_free_pool (pool_list);
        pool_list = next;
      }
-
-   BITMAP_XFREE (far_labels);
  }


--- 4028,4033 ----
*************** s390_output_constant_pool (file)
*** 3745,3763 ****
        else
          fprintf (file, ".LTN%d:\n", current_function_funcdef_no);
      }
  }


  /* Rework the prolog/epilog to avoid saving/restoring
!    registers unnecessarily.  */

  static void
! s390_optimize_prolog ()
  {
    int save_first, save_last, restore_first, restore_last;
    int i, j;
    rtx insn, new_insn, next_insn;

    /* Find first and last gpr to be saved.  */

    for (i = 6; i < 16; i++)
--- 4070,4120 ----
        else
          fprintf (file, ".LTN%d:\n", current_function_funcdef_no);
      }
+
+   /* If no pool required, at least output the anchor label.  */
+   else if (!TARGET_64BIT && flag_pic)
+     fprintf (file, ".LT%d:\n", current_function_funcdef_no);
  }


  /* Rework the prolog/epilog to avoid saving/restoring
!    registers unnecessarily.  If TEMP_REGNO is nonnegative,
!    it specifies the number of a caller-saved register used
!    as temporary scratch register by code emitted during
!    machine dependent reorg.  */

  static void
! s390_optimize_prolog (temp_regno)
!      int temp_regno;
  {
    int save_first, save_last, restore_first, restore_last;
    int i, j;
    rtx insn, new_insn, next_insn;

+   struct s390_frame frame;
+   s390_frame_info (&frame);
+
+   /* Recompute regs_ever_live data for special registers.  */
+   regs_ever_live[BASE_REGISTER] = 0;
+   regs_ever_live[RETURN_REGNUM] = 0;
+   regs_ever_live[STACK_POINTER_REGNUM] = frame.frame_size > 0;
+
+   /* If there is (possibly) any pool entry, we need to
+      load the base register.
+      ??? FIXME: this should be more precise.  */
+   if (get_pool_size ())
+     regs_ever_live[BASE_REGISTER] = 1;
+
+   /* In non-leaf functions, the prolog/epilog code relies
+      on RETURN_REGNUM being saved in any case.  */
+   if (!current_function_is_leaf)
+     regs_ever_live[RETURN_REGNUM] = 1;
+
+   /* We need to save/restore the temporary register.  */
+   if (temp_regno >= 0)
+     regs_ever_live[temp_regno] = 1;
+
+
    /* Find first and last gpr to be saved.  */

    for (i = 6; i < 16; i++)
*************** s390_optimize_prolog ()
*** 3865,3898 ****
      }
  }

  /* Perform machine-dependent processing.  */

  void
  s390_machine_dependent_reorg (first)
       rtx first ATTRIBUTE_UNUSED;
  {
!   struct s390_frame frame;
!   s390_frame_info (&frame);

!   /* Recompute regs_ever_live data for special registers.  */
!   regs_ever_live[BASE_REGISTER] = 0;
!   regs_ever_live[RETURN_REGNUM] = 0;
!   regs_ever_live[STACK_POINTER_REGNUM] = frame.frame_size > 0;

-   /* If there is (possibly) any pool entry, we need to
-      load the base register.
-      ??? FIXME: this should be more precise.  */
-   if (get_pool_size ())
-     regs_ever_live[BASE_REGISTER] = 1;

!   /* In non-leaf functions, the prolog/epilog code relies
!      on RETURN_REGNUM being saved in any case.  */
!   if (!current_function_is_leaf)
!     regs_ever_live[RETURN_REGNUM] = 1;

!   s390_chunkify_pool ();
!   s390_split_branches ();
!   s390_optimize_prolog ();
  }


--- 4222,4367 ----
      }
  }

+ /* Check whether any insn in the function makes use of the original
+    value of RETURN_REG (e.g. for __builtin_return_address).
+    If so, insert an insn reloading that value.
+
+    Return true if any such insn was found.  */
+
+ static bool
+ s390_fixup_clobbered_return_reg (return_reg)
+     rtx return_reg;
+ {
+   bool replacement_done = 0;
+   rtx insn;
+
+   struct s390_frame frame;
+   s390_frame_info (&frame);
+
+   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+     {
+       rtx reg, off, new_insn;
+
+       if (GET_CODE (insn) != INSN)
+     continue;
+       if (!reg_referenced_p (return_reg, PATTERN (insn)))
+     continue;
+       if (GET_CODE (PATTERN (insn)) == PARALLEL
+       && store_multiple_operation (PATTERN (insn), VOIDmode))
+     continue;
+
+       if (frame.frame_pointer_p)
+     reg = hard_frame_pointer_rtx;
+       else
+     reg = stack_pointer_rtx;
+
+       off = GEN_INT (frame.frame_size + REGNO (return_reg) * UNITS_PER_WORD);
+       if (INTVAL (off) >= 4096)
+     {
+       off = force_const_mem (Pmode, off);
+       new_insn = gen_rtx_SET (Pmode, return_reg, off);
+       new_insn = emit_insn_before (new_insn, insn);
+       INSN_ADDRESSES_NEW (new_insn, -1);
+       off = return_reg;
+     }
+
+       new_insn = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, reg, off));
+       new_insn = gen_rtx_SET (Pmode, return_reg, new_insn);
+       new_insn = emit_insn_before (new_insn, insn);
+       INSN_ADDRESSES_NEW (new_insn, -1);
+
+       replacement_done = 1;
+     }
+
+   return replacement_done;
+ }
+
  /* Perform machine-dependent processing.  */

  void
  s390_machine_dependent_reorg (first)
       rtx first ATTRIBUTE_UNUSED;
  {
!   bool fixed_up_clobbered_return_reg = 0;
!   rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
!   bool temp_used = 0;

!   /* Make sure all splits have been performed; splits after
!      machine_dependent_reorg might confuse insn length counts.  */
!   split_all_insns_noflow ();


!   /* There are two problematic situations we need to correct:
!
!      - the literal pool might be > 4096 bytes in size, so that
!        some of its elements cannot be directly accessed
!
!      - a branch target might be > 64K away from the branch, so that
!        it is not possible to use a PC-relative instruction.
!
!      To fix those, we split the single literal pool into multiple
!      pool chunks, reloading the pool base register at various
!      points throughout the function to ensure it always points to
!      the pool chunk the following code expects, and / or replace
!      PC-relative branches by absolute branches.
!
!      However, the two problems are interdependent: splitting the
!      literal pool can move a branch further away from its target,
!      causing the 64K limit to overflow, and on the other hand,
!      replacing a PC-relative branch by an absolute branch means
!      we need to put the branch target address into the literal
!      pool, possibly causing it to overflow.
!
!      So, we loop trying to fix up both problems until we manage
!      to satisfy both conditions at the same time.  Note that the
!      loop is guaranteed to terminate as every pass of the loop
!      strictly decreases the total number of PC-relative branches
!      in the function.  (This is not completely true as there
!      might be branch-over-pool insns introduced by chunkify_start.
!      Those never need to be split however.)  */
!
!   for (;;)
!     {
!       struct constant_pool *pool_list;
!
!       /* Try to chunkify the literal pool.  */
!       pool_list = s390_chunkify_start (temp_reg, &temp_used);
!
!       /* Split out-of-range branches.  If this has created new
!      literal pool entries, cancel current chunk list and
!      recompute it.  */
!       if (s390_split_branches (temp_reg, &temp_used))
!         {
!           if (pool_list)
!             s390_chunkify_cancel (pool_list);
!
!           continue;
!         }
!
!       /* Check whether we have clobbered a use of the return
!      register (e.g. for __builtin_return_address).  If so,
!      add insns reloading the register where necessary.  */
!       if (temp_used && !fixed_up_clobbered_return_reg
!       && s390_fixup_clobbered_return_reg (temp_reg))
!     {
!       fixed_up_clobbered_return_reg = 1;

!       /* The fixup insns might have caused a jump to overflow.  */
!       if (pool_list)
!         s390_chunkify_cancel (pool_list);
!
!       continue;
!     }
!
!       /* If we made it up to here, both conditions are satisfied.
!      Finish up pool chunkification if required.  */
!       if (pool_list)
!     s390_chunkify_finish (pool_list, temp_reg);
!
!       break;
!     }
!
!   s390_optimize_prolog (temp_used? RETURN_REGNUM : -1);
  }


Index: gcc/config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.43
diff -c -p -r1.43 s390.h
*** gcc/config/s390/s390.h    18 Sep 2002 18:57:18 -0000    1.43
--- gcc/config/s390/s390.h    15 Oct 2002 15:02:23 -0000
*************** extern struct rtx_def *s390_compare_op0,
*** 1299,1305 ****

  extern int s390_pool_count;
  extern int s390_nr_constants;
- extern int s390_pool_overflow;

  #define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, fndecl, size)           \
  {                                                         \
--- 1299,1304 ----
Index: gcc/config/s390/s390.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v
retrieving revision 1.35
diff -c -p -r1.35 s390.md
*** gcc/config/s390/s390.md   8 Oct 2002 16:13:24 -0000     1.35
--- gcc/config/s390/s390.md   15 Oct 2002 15:02:26 -0000
***************
*** 5724,5732 ****
                  (const_int 4)
                 (ne (symbol_ref "TARGET_64BIT") (const_int 0))
                   (const_int 6)
-            (ne (symbol_ref "s390_pool_overflow") (const_int 0))
-                  (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
-                                (const_int 12) (const_int 14))
                 (eq (symbol_ref "flag_pic") (const_int 0))
                   (const_int 6)] (const_int 8)))])

--- 5724,5729 ----
***************
*** 5776,5784 ****
                  (const_int 4)
                 (ne (symbol_ref "TARGET_64BIT") (const_int 0))
                   (const_int 6)
-            (ne (symbol_ref "s390_pool_overflow") (const_int 0))
-                  (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
-                                (const_int 12) (const_int 14))
                 (eq (symbol_ref "flag_pic") (const_int 0))
                   (const_int 6)] (const_int 8)))])

--- 5773,5778 ----
***************
*** 5888,5896 ****
                  (const_int 4)
                 (ne (symbol_ref "TARGET_64BIT") (const_int 0))
                   (const_int 10)
-            (ne (symbol_ref "s390_pool_overflow") (const_int 0))
-                  (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
-                                (const_int 12) (const_int 14))
                 (eq (symbol_ref "flag_pic") (const_int 0))
                   (const_int 6)] (const_int 8)))])

--- 5882,5887 ----
***************
*** 6707,6713 ****
    [(set_attr "op_type"  "NN")
     (set_attr "length"   "0")])

! (define_insn "reload_base"
    [(set (match_operand:SI 0 "register_operand" "=a")
          (unspec:SI [(label_ref (match_operand 1 "" ""))] 210))]
    "!TARGET_64BIT"
--- 6698,6704 ----
    [(set_attr "op_type"  "NN")
     (set_attr "length"   "0")])

! (define_insn "reload_base_31"
    [(set (match_operand:SI 0 "register_operand" "=a")
          (unspec:SI [(label_ref (match_operand 1 "" ""))] 210))]
    "!TARGET_64BIT"
***************
*** 6716,6730 ****
     (set_attr "type"    "la")
     (set_attr "length"  "6")])

! (define_insn "reload_base2"
    [(set (match_operand:SI 0 "register_operand" "=a")
!         (unspec:SI [(label_ref (match_operand 1 "" ""))] 211))]
    "!TARGET_64BIT"
!   "la\\t%0,%1-.(%0)"
    [(set_attr "op_type" "NN")
     (set_attr "type"    "la")
!    (set_attr "length"  "4")])


  ;;
  ;; Insns related to generating the function prologue and epilogue.
--- 6707,6735 ----
     (set_attr "type"    "la")
     (set_attr "length"  "6")])

! (define_insn "reload_base_64"
!   [(set (match_operand:DI 0 "register_operand" "=a")
!         (unspec:DI [(label_ref (match_operand 1 "" ""))] 210))]
!   "TARGET_64BIT"
!   "larl\\t%0,%1"
!   [(set_attr "op_type" "RIL")
!    (set_attr "type"    "la")])
!
! (define_insn "reload_anchor"
    [(set (match_operand:SI 0 "register_operand" "=a")
!         (unspec:SI [(match_operand:SI 1 "register_operand" "a")] 211))]
    "!TARGET_64BIT"
!   "l\\t%0,0(%1)\;la\\t%0,0(%0,%1)"
    [(set_attr "op_type" "NN")
     (set_attr "type"    "la")
!    (set_attr "length"  "8")])

+ (define_insn "pool"
+   [(unspec_volatile [(match_operand 0 "const_int_operand" "n")] 220)]
+   ""
+   "* abort ();"
+   [(set_attr "op_type" "NN")
+    (set (attr "length") (symbol_ref "INTVAL (operands[0])"))])

  ;;
  ;; Insns related to generating the function prologue and epilogue.


Mit freundlichen Gruessen / Best Regards

Ulrich Weigand

--
  Dr. Ulrich Weigand
  Linux for S/390 Design & Development
  IBM Deutschland Entwicklung GmbH, Schoenaicher Str. 220, 71032 Boeblingen
  Phone: +49-7031/16-3727   ---   Email: Ulrich.Weigand@de.ibm.com



More information about the Gcc-patches mailing list