public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [Committed] S/390: Fix PR55718: Handle GOTENT + constant for pic addresses
@ 2013-01-10  8:19 Andreas Krebbel
  0 siblings, 0 replies; only message in thread
From: Andreas Krebbel @ 2013-01-10  8:19 UTC (permalink / raw)
  To: gcc-patches

Hi,

I've committed the attached patch which fixes PR 55718 by adding
support for GOTENT + constant to legitimize_pic_address in the S/390
backend.

The patch also does some rearrangements of the whole function in order
to avoid some duplicate code.

Bye,

-Andreas-


2013-01-10  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	PR target/55718
	* config/s390/s390.c (s390_symref_operand_p)
	(s390_loadrelative_operand_p): Merge the two functions.
	(s390_check_qrst_address, print_operand_address): Add parameters
	to s390_loadrelative_operand_p invokation.
	(s390_check_symref_alignment): Use s390_loadrelative_operand_p.
	(s390_reload_larl_operand, s390_secondary_reload): Use
	s390_loadrelative_operand_p instead of s390_symref_operand_p.
	(legitimize_pic_address): Handle @GOTENT and @PLT + addend.

---
 gcc/config/s390/s390.c                  |  474 ++-!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 gcc/testsuite/gcc.target/s390/pr55718.c |   29 +
 2 files changed, 65 insertions(+), 10 deletions(-), 428 modifications(!)

Index: gcc/config/s390/s390.c
===================================================================
*** gcc/config/s390/s390.c.orig
--- gcc/config/s390/s390.c
*************** s390_legitimate_address_without_index_p 
*** 2148,2160 ****
  }
  
  
! /* Return true if ADDR is of kind symbol_ref or symbol_ref + const_int
!    and return these parts in SYMREF and ADDEND.  You can pass NULL in
!    SYMREF and/or ADDEND if you are not interested in these values.
!    Literal pool references are *not* considered symbol references.  */
  
  static bool
! s390_symref_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend)
  {
    HOST_WIDE_INT tmpaddend = 0;
  
--- 2148,2164 ----
  }
  
  
! /* Return TRUE if ADDR is an operand valid for a load/store relative
!    instruction.  Be aware that the alignment of the operand needs to
!    be checked separately.
!    Valid addresses are single references or a sum of a reference and a
!    constant integer. Return these parts in SYMREF and ADDEND.  You can
!    pass NULL in REF and/or ADDEND if you are not interested in these
!    values.  Literal pool references are *not* considered symbol
!    references.  */
  
  static bool
