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]

Re: Patch to fix mips GOT overflow


Richard Henderson <rth@redhat.com> writes:
> On Sun, Sep 28, 2003 at 09:51:36AM +0100, Richard Sandiford wrote:
> > We try to rename $gp for n32 & n64 (the code being based on the x86 port).
> > I didn't think it would be possible to do that optimisation and still lower
> > gp stuff after reload.
> 
> I don't see why not.

Er... no, me neither. ;/

> > Besides, the optimisers already seem quite good at handling the lowered form,
> > especially now we have delegitimize_address.  I was hoping, what with that
> > and with tree-ssa, there'd be less need to maintain a two-level thing.
> 
> I don't know.  Perhaps it isn't worthwhile anymore.  Perhaps it is
> sufficient to teach a few places like combine need to to expect the
> pic register as an operand to lo_sum.

Would the patch below be OK?  The idea is to hide HIGH behind two target
hooks, one to create the high part of an address, another to check whether
a given rtx is the high part.

Wrt the small data case: the patch tries converting (mem CONST) into
(mem (lo_sum $pic CONST)) in combine_simplify_rtx, but only if the
target hooks say that the second form is legitimate.

This is really Plan B.  Plan A was avoid hard-coding the pic register
and instead change combine_simplify_rtx to:

    -----------------------------------------------------------
    case MEM:
       /* Ensure that our address has any ASHIFTs converted to MULT in case
	  address-recognizing predicates are called later.  */
       temp = make_compound_operation (XEXP (x, 0), MEM);

#ifdef have_lo_sum
      if (CONSTANT_P (temp) && !CONSTANT_ADDRESS_P (temp))
	temp = gen_rtx_LO_SUM (Pmode, targetm.matching_high (temp), temp);
#endif
    -----------------------------------------------------------

and then reduce the find_split_point handling from:

    -----------------------------------------------------------
    case MEM:
