From 5af2f3d3ff87a08c4292f6dcbf60a6d1b7039e6c Mon Sep 17 00:00:00 2001
From: Ulrich Weigand <uweigand@de.ibm.com>
Date: Wed, 27 Aug 2003 18:50:37 +0000
Subject: [PATCH] s390.c (struct machine_function): Remove member
 literal_pool_label.

	* config/s390/s390.c (struct machine_function): Remove member
	literal_pool_label.
	(s390_optimize_prolog): Replace TEMP_REG argument with
	TEMP_USED and BASE_USED.  Do not check get_pool_size ().
	(general_s_operand): Accept all immediates before reload if
	ALLOW_IMMEDIATE.  If not ALLOW_IMMEDIATE, reject literal pool
	references.
	(s390_output_symbolic_const): Remove UNSPEC_LTREL_OFFSET handling.
	(find_constant_pool_ref): Ignore UNSPECV_POOL_ENTRY insns.
	(s390_alloc_pool): New function.
	(s390_new_pool): Call it.
	(s390_dump_pool): Add REMOTE_LABEL argument.
	(s390_chunkify_start): Add BASE_REG argument.  Do not check
	get_pool_size ().
	(s390_chunkify_finish): Add BASE_REG argument.  Adapt
	s390_dump_pool call.
	(s390_pool_count, s390_nr_constants): Remove.
	(s390_output_constant_pool): Remove.
	(s390_mainpool_start): New function.
	(s390_mainpool_finish): New function.
	(s390_mainpool_cancel): New function.
	(s390_reorg): Implement main literal pool handling.
	(s390_emit_prologue): Emit main_pool placeholder instead of
	literal_pool_31 / literal_pool_64 insns.
	* config/s390/s390.h (s390_pool_count, s390_nr_constants): Remove.
	(ASM_OUTPUT_POOL_PROLOGUE, ASM_OUTPUT_SPECIAL_POOL_ENTRY): Remove.
	* config/s390/s390.md (UNSPEC_MAIN_BASE): New symbolic constant.
	("main_base_31_small", "main_base_31_large"): New insns.
	("main_base_64",  "main_pool"): New insns.
	("literal_pool_31", "literal_pool_64"): Remove.

From-SVN: r70853
---
 gcc/ChangeLog           |  33 ++++
 gcc/config/s390/s390.c  | 416 +++++++++++++++++++++++++++-------------
 gcc/config/s390/s390.h  |  29 ---
 gcc/config/s390/s390.md |  67 +++----
 4 files changed, 347 insertions(+), 198 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a37591d4b4b..03b535a4b48 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,36 @@