! s390_loadrelative_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend)
  {
    HOST_WIDE_INT tmpaddend = 0;
  
*************** s390_symref_operand_p (rtx addr, rtx *sy
*** 2163,2205 ****
  
    if (GET_CODE (addr) == PLUS)
      {
!       if (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF
! 	  && !CONSTANT_POOL_ADDRESS_P (XEXP (addr, 0))
! 	  && CONST_INT_P (XEXP (addr, 1)))
! 	{
! 	  tmpaddend = INTVAL (XEXP (addr, 1));
! 	  addr = XEXP (addr, 0);
! 	}
!       else
  	return false;
-     }
-   else
-     if (GET_CODE (addr) != SYMBOL_REF || CONSTANT_POOL_ADDRESS_P (addr))
- 	return false;
- 
-   if (symref)
-     *symref = addr;
-   if (addend)
-     *addend = tmpaddend;
  
!   return true;
! }
! 
! /* Return TRUE if ADDR is an operand valid for a load/store relative
!    instructions.  Be aware that the alignment of the operand needs to
!    be checked separately.  */
! static bool
! s390_loadrelative_operand_p (rtx addr)
! {
!   if (GET_CODE (addr) == CONST)
!     addr = XEXP (addr, 0);
  
!   /* Enable load relative for symbol@GOTENT.  */
!   if (GET_CODE (addr) == UNSPEC
!       && XINT (addr, 1) == UNSPEC_GOTENT)
!     return true;
  
!   return s390_symref_operand_p (addr, NULL, NULL);
  }
  
  /* Return true if the address in OP is valid for constraint letter C
--- 2167,2192 ----
  
    if (GET_CODE (addr) == PLUS)
      {
!       if (!CONST_INT_P (XEXP (addr, 1)))
  	return false;
  
!       tmpaddend = INTVAL (XEXP (addr, 1));
!       addr = XEXP (addr, 0);
!     }
  
!   if ((GET_CODE (addr) == SYMBOL_REF && !CONSTANT_POOL_ADDRESS_P (addr))
!       || (GET_CODE (addr) == UNSPEC
! 	  && (XINT (addr, 1) == UNSPEC_GOTENT
! 	      || (TARGET_CPU_ZARCH && XINT (addr, 1) == UNSPEC_PLT))))
!     {
!       if (symref)
! 	*symref = addr;
!       if (addend)
! 	*addend = tmpaddend;
  
!       return true;
!     }
!   return false;
  }
  
  /* Return true if the address in OP is valid for constraint letter C
*************** s390_check_qrst_address (char c, rtx op,
*** 2215,2221 ****
  
    /* This check makes sure that no symbolic address (except literal
       pool references) are accepted by the R or T constraints.  */
!   if (s390_loadrelative_operand_p (op))
      return 0;
  
    /* Ensure literal pool references are only accepted if LIT_POOL_OK.  */
--- 2202,2208 ----
  
    /* This check makes sure that no symbolic address (except literal
       pool references) are accepted by the R or T constraints.  */
!   if (s390_loadrelative_operand_p (op, NULL, NULL))
      return 0;
  
    /* Ensure literal pool references are only accepted if LIT_POOL_OK.  */
*************** s390_check_symref_alignment (rtx addr, H
*** 3022,3039 ****
    HOST_WIDE_INT addend;
    rtx symref;
  
!   /* Accept symbol@GOTENT with pointer size alignment.  */
!   if (GET_CODE (addr) == CONST
!       && GET_CODE (XEXP (addr, 0)) == UNSPEC
!       && XINT (XEXP (addr, 0), 1) == UNSPEC_GOTENT
!       && alignment <= UNITS_PER_LONG)
!     return true;
  
!   if (!s390_symref_operand_p (addr, &symref, &addend))
      return false;
  
!   return (!SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref)
! 	  && !(addend & (alignment - 1)));
  }
  
  /* ADDR is moved into REG using larl.  If ADDR isn't a valid larl
--- 3009,3029 ----
    HOST_WIDE_INT addend;
    rtx symref;
  
!   if (!s390_loadrelative_operand_p (addr, &symref, &addend))
!     return false;
  
!   if (addend & (alignment - 1))
      return false;
  
!   if (GET_CODE (symref) == SYMBOL_REF
!       && !SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref))
!     return true;
! 
!   if (GET_CODE (symref) == UNSPEC
!       && alignment <= UNITS_PER_LONG)
!     return true;
! 
!   return false;
  }
  
  /* ADDR is moved into REG using larl.  If ADDR isn't a valid larl
*************** s390_reload_larl_operand (rtx reg, rtx a
*** 3046,3052 ****
    HOST_WIDE_INT addend;
    rtx symref;
  
!   if (!s390_symref_operand_p (addr, &symref, &addend))
      gcc_unreachable ();
  
    if (!(addend & 1))
--- 3036,3042 ----
    HOST_WIDE_INT addend;
    rtx symref;
  
!   if (!s390_loadrelative_operand_p (addr, &symref, &addend))
      gcc_unreachable ();
  
    if (!(addend & 1))
*************** s390_secondary_reload (bool in_p, rtx x,
*** 3132,3138 ****
        /* On z10 several optimizer steps may generate larl operands with
  	 an odd addend.  */
        if (in_p
! 	  && s390_symref_operand_p (x, &symref, &offset)
  	  && mode == Pmode
  	  && !SYMBOL_REF_ALIGN1_P (symref)
  	  && (offset & 1) == 1)
--- 3122,3128 ----
        /* On z10 several optimizer steps may generate larl operands with
  	 an odd addend.  */
        if (in_p
! 	  && s390_loadrelative_operand_p (x, &symref, &offset)
  	  && mode == Pmode
  	  && !SYMBOL_REF_ALIGN1_P (symref)
  	  && (offset & 1) == 1)
