This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] S/390: Enable literal pool handling to deal with hot/cold sections


Hello,

the literal pool handling code in the S/390 back end is currently not
able to deal with hot/cold partitioning.

The attached patch fixes this with the following strategy for non
z/Architecture CPUs.  This all does not apply to z CPUs providing the
larl and brasl instructions even if they are run in ESA mode.

- If there is a section switch in a function which does have a literal
pool but does not need splitting the literal pool is emitted in the
same section where the literal pool base pointer is set up.
Regardless whether that's a hot or cold section the literal pool can be
accessed using the literal pool base register r13.  Only the base
register setup routine is sensible to whether the literal pool lies
within a different section or not.

This is only relevant if the literal pool and the code chunk together
do not exceed 4k.  Otherwise we emit the literal pool anyway directly
below the literal pool base setup code and jump over it.

This is handled by the changes to the s390_mainpool_* functions.  A
new field in the constant_pool struct allows s390_mainpool_start to
record where to emit the literal pool if a section switch note has
been found.


- If we need to split the literal pool anyway due to an overflow we
have to make sure that a split happens also at section switch notes
since branches between the hot and the cold section have to be
instrumented properly in order to reload the literal pool base
pointer.


Another point to take care of is the GOT pointer setup for 31bit.
Since the literal pool is part of the .text section we can't put the
GOT pointer directly into the literal pool.  Instead we put the
difference between the GOT pointer and the literal pool base pointer
into the pool.  In order to setup the GOT pointer we emit two unspecs
(LTREL_BASE and LTREL_OFFSET) which must not be split apart from each
other.  Both are emitted in the s390_emit_prologue function as a pack
without any control flow instructions in between.  Looking at the
bb-reorder code I understand that it can never happen that a section
switch occurs between instructions of a normal sequence.  Instead
these switches only occur on bb boundaries.  So I consider that case
safe and have therefore added an assertion making sure that there is
no pending ltrel unspec when hitting a section switch.


Bootstrapped and regstested on s390 and s390x.

On s390 the following testcase gets fixed:
> FAIL: gcc.dg/tree-prof/bb-reorg.c compilation,  -fprofile-use -D_PROFILE_USE
> UNRESOLVED: gcc.dg/tree-prof/bb-reorg.c execution,    -fprofile-use -D_PROFILE_USE

Uli could you please have a look?

Bye,

-Andreas-


2008-02-12  Andreas Krebbel  <krebbel1@de.ibm.com>

	* config/s390/s390.c (struct constant_pool): New field
	emit_pool_after added.
	(s390_mainpool_start): Set the emit_pool_after flag according
	to the section switch notes.
	(s390_mainpool_finish): Consider emit_pool_after when emitting
	the literal pool at the end of the function.
	(s390_chunkify_start): Force literal pool splits at section
	switch notes.


Index: gcc/config/s390/s390.c
===================================================================
*** gcc/config/s390/s390.c.orig	2008-02-11 20:15:13.000000000 +0100
--- gcc/config/s390/s390.c	2008-02-12 08:43:16.000000000 +0100
*************** struct constant_pool
*** 5325,5330 ****
--- 5325,5331 ----
    rtx first_insn;
    rtx pool_insn;
    bitmap insns;
+   rtx emit_pool_after;
  
    struct constant *constants[NR_C_MODES];
    struct constant *execute;
*************** s390_alloc_pool (void)
*** 5351,5356 ****
--- 5352,5358 ----
    pool->pool_insn = NULL_RTX;
    pool->insns = BITMAP_ALLOC (NULL);
    pool->size = 0;
+   pool->emit_pool_after = NULL_RTX;
  
    return pool;
  }
*************** s390_mainpool_start (void)
*** 5681,5686 ****
--- 5683,5689 ----
  {
    struct constant_pool *pool;
    rtx insn;
+   bool in_pool_section_p = false;
  
    pool = s390_alloc_pool ();
  
*************** s390_mainpool_start (void)
*** 5693,5698 ****
--- 5696,5702 ----
  	{
  	  gcc_assert (!pool->pool_insn);
  	  pool->pool_insn = insn;
+ 	  in_pool_section_p = true;
  	}
  
        if (!TARGET_CPU_ZARCH && s390_execute_label (insn))
*************** s390_mainpool_start (void)
*** 5710,5715 ****
--- 5714,5733 ----
  	      s390_add_constant (pool, constant, mode);
  	    }
  	}