#ifdef HAVE_lo_sum
      /* If we have (mem (const ..)) or (mem (symbol_ref ...)), split it
	 using LO_SUM and HIGH.  */
      if (GET_CODE (XEXP (x, 0)) == CONST
	  || GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
	{
	  SUBST (XEXP (x, 0),
		 gen_rtx_LO_SUM (Pmode,
				 gen_rtx_HIGH (Pmode, XEXP (x, 0)),
				 XEXP (x, 0)));
	  return &XEXP (XEXP (x, 0), 0);
	}
#endif
    -----------------------------------------------------------
to:
    -----------------------------------------------------------
    case MEM:
#ifdef HAVE_lo_sum
      if (GET_CODE (XEXP (x, 0)) == LO_SUM)
	return &XEXP (XEXP (x, 0), 0);
#endif
    -----------------------------------------------------------

But this splits addresses inside call mems, which wasn't really the idea.
At least this version should have no effect on ports thats don't define
the new hooks.

Anyway, in the mips port, we're now using lo_sum for three things:

   - normal %hi/%lo split (general absolute addresses)
   - %gp_rel (small data addresses)
   - %got_page/%got_ofst and %got/%lo splits (local pic addresses)

This patch seems to optimise the last two cases in the same way
as the first.

Tested on mips64{,el}-linux-gnu, mips-sgi-irix6.5{,o32} and
mipsisa64-elf.  OK to install?

Richard


	* target.h (matching_high_p, matching_high): New hooks.
	* target-def.h (TARGET_MATCHING_HIGH_P): New macro.
	(TARGET_MATCHING_HIGH): Likewise.
	(TARGET_INITIALIZER): Include them.
	* targhooks.h (default_matching_high_p): Declare.
	(default_matching_high): Declare.
	* targhooks.c (default_matching_high_p): New function.
	(default_matching_high): Likewise.
	* combine.c (find_split_point): Use targetm.matching_high.
	(combine_simplify_rtx): If simplifying a MEM, see whether the
	address can be converted into a LO_SUM of the PIC register.
	Use targetm.matching_high_p.
	* cse.c (fold_rtx): Use targetm.matching_high_p.
	* simplify-rtx.c (simplify_replace_rtx): Likewise.
	(simplify_rtx): Likewise.
	* config/mips/mips.c (mips_matching_high_p): New function.
	(mips_matching_high): New function.
	(mips_emit_high): Use mips_matching_high.
	(TARGET_MATCHING_HIGH_P, TARGET_MATCHING_HIGH): Define.
	* doc/tm.tex: Document the new target hooks.

Index: target.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target.h,v
retrieving revision 1.62
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.62 target.h
*** target.h	4 Sep 2003 03:17:51 -0000	1.62
--- target.h	1 Oct 2003 19:35:05 -0000
*************** struct gcc_target
*** 313,318 ****
--- 313,321 ----
    /* Given an address RTX, undo the effects of LEGITIMIZE_ADDRESS.  */
    rtx (* delegitimize_address) (rtx);
  
+   bool (* matching_high_p) (rtx, rtx);
+   rtx (* matching_high) (rtx);
+ 
    /* True if it is OK to do sibling call optimization for the specified
       call expression EXP.  DECL will be the called function, or NULL if
       this is an indirect call.  */
Index: target-def.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target-def.h,v
retrieving revision 1.55
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.55 target-def.h
*** target-def.h	4 Sep 2003 03:17:51 -0000	1.55
--- target-def.h	1 Oct 2003 19:35:06 -0000
*************** #define TARGET_BRANCH_TARGET_REGISTER_CA
*** 287,292 ****
--- 287,294 ----
  #define TARGET_CANNOT_FORCE_CONST_MEM hook_bool_rtx_false
  #define TARGET_CANNOT_COPY_INSN_P NULL
  #define TARGET_DELEGITIMIZE_ADDRESS hook_rtx_rtx_identity
+ #define TARGET_MATCHING_HIGH_P default_matching_high_p
+ #define TARGET_MATCHING_HIGH default_matching_high
  #define TARGET_FUNCTION_OK_FOR_SIBCALL hook_bool_tree_tree_false
  #define TARGET_COMP_TYPE_ATTRIBUTES hook_int_tree_tree_1
  #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES hook_void_tree
*************** #define TARGET_INITIALIZER			\
*** 351,356 ****
--- 353,360 ----
    TARGET_CANNOT_FORCE_CONST_MEM,		\
    TARGET_CANNOT_COPY_INSN_P,			\
    TARGET_DELEGITIMIZE_ADDRESS,			\
+   TARGET_MATCHING_HIGH_P,			\
+   TARGET_MATCHING_HIGH,				\
    TARGET_FUNCTION_OK_FOR_SIBCALL,		\
    TARGET_IN_SMALL_DATA_P,			\
    TARGET_BINDS_LOCAL_P,				\
Index: targhooks.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/targhooks.h,v
retrieving revision 2.1
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r2.1 targhooks.h
*** targhooks.h	4 Sep 2003 03:17:51 -0000	2.1
--- targhooks.h	1 Oct 2003 19:35:06 -0000
*************** extern rtx default_expand_builtin_savere
*** 29,31 ****
--- 29,33 ----
  extern void default_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);
  extern bool default_strict_argument_naming (CUMULATIVE_ARGS *);
  extern bool default_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *);
+ extern bool default_matching_high_p (rtx, rtx);
+ extern rtx default_matching_high (rtx);
Index: targhooks.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/targhooks.c,v
retrieving revision 2.5
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r2.5 targhooks.c
*** targhooks.c	5 Sep 2003 02:12:29 -0000	2.5
--- targhooks.c	1 Oct 2003 19:35:06 -0000
*************** default_pretend_outgoing_varargs_named(C
*** 189,191 ****
--- 189,203 ----
  #endif
  #endif
  }
