S/390: Improve main literal pool handling

Ulrich Weigand weigand@i1.informatik.uni-erlangen.de
Wed Aug 27 19:01:00 GMT 2003


Hello,

this patch changes the handling of the 'main' literal pool
(i.e. in the non-overflow case) to make use of the same logic
as the pool overflow case.  This means that we no longer try
to employ the varasm pool output routines at all, but simply
handle the literal pool output completely in the back end.

This allows us to finally get rid of the weird hacks we had
to do in ASM_OUTPUT_POOL_PROLOGUE etc. and at the same time
allows much greater freedom in how to handle literal pool
details.  Specifically, this patch does

- place the literal pool *after* short 31-bit functions (i.e.
  where the total of code+pool size does not exceed 4K);
  this allows to set up the base pointer using basr %r13,0
  instead of bras %r13,..., which is both shorter and more
  efficient (no branch history table entry, reduced address
  generation interlock stall).

- use a call-clobbered register instead of %r13 in leaf
  functions, where available; this avoids the overhead of
  saving/restoring %r13.

In particular in small functions, use of a literal pool now
has a significantly smaller initial overhead.  Therefore,
the patch also removes some hacks that tried to reduce
literal pool use on 64-bit.

Bye,
Ulrich


ChangeLog:

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




Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.110
diff -c -p -r1.110 s390.c
*** gcc/config/s390/s390.c	26 Aug 2003 20:39:45 -0000	1.110
--- gcc/config/s390/s390.c	27 Aug 2003 16:01:56 -0000
*************** const char *s390_arch_string;		/* for -m
*** 183,191 ****
  
  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;
  
--- 183,188 ----
*************** static void find_constant_pool_ref (rtx,
*** 223,229 ****
  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 int find_unused_clobbered_reg (void);
  static void s390_frame_info (void);
  static rtx save_fpr (rtx, int, int);
--- 220,226 ----
  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 (bool, bool);
  static int find_unused_clobbered_reg (void);
  static void s390_frame_info (void);
  static rtx save_fpr (rtx, int, int);
*************** general_s_operand (register rtx op, enum
*** 1139,1168 ****
  
    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.  */
        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;
  
        /* 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;
  
        default:
  	break;
--- 1136,1165 ----
  
    switch (GET_CODE (op))
      {
!       /* 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)
! 	  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))
! 	  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;
*************** s390_output_symbolic_const (FILE *file, 
*** 3278,3288 ****
          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");
--- 3275,3280 ----
*************** find_constant_pool_ref (rtx x, rtx *ref)
*** 3876,3881 ****
--- 3868,3877 ----
    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))
*************** struct constant_pool
*** 4071,4078 ****
    int size;
  };
  
! 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);
--- 4067,4078 ----
    int size;
  };
  
! 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);
*************** static void s390_add_pool_insn (struct c
*** 4081,4087 ****
  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 void s390_free_pool (struct constant_pool *);
  
  /* Create new constant pool covering instructions starting at INSN
--- 4081,4088 ----
  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 *, 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
*************** static struct constant_pool *
*** 4091,4108 ****
  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->first_insn = insn;
-   pool->pool_insn = NULL_RTX;
-   pool->insns = BITMAP_XMALLOC ();
-   pool->size = 0;
  
    for (prev = pool_list; *prev; prev = &(*prev)->next)
      ;
--- 4092,4100 ----
  s390_start_pool (struct constant_pool **pool_list, rtx insn)
  {
    struct constant_pool *pool, **prev;
  
!   pool = s390_alloc_pool ();
    pool->first_insn = insn;
  
    for (prev = pool_list; *prev; prev = &(*prev)->next)
      ;
*************** s390_find_constant (struct constant_pool
*** 4208,4217 ****
    return offset;
  }
  
! /* Dump out the constants in POOL.  */
  
  static rtx
! s390_dump_pool (struct constant_pool *pool)
  {
    struct constant *c;
    rtx insn;
--- 4200,4210 ----
    return offset;
  }
  
! /* 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, bool remote_label)
  {
    struct constant *c;
    rtx insn;
*************** s390_dump_pool (struct constant_pool *po
*** 4225,4232 ****
      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);
  
    /* Dump constants in descending alignment requirement order,
       ensuring proper alignment for every constant.  */