+ 
+       /* If hot/cold partitioning is enabled we have to make sure that
+ 	 the literal pool is emitted in the same section where the
+ 	 initialization of the literal pool base pointer takes place.
+ 	 emit_pool_after is only used in the non-overflow case on non
+ 	 Z cpus where we can emit the literal pool at the end of the
+ 	 function body within the text section.  */
+       if (NOTE_P (insn)
+ 	  && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+ 	{
+ 	  if (in_pool_section_p)
+ 	    pool->emit_pool_after = PREV_INSN (insn);
+ 	  in_pool_section_p = !in_pool_section_p;
+ 	}
      }
  
    gcc_assert (pool->pool_insn || pool->size == 0);
*************** s390_mainpool_start (void)
*** 5724,5729 ****
--- 5742,5752 ----
        pool = NULL;
      }
  
+   /* If the functions ends with the section where the literal pool
+      should be emitted set the marker to its end.  */
+   if (pool && in_pool_section_p)
+     pool->emit_pool_after = get_last_insn ();
+ 
    return pool;
  }
  
*************** s390_mainpool_finish (struct constant_po
*** 5782,5788 ****
        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);
  
--- 5805,5816 ----
        insn = emit_label_after (pool->label, insn);
        INSN_ADDRESSES_NEW (insn, -1);
  
!       /* emit_pool_after will be set by s390_mainpool_start to the
! 	 last insn of the section where the literal pool should be
! 	 emitted.  */
!       gcc_assert (pool->emit_pool_after);
!       insn = pool->emit_pool_after;
! 
        pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
        INSN_ADDRESSES_NEW (pool->pool_insn, -1);
  
*************** s390_chunkify_start (void)
*** 5881,5886 ****
--- 5909,5916 ----
  
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      {
+       bool section_switch_p = false;
+ 
        /* Check for pending LTREL_BASE.  */
        if (INSN_P (insn))
  	{
*************** s390_chunkify_start (void)
*** 5935,5940 ****
--- 5965,5973 ----
  	  gcc_assert (!pending_ltrel);
  	}
  
+       if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+ 	section_switch_p = true;
+ 
        if (!curr_pool
  	  || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
            || INSN_ADDRESSES (INSN_UID (insn)) == -1)
*************** s390_chunkify_start (void)
*** 5942,5948 ****
  
        if (TARGET_CPU_ZARCH)
  	{
! 	  if (curr_pool->size < S390_POOL_CHUNK_MAX)
  	    continue;
  
  	  s390_end_pool (curr_pool, NULL_RTX);
--- 5975,5982 ----
  
        if (TARGET_CPU_ZARCH)
  	{
! 	  if (curr_pool->size < S390_POOL_CHUNK_MAX
! 	      && !section_switch_p)
  	    continue;
  
  	  s390_end_pool (curr_pool, NULL_RTX);
*************** s390_chunkify_start (void)
*** 5962,5968 ****
  	    extra_size += 6;
  
  	  if (chunk_size < S390_POOL_CHUNK_MIN
! 	      && curr_pool->size < S390_POOL_CHUNK_MIN)
  	    continue;
  
  	  /* Pool chunks can only be inserted after BARRIERs ...  */
--- 5996,6003 ----
  	    extra_size += 6;
  
  	  if (chunk_size < S390_POOL_CHUNK_MIN
! 	      && curr_pool->size < S390_POOL_CHUNK_MIN
! 	      && !section_switch_p)
  	    continue;
  
  	  /* Pool chunks can only be inserted after BARRIERs ...  */
*************** s390_chunkify_start (void)
*** 5974,5994 ****
  	    }
  
  	  /* ... 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 LTREL_BASE from the corresponding
  		 LTREL_OFFSET load.  */
! 	      if (pending_ltrel)
! 		continue;
  
  	      label = gen_label_rtx ();
  	      jump = emit_jump_insn_after (gen_jump (label), insn);
--- 6009,6041 ----
  	    }
  
  	  /* ... 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
! 		   || section_switch_p)
  	    {
                rtx label, jump, barrier;
  
! 	      if (!section_switch_p)
! 		{
! 		  /* 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 LTREL_BASE from the corresponding
  		 LTREL_OFFSET load.  */
! 		  if (pending_ltrel)
! 		    continue;
! 		}
! 	      else
! 		{
! 		  gcc_assert (!pending_ltrel);
! 
! 		  /* The old pool has to end before the section switch
! 		     note in order to make it part of the current
! 		     section.  */
! 		  insn = PREV_INSN (insn);
! 		}
  
  	      label = gen_label_rtx ();
  	      jump = emit_jump_insn_after (gen_jump (label), insn);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]