+ 
+ rtx
+ default_matching_high (rtx addr)
+ {
+   return gen_rtx_HIGH (Pmode, addr);
+ }
+ 
+ bool
+ default_matching_high_p (rtx test, rtx addr)
+ {
+   return (GET_CODE (test) == HIGH && rtx_equal_p (XEXP (test, 0), addr));
+ }
Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.388
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.388 combine.c
*** combine.c	26 Sep 2003 06:05:48 -0000	1.388
--- combine.c	1 Oct 2003 19:35:09 -0000
*************** find_split_point (rtx *loc, rtx insn)
*** 2883,2889 ****
  	{
  	  SUBST (XEXP (x, 0),
  		 gen_rtx_LO_SUM (Pmode,
! 				 gen_rtx_HIGH (Pmode, XEXP (x, 0)),
  				 XEXP (x, 0)));
  	  return &XEXP (XEXP (x, 0), 0);
  	}
--- 2883,2889 ----
  	{
  	  SUBST (XEXP (x, 0),
  		 gen_rtx_LO_SUM (Pmode,
! 				 targetm.matching_high (XEXP (x, 0)),
  				 XEXP (x, 0)));
  	  return &XEXP (XEXP (x, 0), 0);
  	}
*************** combine_simplify_rtx (rtx x, enum machin
*** 3806,3811 ****
--- 3806,3821 ----
        /* Ensure that our address has any ASHIFTs converted to MULT in case
  	 address-recognizing predicates are called later.  */
        temp = make_compound_operation (XEXP (x, 0), MEM);
+ 
+ #ifdef HAVE_lo_sum
+       /* If the address is constant, try replacing it with a LO_SUM of $gp.
+ 	 This is used by some ports to represent small data accesses.  */
+       if (CONSTANT_P (temp)
+ 	  && pic_offset_table_rtx != 0
+ 	  && targetm.matching_high_p (pic_offset_table_rtx, temp))
+ 	temp = gen_rtx_LO_SUM (Pmode, targetm.matching_high (temp), temp);
+ #endif
+ 
        SUBST (XEXP (x, 0), temp);
        break;
  
*************** combine_simplify_rtx (rtx x, enum machin
*** 4109,4116 ****
        /* Convert (lo_sum (high FOO) FOO) to FOO.  This is necessary so we
  	 can add in an offset.  find_split_point will split this address up
  	 again if it doesn't match.  */
!       if (GET_CODE (XEXP (x, 0)) == HIGH
! 	  && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1)))
  	return XEXP (x, 1);
        break;
  #endif
--- 4119,4125 ----
        /* Convert (lo_sum (high FOO) FOO) to FOO.  This is necessary so we
  	 can add in an offset.  find_split_point will split this address up
  	 again if it doesn't match.  */
!       if (targetm.matching_high_p (XEXP (x, 0), XEXP (x, 1)))
  	return XEXP (x, 1);
        break;
  #endif
Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.271
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.271 cse.c
*** cse.c	26 Jul 2003 15:53:14 -0000	1.271
--- cse.c	1 Oct 2003 19:35:12 -0000
*************** fold_rtx (rtx x, rtx insn)
*** 4224,4232 ****
  
      case 'o':
        /* (lo_sum (high X) X) is simply X.  */
!       if (code == LO_SUM && const_arg0 != 0
! 	  && GET_CODE (const_arg0) == HIGH
! 	  && rtx_equal_p (XEXP (const_arg0, 0), const_arg1))
  	return const_arg1;
        break;
  
--- 4224,4232 ----
  
      case 'o':
        /* (lo_sum (high X) X) is simply X.  */