--- 4218,4228 ----
      insn = emit_insn_after (gen_pool_start_31 (), pool->pool_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.  */
*************** s390_dump_pool (struct constant_pool *po
*** 4272,4277 ****
--- 4268,4295 ----
    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
*************** s390_free_pool (struct constant_pool *po
*** 4295,4310 ****
  }
  
  
! /* Chunkify the literal pool if required.  */
  
  #define S390_POOL_CHUNK_MIN	0xc00
  #define S390_POOL_CHUNK_MAX	0xe00
  
  static struct constant_pool *
! s390_chunkify_start (void)
  {
-   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;
--- 4313,4494 ----
  }
  
  
! /* 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 (rtx base_reg)
  {
    struct constant_pool *curr_pool = NULL, *pool_list = NULL;
    int extra_size = 0;
    bitmap far_labels;
*************** s390_chunkify_start (void)
*** 4315,4325 ****
      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 ());
--- 4499,4504 ----
*************** s390_chunkify_start (void)
*** 4568,4579 ****
  
  /* 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.  */
  
  static void
! s390_chunkify_finish (struct constant_pool *pool_list)
  {
-   rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
    struct constant_pool *curr_pool = NULL;
    rtx insn;
  
--- 4747,4758 ----
  
  /* 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.  */
  
  static void
! s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
  {
    struct constant_pool *curr_pool = NULL;
    rtx insn;
  
*************** s390_chunkify_finish (struct constant_po
*** 4607,4613 ****
    /* 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.  */
  
--- 4786,4792 ----
    /* Dump out all literal pools.  */
  
    for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
!     s390_dump_pool (curr_pool, 0);
  
    /* Free pool list.  */
  
*************** s390_chunkify_cancel (struct constant_po
*** 4680,4724 ****
  }
  
  
- /* 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.  */
  
--- 4859,4864 ----
*************** s390_output_pool_entry (FILE *file, rtx 
*** 4760,4788 ****
  
  
  /* 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 (int temp_regno)
  {
    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[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)
--- 4900,4922 ----
  
  
  /* Rework the prolog/epilog to avoid saving/restoring
!    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 (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] = base_used;
!   regs_ever_live[RETURN_REGNUM] = temp_used;
    regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
  
    /* 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)
*************** s390_optimize_prolog (int temp_regno)
*** 4791,4800 ****
        || 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.  */
  
--- 4925,4930 ----
*************** static void
*** 4919,4932 ****
  s390_reorg (void)
  {
    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
--- 5049,5075 ----
  s390_reorg (void)
  {
    rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
!   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 ();
  
  
!   /* 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
*************** s390_reorg (void)
*** 4957,4987 ****
  
    for (;;)
      {
!       struct constant_pool *pool_list;
  
!       /* Try to chunkify the literal pool.  */
!       pool_list = s390_chunkify_start ();
  
        /* 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;
          }
  
        /* 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);
  
        break;
      }
  
!   s390_optimize_prolog (temp_used? RETURN_REGNUM : -1);
  }
  
  
--- 5100,5147 ----
  
    for (;;)
      {
!       struct constant_pool *pool = NULL;
! 
!       /* 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_overflow)
!             s390_chunkify_cancel (pool);
! 	  else
!             s390_mainpool_cancel (pool);
  
            continue;
          }
  
        /* 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)
! 	base_used = true;
! 
!       if (pool_overflow)
! 	s390_chunkify_finish (pool, base_reg);
!       else
! 	s390_mainpool_finish (pool, base_reg);
  
        break;
      }
  
!   s390_optimize_prolog (base_used, temp_used);
  }
  
  
*************** s390_emit_prologue (void)
*** 5305,5311 ****
  {
    rtx insn, addr;
    rtx temp_reg;
-   rtx pool_start_label, pool_end_label;
    int i;
  
    /* Compute frame_info.  */
--- 5465,5470 ----
*************** s390_emit_prologue (void)
*** 5327,5344 ****
  		    cfun->machine->first_save_gpr, cfun->machine->last_save_gpr);
    emit_insn (insn);
  
!   /* Dump constant pool and set constant pool register.  */
! 
!   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));
  
    /* Save fprs for variable args.  */
  
--- 5486,5494 ----
  		    cfun->machine->first_save_gpr, cfun->machine->last_save_gpr);
    emit_insn (insn);
  
!   /* Dummy insn to mark literal pool slot.  */
  
!   emit_insn (gen_main_pool ());
  
    /* Save fprs for variable args.  */
  
Index: gcc/config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.83
diff -c -p -r1.83 s390.h
*** gcc/config/s390/s390.h	26 Aug 2003 20:39:45 -0000	1.83
--- gcc/config/s390/s390.h	27 Aug 2003 16:01:56 -0000
*************** do {									\
*** 1012,1046 ****
  } 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.  */
--- 1012,1017 ----
Index: gcc/config/s390/s390.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v
retrieving revision 1.72
diff -c -p -r1.72 s390.md
*** gcc/config/s390/s390.md	26 Aug 2003 14:53:53 -0000	1.72
--- gcc/config/s390/s390.md	27 Aug 2003 16:01:57 -0000
***************
*** 65,70 ****
--- 65,71 ----
  
     ; Literal pool
     (UNSPEC_RELOAD_BASE		210)
+    (UNSPEC_MAIN_BASE		211)
  
     ; TLS relocation specifiers
     (UNSPEC_TLSGD		500)
***************
*** 7232,7237 ****
--- 7233,7268 ----
    [(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))]
***************
*** 7289,7330 ****
    [(set_attr "op_type" "RR")
     (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.
--- 7320,7325 ----
-- 
  Dr. Ulrich Weigand
  weigand@informatik.uni-erlangen.de



More information about the Gcc-patches mailing list