Patchwork [committed] Fix PR target/49307

login
register
mail settings
Submitter Kaz Kojima
Date June 9, 2011, 10:23 p.m.
Message ID <20110610.072355.479886092.kkojima@rr.iij4u.or.jp>
Download mbox | patch
Permalink /patch/99817/
State New
Headers show

Comments

Kaz Kojima - June 9, 2011, 10:23 p.m.
Hi,

The attached patch is to fix PR target/49307.  In the faulty case,
protector inserts PIC codes after the result register R0 is set
and IRA combines a few of them into a load from a memory which
needs R0 to spill.  The patch use a unspec and an insn_and_split to
hide the above PIC codes from IRA and other early passes to avoid
this unexpected combining.  Tested on sh4-unknown-linux-gnu with no
new failures.  I've added a dg testcase which is tested also on
i686-pc-linux-gnu.  Applied on trunk.

I'll backport this patch to 4.5/4.6 branches since this PR is
a regression on those branches.

Regards,
	kaz
--
2011-06-09  Kaz Kojima  <kkojima@gcc.gnu.org>

	PR target/49307
	* config/sh/sh.md (UNSPEC_CHKADD): New.
	(chk_guard_add): New define_insn_and_split.
	(symGOT_load): Use chk_guard_add instead of blockage.

[testsuite]
	PR target/49307
	* gcc.dg/pr49307.c: New.

Patch

diff -uprN ORIG/trunk/gcc/config/sh/sh.md trunk/gcc/config/sh/sh.md
--- ORIG/trunk/gcc/config/sh/sh.md	2010-08-28 13:32:01.000000000 +0900
+++ trunk/gcc/config/sh/sh.md	2011-06-08 14:32:11.000000000 +0900
@@ -150,6 +150,7 @@ 
   (UNSPEC_DIV_INV_TABLE	37)
   (UNSPEC_ASHIFTRT	35)
   (UNSPEC_THUNK		36)
+  (UNSPEC_CHKADD	38)
   (UNSPEC_SP_SET	40)
   (UNSPEC_SP_TEST	41)
   (UNSPEC_MOVUA		42)
@@ -8454,6 +8455,22 @@  label:
   i++;
 }")
 
+;; op0 = op1 + r12 but hide it before reload completed.  See the comment
+;; in symGOT_load expand.
+
+(define_insn_and_split "chk_guard_add"
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "r")
+		    (reg:SI PIC_REG)]
+		   UNSPEC_CHKADD))]
+  "TARGET_SH1"
+  "#"
+  "TARGET_SH1 && reload_completed"
+  [(set (match_dup 0) (reg:SI PIC_REG))
+   (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
+  ""
+  [(set_attr "type" "arith")])
+
 (define_expand "sym_label2reg"
   [(set (match_operand:SI 0 "" "")
 	(const:SI (unspec:SI [(match_operand:SI 1 "" "")
@@ -8496,13 +8513,9 @@  label:
   else
     emit_move_insn (operands[2], operands[1]);
 
-  emit_move_insn (operands[3], gen_rtx_PLUS (Pmode,
-					     operands[2],
-					     gen_rtx_REG (Pmode, PIC_REG)));
-
   /* When stack protector inserts codes after the result is set to
-     R0, @(rX, r12) will cause a spill failure for R0.  Don't schedule
-     insns to avoid combining (set A (plus rX r12)) and (set op0 (mem A))
+     R0, @(rX, r12) will cause a spill failure for R0.  Use a unspec
+     insn to avoid combining (set A (plus rX r12)) and (set op0 (mem A))
      when rX is a GOT address for the guard symbol.  Ugly but doesn't
      matter because this is a rare situation.  */
   if (!TARGET_SHMEDIA
@@ -8512,7 +8525,10 @@  label:
       && GET_CODE (XVECEXP (XEXP (operands[1], 0), 0, 0)) == SYMBOL_REF
       && strcmp (XSTR (XVECEXP (XEXP (operands[1], 0), 0, 0), 0),
 		 \"__stack_chk_guard\") == 0)
-    emit_insn (gen_blockage ());
+    emit_insn (gen_chk_guard_add (operands[3], operands[2]));
+  else
+    emit_move_insn (operands[3], gen_rtx_PLUS (Pmode, operands[2],
+					       gen_rtx_REG (Pmode, PIC_REG)));
 
   /* N.B. This is not constant for a GOTPLT relocation.  */
   mem = gen_rtx_MEM (Pmode, operands[3]);
diff -uprN ORIG/trunk/gcc/testsuite/gcc.dg/pr49307.c trunk/gcc/testsuite/gcc.dg/pr49307.c
--- ORIG/trunk/gcc/testsuite/gcc.dg/pr49307.c	1970-01-01 09:00:00.000000000 +0900
+++ trunk/gcc/testsuite/gcc.dg/pr49307.c	2011-06-09 08:37:41.000000000 +0900
@@ -0,0 +1,21 @@ 
+/* PR target/49307 */
+/* { dg-do compile } */
+/* { dg-options "-O -fpic -fstack-protector" } */
+/* { dg-require-effective-target fpic } */
+/* { dg-require-effective-target fstack_protector } */
+
+extern void bar (char **pp, void *vp);
+extern void free (void *p);
+
+int
+foo (void)
+{
+  char *p;
+  char fext[128];
+
+  p = fext;
+  bar (&p, (void *)0);
+  if (p)
+    free (p);
+  return 0;
+}