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 PR target/14599 (mips16 memory corruption)


MIPS16 uses a pseudo register as the global pointer, initialising it to
a special constant at the beginning of the function.  This constant has
traditionally been (const (reg $gp)) (a register inside a CONST ;),
which has finally got the hammering it deserves.

In the test case, we have a libcall whose REG_EQUAL note is:

    (float_truncate:DF (mem:DF (lo_sum:SI (reg:SI 183)
                                          (symbol_ref:SI "ud"))))

where reg 183 is the gp pseudo.  During gcse, cselib sets up the
following replacements:

    (reg $gp) -> a VALUE rtx
    (reg 183) -> (const (reg $gp)) -> (const (value))

so when do_local_cprop() processes the libcall, it tries to replace
(reg 183) with (const (value)).  The substitution fails in the libcall
patterns themselves, but try_replace_reg() still makes the suggested
change to the REG_EQUAL.  And AFAIK, that's correct, if not always optimal.

Anyway, the upshot is, a VALUE rtx enters the rtl stream and stays
around until after cselib_finish().  This causes memory access problems
later on.

I suspect the same thing could have happened in 3.3 and earlier,
but it's become more a problem now that cselib uses alloc pools
to handle VALUE rtxes.

The problem is easily fixed by replacing (const (reg $gp)) with
a more sensible representation, such as a (const (unspec ...)).
Patch tested on mips64vrel-elf.  Also bootstrapped & regression
tested on mips-sgi-irix6.5 and mips64{,el}-linux-gnu.  Applied
to head.

Richard


	PR target/14599
	* config/mips/mips.md (UNSPEC_GP): New constant.
	* config/mips/mips.c (CONST_GP_P): Expect the CONST to contain
	an UNSPEC instead of (reg $gp).
	(mips16_gp_pseudo_reg): Change accordingly.
	(print_operand): Print $gp directly when handling CONST_GP_P.

Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.362.4.11
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.362.4.11 mips.c
--- config/mips/mips.c	7 Mar 2004 10:52:40 -0000	1.362.4.11
+++ config/mips/mips.c	15 Mar 2004 22:08:42 -0000
@@ -92,10 +92,12 @@ #define UNSPEC_ADDRESS(X) \
 #define UNSPEC_ADDRESS_TYPE(X) \
   ((enum mips_symbol_type) (XINT (X, 1) - UNSPEC_ADDRESS_FIRST))
 
-/* True if X is (const $gp).  This is used to initialize the mips16
-   gp pseudo register.  */
+/* True if X is (const (unspec [(const_int 0)] UNSPEC_GP)).  This is used
+   to initialize the mips16 gp pseudo register.  */
 #define CONST_GP_P(X) \
-  (GET_CODE (X) == CONST && XEXP (X, 0) == pic_offset_table_rtx)
+  (GET_CODE (X) == CONST			\
+   && GET_CODE (XEXP (X, 0)) == UNSPEC		\
+   && XINT (XEXP (X, 0), 1) == UNSPEC_GP)
 
 /* The maximum distance between the top of the stack frame and the
    value $sp has when we save & restore registers.
@@ -5601,7 +5603,7 @@ print_operand (FILE *file, rtx op, int l
     fputs (code == EQ ? "t" : "f", file);
 
   else if (CONST_GP_P (op))
-    print_operand (file, XEXP (op, 0), letter);
+    fputs (reg_names[GLOBAL_POINTER_REGNUM], file);
 
   else
     output_addr_const (file, op);
@@ -7841,7 +7843,7 @@ mips16_gp_pseudo_reg (void)
 {
   if (cfun->machine->mips16_gp_pseudo_rtx == NULL_RTX)
     {
-      rtx const_gp;
+      rtx unspec;
       rtx insn, scan;
 
       cfun->machine->mips16_gp_pseudo_rtx = gen_reg_rtx (Pmode);
@@ -7849,10 +7851,10 @@ mips16_gp_pseudo_reg (void)
 
       /* We want to initialize this to a value which gcc will believe
          is constant.  */
-      const_gp = gen_rtx_CONST (Pmode, pic_offset_table_rtx);
       start_sequence ();
+      unspec = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, const0_rtx), UNSPEC_GP);
       emit_move_insn (cfun->machine->mips16_gp_pseudo_rtx,
-		      const_gp);
+		      gen_rtx_CONST (Pmode, unspec));
       insn = get_insns ();
       end_sequence ();
 
Index: config/mips/mips.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.md,v
retrieving revision 1.211.4.4
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.211.4.4 mips.md
--- config/mips/mips.md	19 Feb 2004 22:56:11 -0000	1.211.4.4
+++ config/mips/mips.md	15 Mar 2004 22:08:43 -0000
@@ -55,6 +55,7 @@ (define_constants
    (UNSPEC_SDR			25)
    (UNSPEC_LOADGP		26)
    (UNSPEC_LOAD_CALL		27)
+   (UNSPEC_GP			29)
 
    (UNSPEC_ADDRESS_FIRST	100)
 


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