*************** s390_secondary_reload (bool in_p, rtx x,
*** 3144,3150 ****
  	 or if the symref addend of a SI or DI move is not aligned to the
  	 width of the access.  */
        if (MEM_P (x)
! 	  && s390_symref_operand_p (XEXP (x, 0), NULL, NULL)
  	  && (mode == QImode || mode == TImode || FLOAT_MODE_P (mode)
  	      || (!TARGET_ZARCH && mode == DImode)
  	      || ((mode == HImode || mode == SImode || mode == DImode)
--- 3134,3140 ----
  	 or if the symref addend of a SI or DI move is not aligned to the
  	 width of the access.  */
        if (MEM_P (x)
! 	  && s390_loadrelative_operand_p (XEXP (x, 0), NULL, NULL)
  	  && (mode == QImode || mode == TImode || FLOAT_MODE_P (mode)
  	      || (!TARGET_ZARCH && mode == DImode)
  	      || ((mode == HImode || mode == SImode || mode == DImode)
*************** rtx
*** 3419,3470 ****
  legitimize_pic_address (rtx orig, rtx reg)
  {
    rtx addr = orig;
    rtx new_rtx = orig;
-   rtx base;
  
    gcc_assert (!TLS_SYMBOLIC_CONST (addr));
  
!   if (GET_CODE (addr) == LABEL_REF
!       || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr)))
      {
!       /* This is a local symbol.  */
!       if (TARGET_CPU_ZARCH && larl_operand (addr, VOIDmode))
!         {
!           /* Access local symbols PC-relative via LARL.
!              This is the same as in the non-PIC case, so it is
!              handled automatically ...  */
!         }
        else
!         {
!           /* Access local symbols relative to the GOT.  */
  
!           rtx temp = reg? reg : gen_reg_rtx (Pmode);
  
  	  if (reload_in_progress || reload_completed)
  	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
  
!           addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
!           addr = gen_rtx_CONST (Pmode, addr);
!           addr = force_const_mem (Pmode, addr);
  	  emit_move_insn (temp, addr);
  
!           new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
!           if (reg != 0)
!             {
!               s390_load_address (reg, new_rtx);
!               new_rtx = reg;
!             }
!         }
      }
!   else if (GET_CODE (addr) == SYMBOL_REF)
      {
        if (reg == 0)
          reg = gen_reg_rtx (Pmode);
  
!       if (flag_pic == 1)
          {
!           /* Assume GOT offset < 4k.  This is handled the same way
!              in both 31- and 64-bit code (@GOT).  */
  
  	  if (reload_in_progress || reload_completed)
  	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
--- 3409,3533 ----
  legitimize_pic_address (rtx orig, rtx reg)
  {
    rtx addr = orig;
+   rtx addend = const0_rtx;
    rtx new_rtx = orig;
  
    gcc_assert (!TLS_SYMBOLIC_CONST (addr));
  
!   if (GET_CODE (addr) == CONST)
!     addr = XEXP (addr, 0);
! 
!   if (GET_CODE (addr) == PLUS)
      {
!       addend = XEXP (addr, 1);
!       addr = XEXP (addr, 0);
!     }
! 
!   if ((GET_CODE (addr) == LABEL_REF
!        || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr))
!        || (GET_CODE (addr) == UNSPEC &&
! 	   (XINT (addr, 1) == UNSPEC_GOTENT
! 	    || (TARGET_CPU_ZARCH && XINT (addr, 1) == UNSPEC_PLT))))
!       && GET_CODE (addend) == CONST_INT)
!     {
!       /* This can be locally addressed.  */
! 
!       /* larl_operand requires UNSPECs to be wrapped in a const rtx.  */
!       rtx const_addr = (GET_CODE (addr) == UNSPEC ?
! 			gen_rtx_CONST (Pmode, addr) : addr);
! 
!       if (TARGET_CPU_ZARCH
! 	  && larl_operand (const_addr, VOIDmode)
! 	  && INTVAL (addend) < (HOST_WIDE_INT)1 << 31
! 	  && INTVAL (addend) >= -((HOST_WIDE_INT)1 << 31))
! 	{
! 	  if (INTVAL (addend) & 1)
! 	    {
! 	      /* LARL can't handle odd offsets, so emit a pair of LARL
! 		 and LA.  */
! 	      rtx temp = reg? reg : gen_reg_rtx (Pmode);
! 
! 	      if (!DISP_IN_RANGE (INTVAL (addend)))
! 		{
! 		  HOST_WIDE_INT even = INTVAL (addend) - 1;
! 		  addr = gen_rtx_PLUS (Pmode, addr, GEN_INT (even));
! 		  addr = gen_rtx_CONST (Pmode, addr);
! 		  addend = const1_rtx;
! 		}
! 
! 	      emit_move_insn (temp, addr);
! 	      new_rtx = gen_rtx_PLUS (Pmode, temp, addend);
! 
! 	      if (reg != 0)
! 		{
! 		  s390_load_address (reg, new_rtx);
! 		  new_rtx = reg;
! 		}
! 	    }
! 	  else
! 	    {
! 	      /* If the offset is even, we can just use LARL.  This
! 		 will happen automatically.  */
! 	    }
! 	}
        else
! 	{
! 	  /* No larl - Access local symbols relative to the GOT.  */
  
! 	  rtx temp = reg? reg : gen_reg_rtx (Pmode);
  
  	  if (reload_in_progress || reload_completed)
  	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
  
! 	  addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
! 	  if (addend != const0_rtx)
! 	    addr = gen_rtx_PLUS (Pmode, addr, addend);
! 	  addr = gen_rtx_CONST (Pmode, addr);
! 	  addr = force_const_mem (Pmode, addr);
  	  emit_move_insn (temp, addr);
  
! 	  new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
! 	  if (reg != 0)
! 	    {
! 	      s390_load_address (reg, new_rtx);
! 	      new_rtx = reg;
! 	    }
! 	}
      }
!   else if (GET_CODE (addr) == SYMBOL_REF && addend == const0_rtx)
      {
+       /* A non-local symbol reference without addend.
+ 
+ 	 The symbol ref is wrapped into an UNSPEC to make sure the
+ 	 proper operand modifier (@GOT or @GOTENT) will be emitted.
+ 	 This will tell the linker to put the symbol into the GOT.
+ 
+ 	 Additionally the code dereferencing the GOT slot is emitted here.
+ 
+ 	 An addend to the symref needs to be added afterwards.
+ 	 legitimize_pic_address calls itself recursively to handle
+ 	 that case.  So no need to do it here.  */
+ 
        if (reg == 0)
          reg = gen_reg_rtx (Pmode);
  
!       if (TARGET_Z10)
! 	{
! 	  /* Use load relative if possible.
! 	     lgrl <target>, sym@GOTENT  */
! 	  new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT);
! 	  new_rtx = gen_rtx_CONST (Pmode, new_rtx);
! 	  new_rtx = gen_const_mem (GET_MODE (reg), new_rtx);
! 
! 	  emit_move_insn (reg, new_rtx);
! 	  new_rtx = reg;
! 	}
!       else if (flag_pic == 1)
          {
!           /* Assume GOT offset is a valid displacement operand (< 4k
!              or < 512k with z990).  This is handled the same way in
!              both 31- and 64-bit code (@GOT).
!              lg <target>, sym@GOT(r12)  */
  
  	  if (reload_in_progress || reload_completed)
  	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
*************** legitimize_pic_address (rtx orig, rtx re
*** 3479,3485 ****
        else if (TARGET_CPU_ZARCH)
          {
            /* If the GOT offset might be >= 4k, we determine the position
!              of the GOT entry via a PC-relative LARL (@GOTENT).  */
  
            rtx temp = reg ? reg : gen_reg_rtx (Pmode);
  
--- 3542,3550 ----
        else if (TARGET_CPU_ZARCH)
          {
            /* If the GOT offset might be >= 4k, we determine the position
!              of the GOT entry via a PC-relative LARL (@GOTENT).
! 	     larl temp, sym@GOTENT
!              lg   <target>, 0(temp) */
  
            rtx temp = reg ? reg : gen_reg_rtx (Pmode);
  
*************** legitimize_pic_address (rtx orig, rtx re
*** 3488,3508 ****
  
            new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT);
            new_rtx = gen_rtx_CONST (Pmode, new_rtx);
  
! 	  if (!TARGET_Z10)
! 	    {
! 	      emit_move_insn (temp, new_rtx);
! 	      new_rtx = gen_const_mem (Pmode, temp);
! 	    }
! 	  else
! 	    new_rtx = gen_const_mem (GET_MODE (reg), new_rtx);
            emit_move_insn (reg, new_rtx);
            new_rtx = reg;
          }
        else
          {
            /* If the GOT offset might be >= 4k, we have to load it
!              from the literal pool (@GOT).  */
  
            rtx temp = reg ? reg : gen_reg_rtx (Pmode);
  
--- 3553,3573 ----
  
            new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT);
            new_rtx = gen_rtx_CONST (Pmode, new_rtx);
+ 	  emit_move_insn (temp, new_rtx);
  
! 	  new_rtx = gen_const_mem (Pmode, temp);
            emit_move_insn (reg, new_rtx);
+ 
            new_rtx = reg;
          }
        else
          {
            /* If the GOT offset might be >= 4k, we have to load it
!              from the literal pool (@GOT).
! 
! 	     lg temp, lit-litbase(r13)
!              lg <target>, 0(temp)
! 	     lit:  .long sym@GOT  */
  
            rtx temp = reg ? reg : gen_reg_rtx (Pmode);
  
*************** legitimize_pic_address (rtx orig, rtx re
*** 3523,3697 ****
            new_rtx = reg;
          }
      }
!   else
      {
!       if (GET_CODE (addr) == CONST)
  	{
! 	  addr = XEXP (addr, 0);
! 	  if (GET_CODE (addr) == UNSPEC)
! 	    {
! 	      gcc_assert (XVECLEN (addr, 0) == 1);
!               switch (XINT (addr, 1))
!                 {
!                   /* If someone moved a GOT-relative UNSPEC
!                      out of the literal pool, force them back in.  */
!                   case UNSPEC_GOTOFF:
!                   case UNSPEC_PLTOFF:
!                     new_rtx = force_const_mem (Pmode, orig);
!                     break;
! 
!                   /* @GOT is OK as is if small.  */
! 		  case UNSPEC_GOT:
! 		    if (flag_pic == 2)
! 		      new_rtx = force_const_mem (Pmode, orig);
! 		    break;
! 
!                   /* @GOTENT is OK as is.  */
!                   case UNSPEC_GOTENT:
!                     break;
! 
!                   /* @PLT is OK as is on 64-bit, must be converted to
!                      GOT-relative @PLTOFF on 31-bit.  */
!                   case UNSPEC_PLT:
!                     if (!TARGET_CPU_ZARCH)
!                       {
!                         rtx temp = reg? reg : gen_reg_rtx (Pmode);
! 
! 			if (reload_in_progress || reload_completed)
! 			  df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
! 
!                         addr = XVECEXP (addr, 0, 0);
!                         addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
! 					       UNSPEC_PLTOFF);
!                         addr = gen_rtx_CONST (Pmode, addr);
!                         addr = force_const_mem (Pmode, addr);
! 	                emit_move_insn (temp, addr);
! 
!                         new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
!                         if (reg != 0)
!                           {
!                             s390_load_address (reg, new_rtx);
!                             new_rtx = reg;
!                           }
!                       }
!                     break;
! 
!                   /* Everything else cannot happen.  */
!                   default:
!                     gcc_unreachable ();
!                 }
! 	    }
! 	  else
! 	    gcc_assert (GET_CODE (addr) == PLUS);
! 	}
!       if (GET_CODE (addr) == PLUS)
! 	{
! 	  rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
  
! 	  gcc_assert (!TLS_SYMBOLIC_CONST (op0));
! 	  gcc_assert (!TLS_SYMBOLIC_CONST (op1));
  
! 	  /* Check first to see if this is a constant offset
!              from a local symbol reference.  */
! 	  if ((GET_CODE (op0) == LABEL_REF
! 		|| (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (op0)))
! 	      && GET_CODE (op1) == CONST_INT)
! 	    {
!               if (TARGET_CPU_ZARCH
! 		  && larl_operand (op0, VOIDmode)
! 		  && INTVAL (op1) < (HOST_WIDE_INT)1 << 31
! 		  && INTVAL (op1) >= -((HOST_WIDE_INT)1 << 31))
!                 {
!                   if (INTVAL (op1) & 1)
!                     {
!                       /* LARL can't handle odd offsets, so emit a
!                          pair of LARL and LA.  */
!                       rtx temp = reg? reg : gen_reg_rtx (Pmode);
! 
!                       if (!DISP_IN_RANGE (INTVAL (op1)))
!                         {
!                           HOST_WIDE_INT even = INTVAL (op1) - 1;
!                           op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even));
! 			  op0 = gen_rtx_CONST (Pmode, op0);
!                           op1 = const1_rtx;
!                         }
! 
!                       emit_move_insn (temp, op0);
!                       new_rtx = gen_rtx_PLUS (Pmode, temp, op1);
! 
!                       if (reg != 0)
!                         {
!                           s390_load_address (reg, new_rtx);
!                           new_rtx = reg;
!                         }
!                     }
!                   else
!                     {
!                       /* If the offset is even, we can just use LARL.
!                          This will happen automatically.  */
!                     }
!                 }
!               else
!                 {
!                   /* Access local symbols relative to the GOT.  */
! 
!                   rtx temp = reg? reg : gen_reg_rtx (Pmode);
! 
! 		  if (reload_in_progress || reload_completed)
! 		    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
! 
!                   addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
! 					 UNSPEC_GOTOFF);
!                   addr = gen_rtx_PLUS (Pmode, addr, op1);
!                   addr = gen_rtx_CONST (Pmode, addr);
!                   addr = force_const_mem (Pmode, addr);
! 		  emit_move_insn (temp, addr);
! 
!                   new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
!                   if (reg != 0)
!                     {
!                       s390_load_address (reg, new_rtx);
!                       new_rtx = reg;
!                     }
!                 }
! 	    }
! 
!           /* Now, check whether it is a GOT relative symbol plus offset
!              that was pulled out of the literal pool.  Force it back in.  */
! 
! 	  else if (GET_CODE (op0) == UNSPEC
! 	           && GET_CODE (op1) == CONST_INT
! 	           && XINT (op0, 1) == UNSPEC_GOTOFF)
!             {
! 	      gcc_assert (XVECLEN (op0, 0) == 1);
  
!               new_rtx = force_const_mem (Pmode, orig);
!             }
  
!           /* Otherwise, compute the sum.  */
! 	  else
! 	    {
! 	      base = legitimize_pic_address (XEXP (addr, 0), reg);
! 	      new_rtx  = legitimize_pic_address (XEXP (addr, 1),
! 					     base == reg ? NULL_RTX : reg);
! 	      if (GET_CODE (new_rtx) == CONST_INT)
! 		new_rtx = plus_constant (Pmode, base, INTVAL (new_rtx));
! 	      else
  		{
! 		  if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1)))
! 		    {
! 		      base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0));
! 		      new_rtx = XEXP (new_rtx, 1);
! 		    }
! 		  new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx);
  		}
  
! 	      if (GET_CODE (new_rtx) == CONST)
! 		new_rtx = XEXP (new_rtx, 0);
!               new_rtx = force_operand (new_rtx, 0);
  	    }
  	}
      }
    return new_rtx;
  }
  