!       if (code == LO_SUM
! 	  && const_arg0 != 0
! 	  && targetm.matching_high_p (const_arg0, const_arg1))
  	return const_arg1;
        break;
  
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.157
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.157 simplify-rtx.c
*** simplify-rtx.c	4 Sep 2003 01:52:59 -0000	1.157
--- simplify-rtx.c	1 Oct 2003 19:35:12 -0000
*************** simplify_replace_rtx (rtx x, rtx old, rt
*** 334,340 ****
  	  rtx op1 = simplify_replace_rtx (XEXP (x, 1), old, new);
  
  	  /* (lo_sum (high x) x) -> x  */
! 	  if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
  	    return op1;
  
  	  return gen_rtx_LO_SUM (mode, op0, op1);
--- 334,340 ----
  	  rtx op1 = simplify_replace_rtx (XEXP (x, 1), old, new);
  
  	  /* (lo_sum (high x) x) -> x  */
! 	  if (targetm.matching_high_p (op0, op1))
  	    return op1;
  
  	  return gen_rtx_LO_SUM (mode, op0, op1);
*************** simplify_rtx (rtx x)
*** 3207,3219 ****
        break;
  
      case 'o':
!       if (code == LO_SUM)
! 	{
! 	  /* Convert (lo_sum (high FOO) FOO) to FOO.  */
! 	  if (GET_CODE (XEXP (x, 0)) == HIGH
! 	      && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1)))
! 	  return XEXP (x, 1);
! 	}
        break;
  
      default:
--- 3207,3214 ----
        break;
  
      case 'o':
!       if (code == LO_SUM && targetm.matching_high_p (XEXP (x, 0), XEXP (x, 1)))
! 	return XEXP (x, 1);
        break;
  
      default:
Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.317
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.317 mips.c
*** config/mips/mips.c	30 Sep 2003 07:14:39 -0000	1.317
--- config/mips/mips.c	1 Oct 2003 19:35:15 -0000
*************** static enum mips_address_type
*** 182,187 ****
--- 182,189 ----
    mips_classify_address (struct mips_address_info *, rtx,
  			 enum machine_mode, int, int);
  static bool mips_splittable_symbol_p (enum mips_symbol_type, HOST_WIDE_INT);
+ static bool mips_matching_high_p (rtx, rtx);
+ static rtx mips_matching_high (rtx);
  static int mips_symbol_insns (enum mips_symbol_type);
  static bool mips16_unextended_reference_p (enum machine_mode mode, rtx, rtx);
  static rtx mips_reloc (rtx, int);
*************** #define TARGET_RTX_COSTS mips_rtx_costs
*** 761,766 ****
--- 763,772 ----
  #define TARGET_ADDRESS_COST mips_address_cost
  #undef TARGET_DELEGITIMIZE_ADDRESS
  #define TARGET_DELEGITIMIZE_ADDRESS mips_delegitimize_address
+ #undef TARGET_MATCHING_HIGH_P
+ #define TARGET_MATCHING_HIGH_P mips_matching_high_p
+ #undef TARGET_MATCHING_HIGH
+ #define TARGET_MATCHING_HIGH mips_matching_high
  
  #undef TARGET_ENCODE_SECTION_INFO
  #define TARGET_ENCODE_SECTION_INFO mips_encode_section_info
*************** mips_splittable_symbol_p (enum mips_symb
*** 1086,1091 ****
--- 1092,1157 ----
  }
  
  
