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]

Fix mips PR bootstrap/13145


This patch fixes PR 13145, a bootstrap failure on mips-linux-gnu.
The problem was that a function's lazy binding stub was being called twice.

To recap, the lowered form of a GOT load uses a MEM to represent the
GOT entry.  In the case of %call* accesses, this MEM is marked as
!RTX_UNCHANGING_P.  This was _supposed_ to stop gcc from reusing call
addresses or moving the load across a call.  But in hindsight, it has
the rather obvious flaw of not working for const and pure functions.

I thought one way of fixing this would be to make calls clobber
(mem:BLK gp).  But even if we put the MEM into the got alias set,
it would still alias things in set 0.  And (not suprisingly) there's
not really any support for such a clobber anyway.

I think the neatest fix would be to introduce a fixed, call-clobbered
register that acts something like a "GOT version number".  If we make
the call address depend on this register, the optimisers will know
that it could be modified by any call insn.

[ By the way, the original reason for using MEMs for GOT accesses was
  precisely so that we could have variable call address entries.  I couldn't
  think of any other way of handling it, at least not without crippling
  the scheduler.  Wish I'd thought of this a year ago...  

  If we do change calls to use UNSPECs rather than MEMs, it might be a good
  idea to do the same for non-call accesses.  It'd only be a small change,
  but not one that's suitable for stage 3. ]

Patch bootstrapped & regression tested on mips-sgi-irix6.5 and
mips64el-linux-gnu.  I also started a bootstrap on mips-linux-gnu but
lost contact with the machine part way through.  The bootstrap itself
succeeded though, and the build was well into libjava.  That's
definitely an improvement over the current stage 2 failure.

I also scanned the c-torture assembly code for invalid address sharing
but couldn't see any.  The patch also seems to produce better code.
OK to install?

[ FWIW, the mips-linux-gnu box should be back up on Monday or Tuesday.
  I'll retest then to make sure. ]

Richard


	PR bootstrap/13145
	* config/mips/mips.h (FIRST_PSEUDO_REGISTER): Adjust comment.
	* config/mips/mips.c (mips_reg_names, mips_sw_reg_names): Add $fcall.
	(mips_load_got): Always create a constant MEM.
	(mips_expand_call): Use load_callsi and load_calldi.
	* config/mips/mips.md (UNSPEC_LOAD_CALL, FAKE_CALL_REGNO): New consts.
	(load_callsi, load_calldi): New patterns.

Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.344
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.344 mips.c
--- config/mips/mips.c	16 Nov 2003 19:10:08 -0000	1.344
+++ config/mips/mips.c	29 Nov 2003 12:10:22 -0000
@@ -569,7 +569,7 @@ char mips_reg_names[][8] =
  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
  "hi",   "lo",   "",     "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
- "$fcc5","$fcc6","$fcc7","", "",     "",     "",     "",
+ "$fcc5","$fcc6","$fcc7","", "",     "",     "",     "$fakec",
  "$c0r0", "$c0r1", "$c0r2", "$c0r3", "$c0r4", "$c0r5", "$c0r6", "$c0r7",
  "$c0r8", "$c0r9", "$c0r10","$c0r11","$c0r12","$c0r13","$c0r14","$c0r15",
  "$c0r16","$c0r17","$c0r18","$c0r19","$c0r20","$c0r21","$c0r22","$c0r23",
@@ -598,7 +598,7 @@ char mips_sw_reg_names[][8] =
   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
   "hi",   "lo",   "",     "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
-  "$fcc5","$fcc6","$fcc7","$rap", "",     "",     "",     "",
+  "$fcc5","$fcc6","$fcc7","$rap", "",     "",     "",     "$fakec",
   "$c0r0", "$c0r1", "$c0r2", "$c0r3", "$c0r4", "$c0r5", "$c0r6", "$c0r7",
   "$c0r8", "$c0r9", "$c0r10","$c0r11","$c0r12","$c0r13","$c0r14","$c0r15",
   "$c0r16","$c0r17","$c0r18","$c0r19","$c0r20","$c0r21","$c0r22","$c0r23",
@@ -1658,14 +1658,10 @@ mips_load_got (rtx base, rtx addr, enum 
   mem = gen_rtx_MEM (ptr_mode, gen_rtx_LO_SUM (Pmode, base, offset));
   set_mem_alias_set (mem, mips_got_alias_set);
 
-  /* GOT references can't trap.  */
+  /* GOT entries are constant and references to them can't trap.  */
+  RTX_UNCHANGING_P (mem) = 1;
   MEM_NOTRAP_P (mem) = 1;
 
-  /* If we allow a function's address to be lazily bound, its entry
-     may change after the first call.  Other entries are constant.  */
-  if (symbol_type != SYMBOL_GOTOFF_CALL)
-    RTX_UNCHANGING_P (mem) = 1;
-
   return mem;
 }
 
@@ -3193,11 +3189,20 @@ mips_expand_call (rtx result, rtx addr, 
     {
       if (TARGET_EXPLICIT_RELOCS && global_got_operand (addr, VOIDmode))
 	{
-	  rtx high = mips_unspec_offset_high (pic_offset_table_rtx,
-					      addr, SYMBOL_GOTOFF_CALL);
-	  addr = mips_load_got (high, addr, SYMBOL_GOTOFF_CALL);
+	  rtx high, lo_sum_symbol, reg;
+
+	  high = mips_unspec_offset_high (pic_offset_table_rtx,
+					  addr, SYMBOL_GOTOFF_CALL);
+	  lo_sum_symbol = mips_unspec_address (addr, SYMBOL_GOTOFF_CALL);
+	  reg = gen_reg_rtx (Pmode);
+	  if (Pmode == SImode)
+	    emit_insn (gen_load_callsi (reg, high, lo_sum_symbol));
+	  else
+	    emit_insn (gen_load_calldi (reg, high, lo_sum_symbol));
+	  addr = reg;
 	}
-      addr = force_reg (Pmode, addr);
+      else
+	addr = force_reg (Pmode, addr);
     }
 
   if (TARGET_MIPS16
Index: config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.304
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.304 mips.h
--- config/mips/mips.h	4 Nov 2003 22:13:30 -0000	1.304
+++ config/mips/mips.h	29 Nov 2003 12:10:24 -0000
@@ -1468,7 +1468,8 @@ #define PROMOTE_FUNCTION_RETURN
    - 8 condition code registers
    - 2 accumulator registers (hi and lo)
    - 32 registers each for coprocessors 0, 2 and 3
-   - 6 dummy entries that were used at various times in the past.  */
+   - FAKE_CALL_REGNO (see the comment above load_callsi for details)
+   - 5 dummy entries that were used at various times in the past.  */
 
 #define FIRST_PSEUDO_REGISTER 176
 
Index: config/mips/mips.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.md,v
retrieving revision 1.209
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.209 mips.md
--- config/mips/mips.md	14 Nov 2003 17:28:25 -0000	1.209
+++ config/mips/mips.md	29 Nov 2003 12:10:25 -0000
@@ -54,8 +54,11 @@ (define_constants
    (UNSPEC_SDL			24)
    (UNSPEC_SDR			25)
    (UNSPEC_LOADGP		26)
+   (UNSPEC_LOAD_CALL		27)
 
-   (UNSPEC_ADDRESS_FIRST	100)])
+   (UNSPEC_ADDRESS_FIRST	100)
+
+   (FAKE_CALL_REGNO		79)])
 
 ;; ....................
 ;;
@@ -8330,6 +8333,42 @@ (define_insn "exception_receiver"
 ;;	FUNCTION CALLS
 ;;
 ;;  ....................
+
+;; Instructions to load a call address from the GOT.  The address might
+;; point to a function or to a lazy binding stub.  In the latter case,
+;; the stub will use the dynamic linker to resolve the function, which
+;; in turn will change the GOT entry to point to the function's real
+;; address.
+;;
+;; This means that every call, even pure and constant ones, can
+;; potentially modify the GOT entry.  And once a stub has been called,
+;; we must not call it again.
+;;
+;; We represent this restriction using an imaginary fixed register that
+;; acts like a GOT version number.  By making the register call-clobbered,
+;; we tell the target-independent code that the address could be changed
+;; by any call insn.
+(define_insn "load_callsi"
+  [(set (match_operand:SI 0 "register_operand" "=c")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "r")
+		    (match_operand:SI 2 "immediate_operand" "")
+		    (reg:SI FAKE_CALL_REGNO)]
+		   UNSPEC_LOAD_CALL))]
+  "TARGET_ABICALLS"
+  "lw\t%0,%R2(%1)"
+  [(set_attr "type" "load")
+   (set_attr "length" "4")])
+
+(define_insn "load_calldi"
+  [(set (match_operand:DI 0 "register_operand" "=c")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "r")
+		    (match_operand:DI 2 "immediate_operand" "")
+		    (reg:DI FAKE_CALL_REGNO)]
+		   UNSPEC_LOAD_CALL))]
+  "TARGET_ABICALLS"
+  "ld\t%0,%R2(%1)"
+  [(set_attr "type" "load")
+   (set_attr "length" "4")])
 
 ;; Sibling calls.  All these patterns use jump instructions.
 


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