--- 3588,3681 ----
            new_rtx = reg;
          }
      }
!   else if (GET_CODE (addr) == UNSPEC && GET_CODE (addend) == CONST_INT)
      {
!       gcc_assert (XVECLEN (addr, 0) == 1);
!       switch (XINT (addr, 1))
  	{
! 	  /* These address symbols (or PLT slots) relative to the GOT
! 	     (not GOT slots!).  In general this will exceed the
! 	     displacement range so these value belong into the literal
! 	     pool.  */
! 	case UNSPEC_GOTOFF:
! 	case UNSPEC_PLTOFF:
! 	  new_rtx = force_const_mem (Pmode, orig);
! 	  break;
  
! 	  /* For -fPIC the GOT size might exceed the displacement
! 	     range so make sure the value is in the literal pool.  */
! 	case UNSPEC_GOT:
! 	  if (flag_pic == 2)
! 	    new_rtx = force_const_mem (Pmode, orig);
! 	  break;
  
! 	  /* For @GOTENT larl is used.  This is handled like local
! 	     symbol refs.  */
! 	case UNSPEC_GOTENT:
! 	  gcc_unreachable ();
! 	  break;
  
! 	  /* @PLT is OK as is on 64-bit, must be converted to
! 	     GOT-relative @PLTOFF on 31-bit.  */
! 	case UNSPEC_PLT:
! 	  if (!TARGET_CPU_ZARCH)
! 	    {
! 	      rtx temp = reg? reg : gen_reg_rtx (Pmode);
! 
! 	      if (reload_in_progress || reload_completed)
! 		df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
! 
! 	      addr = XVECEXP (addr, 0, 0);
! 	      addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
! 				     UNSPEC_PLTOFF);
! 	      if (addend != const0_rtx)
! 		addr = gen_rtx_PLUS (Pmode, addr, addend);
! 	      addr = gen_rtx_CONST (Pmode, addr);
! 	      addr = force_const_mem (Pmode, addr);
! 	      emit_move_insn (temp, addr);
  
! 	      new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
! 	      if (reg != 0)
  		{
! 		  s390_load_address (reg, new_rtx);
! 		  new_rtx = reg;
  		}
+ 	    }
+ 	  else
+ 	    /* On 64 bit larl can be used.  This case is handled like
+ 	       local symbol refs.  */
+ 	    gcc_unreachable ();
+ 	  break;
+ 
+ 	  /* Everything else cannot happen.  */
+ 	default:
+ 	  gcc_unreachable ();
+ 	}
+     }
+   else if (addend != const0_rtx)
+     {
+       /* Otherwise, compute the sum.  */
  
!       rtx base = legitimize_pic_address (addr, reg);
!       new_rtx  = legitimize_pic_address (addend,
! 					 base == reg ? NULL_RTX : reg);
!       if (GET_CODE (new_rtx) == CONST_INT)
! 	new_rtx = plus_constant (Pmode, base, INTVAL (new_rtx));
!       else
! 	{
! 	  if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1)))
! 	    {
! 	      base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0));
! 	      new_rtx = XEXP (new_rtx, 1);
  	    }