+ /* Implement TARGET_MATCHING_HIGH_P.  Handle the special cases and
+    fall through to the generic HIGH handling.  */
+ 
+ bool
+ mips_matching_high_p (rtx x, rtx addr)
+ {
+   struct mips_constant_info cx, caddr;
+ 
+   if (mips_classify_constant (&caddr, addr) == CONSTANT_SYMBOLIC)
+     switch (mips_classify_symbol (caddr.symbol))
+       {
+       case SYMBOL_GOT_LOCAL:
+ 	if (GET_CODE (x) == MEM)
+ 	  {
+ 	    rtx x1 = XEXP (x, 0);
+ 	    if (GET_CODE (x1) == PLUS
+ 		&& XEXP (x1, 0) == pic_offset_table_rtx
+ 		&& mips_classify_constant (&cx, XEXP (x1, 1)) == CONSTANT_RELOC
+ 		&& cx.symbol == caddr.symbol
+ 		&& cx.offset == caddr.offset)
+ 	      return true;
+ 	  }
+ 	break;
+ 
+       case SYMBOL_SMALL_DATA:
+ 	if (x == pic_offset_table_rtx)
+ 	  return true;
+ 	break;
+ 
+       default:
+ 	break;
+       }
+ 
+   return default_matching_high_p (x, addr);
+ }
+ 
+ 
+ /* Likewise TARGET_MATCHING_HIGH.  */
+ 
+ rtx
+ mips_matching_high (rtx addr)
+ {
+   struct mips_constant_info c;
+ 
+   if (mips_classify_constant (&c, addr) == CONSTANT_SYMBOLIC)
+     switch (mips_classify_symbol (c.symbol))
+       {
+       case SYMBOL_GOT_LOCAL:
+ 	return mips_load_got16 (addr, RELOC_GOT_PAGE);
+ 
+       case SYMBOL_SMALL_DATA:
+ 	return pic_offset_table_rtx;
+ 
+       default:
+ 	break;
+       }
+   return default_matching_high (addr);
+ }
+ 
+ 
  /* Return the number of instructions needed to load a symbol of the
     given type into a register.  If valid in an address, the same number
     of instructions are needed for loads and stores.  Treat extended
*************** mips_emit_high (rtx dest, rtx addr)
*** 1675,1689 ****
  {
    rtx high, x;
  
!   high = gen_rtx_HIGH (Pmode, addr);
!   if (TARGET_ABICALLS)
!     {
!       x = mips_load_got16 (copy_rtx (addr), RELOC_GOT_PAGE);
!       x = mips_force_temporary (dest, x);
!       set_unique_reg_note (get_last_insn (), REG_EQUAL, high);
!     }
!   else
!     x = mips_force_temporary (dest, high);
  
    return x;
  }
--- 1741,1751 ----
  {
    rtx high, x;
  
!   high = targetm.matching_high (addr);
!   x = mips_force_temporary (dest, high);
!   if (GET_CODE (high) != HIGH)
!     set_unique_reg_note (get_last_insn (), REG_EQUAL,
! 			 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
  
    return x;
  }
Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.255
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.255 tm.texi
*** doc/tm.texi	4 Sep 2003 03:18:03 -0000	1.255
--- doc/tm.texi	1 Oct 2003 19:35:19 -0000
*************** an immediate operand on the target machi
*** 5015,5020 ****
--- 5015,5049 ----
  anything @code{CONSTANT_P} is valid.
  @end defmac
  
+ @findex lo_sum
+ @findex high
+ @deftypefn {Target Hook} bool TARGET_MATCHING_HIGH (rtx @var{addr})
+ If @var{addr} can be used in a @code{lo_sum}, return an rtx for
+ the high part.  The return value doesn't matter otherwise.
+ 
+ It is always safe to return @samp{(high @var{addr})}, which is
+ the generic representation for the high part of an address.  Hoever,
+ some ports might prefer to use a more specific represenation instead.
+ 
+ For example, if the high part is loaded from the GOT, the target might
+ represent it as a memory reference.  If the address refers to small data,
+ the target might use @code{pic_offset_table_rtx} as the high part.
+ 
+ The default implementation just returns @samp{(high @var{addr})}.
+ Any use of the return value must be verified in the usual way.
+ @end deftypefn
+ 
+ @findex lo_sum
+ @findex high
+ @deftypefn {Target Hook} bool TARGET_MATCHING_HIGH_P (rtx @var{x}, rtx @var{addr})
+ Return true if @code{(lo_sum @var{x} @var{addr})} is equal to
+ @var{addr}.  This is always true if @var{x} is @samp{(high @var{addr})}.
+ However, some ports might also have other valid values for @var{x};
+ see @code{TARGET_MATCHING_HIGH}.
+ 
+ The default implementation just checks for @samp{(high @var{addr})}.
+ @end deftypefn
+ 
  @node Condition Code
  @section Condition Code Status
  @cindex condition code status


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