+2003-08-27  Ulrich Weigand  <uweigand@de.ibm.com>
+
+	* config/s390/s390.c (struct machine_function): Remove member
+	literal_pool_label.
+	(s390_optimize_prolog): Replace TEMP_REG argument with 
+	TEMP_USED and BASE_USED.  Do not check get_pool_size ().
+	(general_s_operand): Accept all immediates before reload if 
+	ALLOW_IMMEDIATE.  If not ALLOW_IMMEDIATE, reject literal pool 
+	references.
+	(s390_output_symbolic_const): Remove UNSPEC_LTREL_OFFSET handling.
+	(find_constant_pool_ref): Ignore UNSPECV_POOL_ENTRY insns.
+	(s390_alloc_pool): New function.
+	(s390_new_pool): Call it.
+	(s390_dump_pool): Add REMOTE_LABEL argument.
+	(s390_chunkify_start): Add BASE_REG argument.  Do not check 
+	get_pool_size ().
+	(s390_chunkify_finish): Add BASE_REG argument.  Adapt 
+	s390_dump_pool call.
+	(s390_pool_count, s390_nr_constants): Remove.
+	(s390_output_constant_pool): Remove.
+	(s390_mainpool_start): New function.
+	(s390_mainpool_finish): New function.
+	(s390_mainpool_cancel): New function.
+	(s390_reorg): Implement main literal pool handling.
+	(s390_emit_prologue): Emit main_pool placeholder instead of 
+	literal_pool_31 / literal_pool_64 insns.
+	* config/s390/s390.h (s390_pool_count, s390_nr_constants): Remove.
+	(ASM_OUTPUT_POOL_PROLOGUE, ASM_OUTPUT_SPECIAL_POOL_ENTRY): Remove.
+	* config/s390/s390.md (UNSPEC_MAIN_BASE): New symbolic constant.
+	("main_base_31_small", "main_base_31_large"): New insns.
+	("main_base_64",  "main_pool"): New insns.
+	("literal_pool_31", "literal_pool_64"): Remove.
+
 2003-08-27  Nathanael Nerode  <neroden@gcc.gnu.org>
 
 	* fixinc/inclhack.def (ptx_netswap): New disabled fix, ported from
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index c318d4770a3..bd3fc655890 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -183,9 +183,6 @@ const char *s390_arch_string;		/* for -march=<xxx> */
 
 struct machine_function GTY(())
 {
-  /* Label of start of initial literal pool.  */
-  rtx literal_pool_label;
-
   /* Set, if some of the fprs 8-15 need to be saved (64 bit abi).  */
   int save_fprs_p;
 
@@ -223,7 +220,7 @@ 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 s390_optimize_prolog (int);
+static void s390_optimize_prolog (bool, bool);
 static int find_unused_clobbered_reg (void);
 static void s390_frame_info (void);
 static rtx save_fpr (rtx, int, int);
@@ -1139,30 +1136,30 @@ general_s_operand (register rtx op, enum machine_mode mode,
 
   switch (GET_CODE (op))
     {
-      /* Constants that we are sure will be forced to the
-         literal pool in reload are OK as s-operand.  Note
-	 that we cannot call s390_preferred_reload_class here
-	 because it might not be known yet at this point
-	 whether the current function is a leaf or not.  */
+      /* Constants are OK as s-operand if ALLOW_IMMEDIATE
+	 is true and we are still before reload.  */
       case CONST_INT:
       case CONST_DOUBLE:
 	if (!allow_immediate || reload_completed)
-	  break;
-	if (!legitimate_reload_constant_p (op))
-	  return 1;
-	if (!TARGET_64BIT)
-	  return 1;
-	break;
+	  return 0;
+	return 1;
 
       /* Memory operands are OK unless they already use an
 	 index register.  */
       case MEM:
 	if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
 	  return 1;
-	if (s390_decompose_address (XEXP (op, 0), &addr)
-	    && !addr.indx)
-	  return 1;
-	break;
+	if (!s390_decompose_address (XEXP (op, 0), &addr))
+	  return 0;
+	if (addr.indx)
+	  return 0;
+	/* Do not allow literal pool references unless ALLOW_IMMEDIATE 
+	   is true.  This prevents compares between two literal pool 
+	   entries from being accepted.  */
+	if (!allow_immediate 
+	    && addr.base && REGNO (addr.base) == BASE_REGISTER)
+	  return 0;
+	return 1;
 
       default:
 	break;
@@ -3278,11 +3275,6 @@ s390_output_symbolic_const (FILE *file, rtx x)
         output_operand_lossage ("invalid UNSPEC as operand (1)");
       switch (XINT (x, 1))
         {
-        case UNSPEC_LTREL_OFFSET:
-	  s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
-          fprintf (file, "-");
-	  s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
-	  break;
 	case UNSPEC_GOTENT:
 	  s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
 	  fprintf (file, "@GOTENT");
@@ -3876,6 +3868,10 @@ find_constant_pool_ref (rtx x, rtx *ref)
   if (GET_CODE (x) == UNSPEC
       && XINT (x, 1) == UNSPEC_LTREL_BASE)
     return;
+  /* Likewise POOL_ENTRY insns.  */
+  if (GET_CODE (x) == UNSPEC_VOLATILE
+      && XINT (x, 1) == UNSPECV_POOL_ENTRY)
+    return;
 
   if (GET_CODE (x) == SYMBOL_REF
       && CONSTANT_POOL_ADDRESS_P (x))
@@ -4071,8 +4067,12 @@ struct constant_pool
   int size;
 };
 
-static struct constant_pool * s390_chunkify_start (void);
-static void s390_chunkify_finish (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_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 void s390_chunkify_cancel (struct constant_pool *);
 
 static struct constant_pool *s390_start_pool (struct constant_pool **, rtx);
@@ -4081,7 +4081,8 @@ static void s390_add_pool_insn (struct constant_pool *, rtx);
 static struct constant_pool *s390_find_pool (struct constant_pool *, rtx);
 static void s390_add_constant (struct constant_pool *, rtx, enum machine_mode);
 static rtx s390_find_constant (struct constant_pool *, rtx, enum machine_mode);
-static rtx s390_dump_pool (struct constant_pool *);
+static rtx s390_dump_pool (struct constant_pool *, bool);
+static struct constant_pool *s390_alloc_pool (void);
 static void s390_free_pool (struct constant_pool *);
 
 /* Create new constant pool covering instructions starting at INSN
@@ -4091,18 +4092,9 @@ static struct constant_pool *
 s390_start_pool (struct constant_pool **pool_list, rtx insn)
 {
   struct constant_pool *pool, **prev;
-  int i;
 
-  pool = (struct constant_pool *) xmalloc (sizeof *pool);
-  pool->next = NULL;
-  for (i = 0; i < NR_C_MODES; i++)
-    pool->constants[i] = NULL;
-
-  pool->label = gen_label_rtx ();
+  pool = s390_alloc_pool ();
   pool->first_insn = insn;
-  pool->pool_insn = NULL_RTX;
-  pool->insns = BITMAP_XMALLOC ();
-  pool->size = 0;
 
   for (prev = pool_list; *prev; prev = &(*prev)->next)
     ;
@@ -4208,10 +4200,11 @@ s390_find_constant (struct constant_pool *pool, rtx val,
   return offset;
 }
 
-/* Dump out the constants in POOL.  */
+/* Dump out the constants in POOL.  If REMOTE_LABEL is true,
+   do not emit the pool base label.  */
 
 static rtx
-s390_dump_pool (struct constant_pool *pool)
+s390_dump_pool (struct constant_pool *pool, bool remote_label)
 {
   struct constant *c;
   rtx insn;
@@ -4225,8 +4218,11 @@ s390_dump_pool (struct constant_pool *pool)
     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);
+  if (!remote_label)
+    {
+      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.  */
@@ -4272,6 +4268,28 @@ s390_dump_pool (struct constant_pool *pool)
   return insn;
 }
 
+/* Allocate new constant_pool structure.  */
+
+static struct constant_pool *
+s390_alloc_pool (void)
+{
+  struct constant_pool *pool;
+  int i;
+
+  pool = (struct constant_pool *) xmalloc (sizeof *pool);
+  pool->next = NULL;
+  for (i = 0; i < NR_C_MODES; i++)
+    pool->constants[i] = NULL;
+
+  pool->label = gen_label_rtx ();
+  pool->first_insn = NULL_RTX;
+  pool->pool_insn = NULL_RTX;
+  pool->insns = BITMAP_XMALLOC ();
+  pool->size = 0;
+
+  return pool;
+}
+
 /* Free all memory used by POOL.  */
 
 static void
@@ -4295,16 +4313,182 @@ s390_free_pool (struct constant_pool *pool)
 }
 
 
-/* Chunkify the literal pool if required.  */
+/* Collect main literal pool.  Return NULL on overflow.  */
+
+static struct constant_pool *
+s390_mainpool_start (void)
+{
+  struct constant_pool *pool;
+  rtx insn;
+
+  pool = s390_alloc_pool ();
+
+  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)
+	{
+	  if (pool->pool_insn)
+	    abort ();
+	  pool->pool_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)
+	    {
+	      rtx constant = get_pool_constant (pool_ref);
+	      enum machine_mode mode = get_pool_mode (pool_ref);
+	      s390_add_constant (pool, constant, mode);
+	    }
+	}
+    }
+
+  if (!pool->pool_insn)
+    abort ();
+
+  if (pool->size >= 4096)
+    {
+      s390_free_pool (pool);
+      pool = NULL;
+    }
+
+  return pool;
+}
+
+/* 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.  */
+
+static void
+s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
+{
+  rtx insn;
+
+  /* If the pool is empty, we're done.  */
+  if (pool->size == 0)
+    {
+      remove_insn (pool->pool_insn);
+      s390_free_pool (pool);
+      return;
+    }
+
+  /* We need correct insn addresses.  */
+  shorten_branches (get_insns ());
+
+  /* In 64-bit, we use a LARL to load the pool register.  The pool is
+     located in the .rodata section, so we emit it after the function.  */
+  if (TARGET_64BIT)
+    {
+      insn = gen_main_base_64 (base_reg, pool->label);
+      insn = emit_insn_after (insn, pool->pool_insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+      remove_insn (pool->pool_insn);
+     
+      insn = get_last_insn (); 
+      pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
+      INSN_ADDRESSES_NEW (pool->pool_insn, -1);
+
+      s390_dump_pool (pool, 0);
+    }
+
+  /* In 31-bit, if the total size of the function's code plus literal pool
+     does not exceed 4096 bytes, we use BASR to set up a function base
+     pointer, and emit the literal pool at the end of the function.  */
+  else if (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
+	   + pool->size + 8 /* alignment slop */ < 4096)
+    {
+      insn = gen_main_base_31_small (base_reg, pool->label);
+      insn = emit_insn_after (insn, pool->pool_insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+      remove_insn (pool->pool_insn);
+
+      insn = emit_label_after (pool->label, insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+
+      insn = get_last_insn ();
+      pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
+      INSN_ADDRESSES_NEW (pool->pool_insn, -1);
+
+      s390_dump_pool (pool, 1);
+    }
+
+  /* Otherwise, we emit an inline literal pool and use BASR to branch
+     over it, setting up the pool register at the same time.  */
+  else
+    {
+      rtx pool_end = gen_label_rtx ();
+
+      insn = gen_main_base_31_large (base_reg, pool->label, pool_end);
+      insn = emit_insn_after (insn, pool->pool_insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+      remove_insn (pool->pool_insn);
+
+      insn = emit_label_after (pool->label, insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+
+      pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
+      INSN_ADDRESSES_NEW (pool->pool_insn, -1);
+
+      insn = emit_label_after (pool_end, pool->pool_insn);
+      INSN_ADDRESSES_NEW (insn, -1);
+
+      s390_dump_pool (pool, 1);
+    }
+
+
+  /* Replace all literal pool references.  */
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (INSN_P (insn))
+	replace_ltrel_base (&PATTERN (insn), base_reg);
+
+      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 (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;
+            }
+        }
+    }
+
+
+  /* Free the pool.  */
+  s390_free_pool (pool);
+}
+
+/* POOL holds the main literal pool as collected by s390_mainpool_start.
+   We have decided we cannot use this pool, so revert all changes
+   to the current function that were done by s390_mainpool_start.  */
+static void
+s390_mainpool_cancel (struct constant_pool *pool)
+{
+  /* We didn't actually change the instruction stream, so simply
+     free the pool memory.  */
+  s390_free_pool (pool);
+}
+
+
+/* Chunkify the literal pool.  BASE_REG is to be used as pool
+   register.  */
 
 #define S390_POOL_CHUNK_MIN	0xc00
 #define S390_POOL_CHUNK_MAX	0xe00
 
 static struct constant_pool *
-s390_chunkify_start (void)
+s390_chunkify_start (rtx base_reg)
 {
-  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;
@@ -4315,11 +4499,6 @@ s390_chunkify_start (void)
     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 ());
@@ -4568,12 +4747,12 @@ s390_chunkify_start (void)
 
 /* 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.  */
+   all changes to the current function as required.  BASE_REG is
+   to be used as pool base register.  */
 
 static void
-s390_chunkify_finish (struct constant_pool *pool_list)
+s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
 {
-  rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
   struct constant_pool *curr_pool = NULL;
   rtx insn;
 
@@ -4607,7 +4786,7 @@ s390_chunkify_finish (struct constant_pool *pool_list)
   /* Dump out all literal pools.  */
 
   for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
-    s390_dump_pool (curr_pool);
+    s390_dump_pool (curr_pool, 0);
 
   /* Free pool list.  */
 
@@ -4680,45 +4859,6 @@ s390_chunkify_cancel (struct constant_pool *pool_list)
 }
 
 
-/* Index of constant pool chunk that is currently being processed.
-   Set to -1 before function output has started.  */
-int s390_pool_count = -1;
-
-/* Number of elements of current constant pool.  */
-int s390_nr_constants;
-
-/* Output main constant pool to stdio stream FILE.  */
-
-void
-s390_output_constant_pool (rtx start_label, rtx end_label)
-{
-  if (TARGET_64BIT)
-    {
-      readonly_data_section ();
-      ASM_OUTPUT_ALIGN (asm_out_file, 3);
-      targetm.asm_out.internal_label (asm_out_file, "L",
-				      CODE_LABEL_NUMBER (start_label));
-    }
-  else
-    {
-      targetm.asm_out.internal_label (asm_out_file, "L",
-				      CODE_LABEL_NUMBER (start_label));
-      ASM_OUTPUT_ALIGN (asm_out_file, 2);
-    }
-
-  s390_pool_count = 0;
-  output_constant_pool (current_function_name, current_function_decl);
-  s390_pool_count = -1;
-  if (TARGET_64BIT)
-    function_section (current_function_decl);
-  else
-    {
-      ASM_OUTPUT_ALIGN (asm_out_file, 1);
-      targetm.asm_out.internal_label (asm_out_file, "L",
-				      CODE_LABEL_NUMBER (end_label));
-    }
-}
-
 /* Output to FILE the constant pool entry EXP in mode MODE
    with alignment ALIGN.  */
 
@@ -4760,29 +4900,23 @@ s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode,
 
 
 /* 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.  */
+   registers unnecessarily.  BASE_USED specifies whether
+   the literal pool base register needs to be saved, 
+   TEMP_USED specifies whether the return register needs
+   to be saved.  */
 
 static void
-s390_optimize_prolog (int temp_regno)
+s390_optimize_prolog (bool base_used, bool temp_used)
 {
   int save_first, save_last, restore_first, restore_last;
   int i, j;
   rtx insn, new_insn, next_insn;
 
   /* Recompute regs_ever_live data for special registers.  */
-  regs_ever_live[BASE_REGISTER] = 0;
-  regs_ever_live[RETURN_REGNUM] = 0;
+  regs_ever_live[BASE_REGISTER] = base_used;
+  regs_ever_live[RETURN_REGNUM] = temp_used;
   regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->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.  We also need
      to save the return register if __builtin_return_address (0)
@@ -4791,10 +4925,6 @@ s390_optimize_prolog (int temp_regno)
       || cfun->machine->save_return_addr_p)
     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.  */
 
@@ -4919,14 +5049,27 @@ static void
 s390_reorg (void)
 {
   rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
-  bool temp_used = 0;
+  rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
+  bool temp_used = false;
+  bool base_used = false;
+  bool pool_overflow = false;
 
   /* 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:
+  /* 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.
+
+     In addition, 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
@@ -4957,31 +5100,48 @@ s390_reorg (void)
 
   for (;;)
     {
-      struct constant_pool *pool_list;
+      struct constant_pool *pool = NULL;
 
-      /* Try to chunkify the literal pool.  */
-      pool_list = s390_chunkify_start ();
+      /* Collect the literal pool.  */
+      if (!pool_overflow)
+	{
+	  pool = s390_mainpool_start ();
+	  if (!pool)
+	    pool_overflow = true;
+	}
+
+      /* If literal pool overflowed, start to chunkify it.  */
+      if (pool_overflow)
+        pool = s390_chunkify_start (base_reg);
 
       /* 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);
+          if (pool_overflow)
+            s390_chunkify_cancel (pool);
+	  else
+            s390_mainpool_cancel (pool);
 
           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);
+	 Finish up literal pool related changes.  */
+      if ((pool_overflow || pool->size > 0)
+	   && REGNO (base_reg) == BASE_REGISTER)
+	base_used = true;
+
+      if (pool_overflow)
+	s390_chunkify_finish (pool, base_reg);
+      else
+	s390_mainpool_finish (pool, base_reg);
 
       break;
     }
 
-  s390_optimize_prolog (temp_used? RETURN_REGNUM : -1);
+  s390_optimize_prolog (base_used, temp_used);
 }
 
 
@@ -5305,7 +5465,6 @@ s390_emit_prologue (void)
 {
   rtx insn, addr;
   rtx temp_reg;
-  rtx pool_start_label, pool_end_label;
   int i;
 
   /* Compute frame_info.  */
@@ -5327,18 +5486,9 @@ s390_emit_prologue (void)
 		    cfun->machine->first_save_gpr, cfun->machine->last_save_gpr);
   emit_insn (insn);
 
-  /* Dump constant pool and set constant pool register.  */
+  /* Dummy insn to mark literal pool slot.  */
 
-  pool_start_label = gen_label_rtx();
-  pool_end_label = gen_label_rtx();
-  cfun->machine->literal_pool_label = pool_start_label;
-
-  if (TARGET_64BIT)
-    insn = emit_insn (gen_literal_pool_64 (gen_rtx_REG (Pmode, BASE_REGISTER),
-			   pool_start_label, pool_end_label));
-  else
-    insn = emit_insn (gen_literal_pool_31 (gen_rtx_REG (Pmode, BASE_REGISTER),
-					     pool_start_label, pool_end_label));
+  emit_insn (gen_main_pool ());
 
   /* Save fprs for variable args.  */
 
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 541d6892f8a..5cd1d46d666 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -1012,35 +1012,6 @@ do {									\
 } while (0)
 
 
-/* Constant Pool for all symbols operands which are changed with
-   force_const_mem during insn generation (expand_insn).  */
-
-extern int s390_pool_count;
-extern int s390_nr_constants;
-
-#define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, fndecl, size)  	        \
-{								       	\
-  struct pool_constant *pool;					       	\
-								        \
-    if (s390_pool_count == -1)                                        	\
-     {							                \
-       s390_nr_constants = 0;				                \
-       for (pool = first_pool; pool; pool = pool->next)	                \
-	 if (pool->mark) s390_nr_constants++;		                \
-       return;                                      	                \
-     }                                                                  \
-}
-
-#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE, EXP, MODE, ALIGN, LABELNO, WIN) \
-{									    \
-  fprintf (FILE, ".LC%d:\n", LABELNO);					    \
-  s390_output_pool_entry (FILE, EXP, MODE, ALIGN);			    \
-  if (GET_MODE_SIZE (MODE) == 1)					    \
-    ASM_OUTPUT_SKIP ((FILE), (unsigned HOST_WIDE_INT)1);		    \
-  goto WIN;								    \
-}
-
-
 /* Miscellaneous parameters.  */
 
 /* Define the codes that are matched by predicates in aux-output.c.  */
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index fa7203df47a..4cda1480cab 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -65,6 +65,7 @@
 
    ; Literal pool
    (UNSPEC_RELOAD_BASE		210)
+   (UNSPEC_MAIN_BASE		211)
 
    ; TLS relocation specifiers
    (UNSPEC_TLSGD		500)
@@ -7232,6 +7233,36 @@
   [(set_attr "op_type"  "NN")
    (set_attr "length"   "0")])
 
+(define_insn "main_base_31_small"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+        (unspec:SI [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))]
+  "!TARGET_64BIT"
+  "basr\t%0,0"
+  [(set_attr "op_type" "RR")
+   (set_attr "type"    "la")])
+
+(define_insn "main_base_31_large"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+        (unspec:SI [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))
+   (set (pc) (label_ref (match_operand 2 "" "")))]
+  "!TARGET_64BIT"
+  "bras\t%0,%2"
+  [(set_attr "op_type" "RI")])
+
+(define_insn "main_base_64"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+        (unspec:DI [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))]
+  "TARGET_64BIT"
+  "larl\t%0,%1"
+  [(set_attr "op_type" "RIL")
+   (set_attr "type"    "larl")])
+
+(define_insn "main_pool"
+  [(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)]
+  ""
+  "* abort ();"
+  [(set_attr "op_type" "NN")])
+
 (define_insn "reload_base_31"
   [(set (match_operand:SI 0 "register_operand" "=a")
         (unspec:SI [(label_ref (match_operand 1 "" ""))] UNSPEC_RELOAD_BASE))]
@@ -7290,42 +7321,6 @@
    (set_attr "type"    "jsr")
    (set_attr "atype"   "agen")])
 
-(define_insn "literal_pool_31"
-  [(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)
-   (set (match_operand:SI 0 "register_operand" "=a")
-        (label_ref (match_operand 1 "" "")))
-   (use (label_ref (match_operand 2 "" "")))]
-  ""
-{
-   if (s390_nr_constants)
-     {
-       output_asm_insn ("bras\t%0,%2", operands);
-       s390_output_constant_pool (operands[1], operands[2]);
-     }
-
-   return "";
-}
-  [(set_attr "op_type" "NN")
-   (set_attr "type"    "larl")])
-
-(define_insn "literal_pool_64"
-  [(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)
-   (set (match_operand:DI 0 "register_operand" "=a")
-        (label_ref (match_operand 1 "" "")))
-   (use (label_ref (match_operand 2 "" "")))]
-  ""
-{
-   if (s390_nr_constants)
-     {
-       output_asm_insn ("larl\t%0,%1", operands);
-       s390_output_constant_pool (operands[1], operands[2]);
-     }
-
-   return "";
-}
-  [(set_attr "op_type" "NN")
-   (set_attr "type"    "larl")])
-
 ;; Instruction definition to extend a 31-bit pointer into a 64-bit
 ;; pointer. This is used for compatability.