+ 	  new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx);
  	}
+ 
+       if (GET_CODE (new_rtx) == CONST)
+ 	new_rtx = XEXP (new_rtx, 0);
+       new_rtx = force_operand (new_rtx, 0);
      }
+ 
    return new_rtx;
  }
  
*************** print_operand_address (FILE *file, rtx a
*** 5350,5356 ****
  {
    struct s390_address ad;
  
!   if (s390_loadrelative_operand_p (addr))
      {
        if (!TARGET_Z10)
  	{
--- 5334,5340 ----
  {
    struct s390_address ad;
  
!   if (s390_loadrelative_operand_p (addr, NULL, NULL))
      {
        if (!TARGET_Z10)
  	{
Index: gcc/testsuite/gcc.target/s390/pr55718.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/pr55718.c
***************
*** 0 ****
--- 1,29 ----
+ /* PR target/55717  */
+ 
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -march=z10 -fPIC" } */
+ 
+ extern char temp[];
+ short ansi_value[256];
+ void terminal_state(void)
+ {
+   static const char *puc[] = { "", "<", "=", ">", "?", 0};
+   int i, j, k, l, modes_found;
+   char buf[256];
+   k = (int) __builtin_strlen(temp);
+   for (j = l = 0; j < 255 && j - l < 50; j++)
+     {
+       __builtin_sprintf(temp, "\033[%s%d$p", puc[i], j);
+       if (ansi_value[1])
+         {
+           l = j;
+           buf[k] = '\0';
+           put_crlf();
+           ptextln(buf);
+           buf[k++] = ' ';
+           k = (int) __builtin_strlen(temp);
+         }
+     }
+   for (i = j = 0; j < modes_found; j = ++i >> 1)
+     ;
+ }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2013-01-10  8:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-10  8:19 [Committed] S/390: Fix PR55718: Handle GOTENT + constant for pic addresses Andreas Krebbel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).