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]

[PATCH] Fix -mno-accumulate-outgoing-args -fasynchronous-unwind-tables (PR rtl-optimization/36419)


Hi!

With -mno-accumulate-outgoing-args -fasynchronous-unwind-tables
DW_CFA_GNU_args_size ops are generated for all stack changes within
the body of the function, except for prologues/epilogues.

But, the CSA pass can merge a post-prologue stack adjustment which
needs DW_CFA_GNU_args_size into the prologue stack adjustment, which results
in DW_CFA_GNU_args_size ops being incorrect in the beginning of the
function.  That in turn means invalid restored sp when catching exceptions,
see e.g. the attached testcase.  There is:
(insn/f 94 4 95 2 dd.C:41 (set (mem:SI (pre_dec:SI (reg/f:SI 7 sp)) [0 S4 A8])
        (reg/f:SI 6 bp)) -1 (nil))
(insn/f 95 94 96 2 dd.C:41 (set (reg/f:SI 6 bp)
        (reg/f:SI 7 sp)) -1 (nil))
(insn/f 96 95 97 2 dd.C:41 (parallel [
            (set (reg/f:SI 7 sp)
                (plus:SI (reg/f:SI 7 sp)
                    (const_int -8 [0xfffffffffffffff8])))
            (clobber (reg:CC 17 flags))
            (clobber (mem:BLK (scratch) [0 A8]))
        ]) -1 (nil))
(note 97 96 5 2 NOTE_INSN_PROLOGUE_END)
(insn:HI 5 97 6 2 dd.C:46 (parallel [
            (set (reg/f:SI 7 sp)
                (plus:SI (reg/f:SI 7 sp)
                    (const_int -8 [0xfffffffffffffff8])))
            (clobber (reg:CC 17 flags))
        ]) 283 {*addsi_1} (nil))
(insn:HI 6 5 7 2 dd.C:46 (set (mem/i:SI (pre_dec:SI (reg/f:SI 7 sp)) [0 S4 A32])
        (const_int 2 [0x2])) 40 {*pushsi2} (nil))
(insn:HI 7 6 8 2 dd.C:46 (set (mem/i:SI (pre_dec:SI (reg/f:SI 7 sp)) [0 S4 A32])
        (const_int 1 [0x1])) 40 {*pushsi2} (nil))
(call_insn:HI 8 7 63 2 dd.C:46 (call (mem:QI (symbol_ref:SI ("_Z3fooii") [flags 0x3] <function_decl 0x7f01266dd750 foo>) [0 S1 A8])
        (const_int 16 [0x10])) 635 {*call_0} (expr_list:REG_EH_REGION (const_int 2 [0x2])
        (nil))
    (nil))
before CSA, without CSA a DW_CFA_GNU_args_size 8 would be added after insn 5,
12 after insn 6, 16 after insn 7 and so it matches -fno-asynchronous-unwind-tables
which uses the second call argument to determine argument size.
But CSA merges this into:
(insn/f 94 4 95 2 dd.C:41 (set (mem:SI (pre_dec:SI (reg/f:SI 7 sp)) [0 S4 A8])
        (reg/f:SI 6 bp)) -1 (nil))
(insn/f 95 94 96 2 dd.C:41 (set (reg/f:SI 6 bp)
        (reg/f:SI 7 sp)) -1 (nil))
(insn/f 96 95 97 2 dd.C:41 (parallel [
            (set (reg/f:SI 7 sp)
                (plus:SI (reg/f:SI 7 sp)
                    (const_int -16 [0xfffffffffffffff0])))
            (clobber (reg:CC 17 flags))
            (clobber (mem:BLK (scratch) [0 A8]))
        ]) 868 {pro_epilogue_adjust_stack_1} (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))
(note 97 96 6 2 NOTE_INSN_PROLOGUE_END)
(insn:HI 6 97 7 2 dd.C:46 (set (mem/i:SI (pre_dec:SI (reg/f:SI 7 sp)) [0 S4 A32])
        (const_int 2 [0x2])) 40 {*pushsi2} (nil))
(insn:HI 7 6 8 2 dd.C:46 (set (mem/i:SI (pre_dec:SI (reg/f:SI 7 sp)) [0 S4 A32])
        (const_int 1 [0x1])) 40 {*pushsi2} (nil))
(call_insn:HI 8 7 63 2 dd.C:46 (call (mem:QI (symbol_ref:SI ("_Z3fooii") [flags 0x3] <function_decl 0x7f01266dd750 foo>) [0 S1 A8])
        (const_int 16 [0x10])) 635 {*call_0} (expr_list:REG_EH_REGION (const_int 2 [0x2])
        (nil))
    (nil))
and as DW_CFA_GNU_args_size isn't generated for /f insns, we end up with
DW_CFA_GNU_args_size 4 after insn 6 and 8 after insn 7, so 8 bytes
smaller value.  The following so far only lightly tested patch
fixes this by remembering CSA of non-/f insns into /f insns and adding
DW_CFA_GNU_args_size on the stack subtraction that does the combined
adjustment.

Ok for trunk if testing succeeds?  Ok for 4.3 too (with the field
in cfun-> instead of crtl->)?

2008-06-11  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/36419
	* function.c (struct rtl_data): Add initial_args_size field.
	* combine-stack-adj.c (combine_stack_adjustments_for_block): When
	merging a non-RTX_FRAME_RELATED_P adjustment into a frame related
	one, adjust crtl->initial_args_size.  Delete correct insn.
	* dwarf2out.c (dwarf2out_frame_debug_expr): Adjust
	DW_CFA_GNU_args_size if CSA pass merged some adjustments into
	prologue sp adjustment.

	* g++.dg/eh/async-unwind1.C: New test.

--- gcc/function.h.jj	2008-06-06 09:17:07.000000000 +0200
+++ gcc/function.h	2008-06-11 13:38:44.000000000 +0200
@@ -270,6 +270,9 @@ struct rtl_data GTY(())
      defined, the needed space is pushed by the prologue.  */
   int outgoing_args_size;
 
+  /* Initial args_size at the prologue stack subtraction instruction.  */
+  int initial_args_size;
+
   /* If nonzero, an RTL expression for the location at which the current
      function returns its result.  If the current function returns its
      result in a register, current_function_return_rtx will always be
--- gcc/combine-stack-adj.c.jj	2008-06-10 17:14:13.000000000 +0200
+++ gcc/combine-stack-adj.c	2008-06-11 13:40:30.000000000 +0200
@@ -344,6 +344,9 @@ combine_stack_adjustments_for_block (bas
 						  this_adjust))
 		    {
 		      /* It worked!  */
+		      if (RTX_FRAME_RELATED_P (last_sp_set)
+			  && !RTX_FRAME_RELATED_P (insn))
+			crtl->initial_args_size += this_adjust;
 		      delete_insn (insn);
 		      last_sp_adjust += this_adjust;
 		      continue;
@@ -373,7 +376,7 @@ combine_stack_adjustments_for_block (bas
 		 deallocation+allocation conspired to cancel, we can
 		 delete the old deallocation insn.  */
 	      if (last_sp_set && last_sp_adjust == 0)
-		delete_insn (insn);
+		delete_insn (last_sp_set);
 	      free_csa_memlist (memlist);
 	      memlist = NULL;
 	      last_sp_set = insn;
--- gcc/dwarf2out.c.jj	2008-06-06 09:17:07.000000000 +0200
+++ gcc/dwarf2out.c	2008-06-11 14:54:34.000000000 +0200
@@ -1658,7 +1658,21 @@ dwarf2out_frame_debug_expr (rtx expr, co
 		/* Assume we've set the source reg of the LO_SUM from sp.  */
 		;
 	      else
-		gcc_assert (XEXP (src, 0) == stack_pointer_rtx);
+		{
+		  gcc_assert (XEXP (src, 0) == stack_pointer_rtx);
+		  /* If pass_stack_adjustments merged prologue stack
+		     adjustment with following stack adjustment,
+		     add DW_CFA_GNU_args_size for it.  */
+		  if (crtl->initial_args_size
+		      && flag_asynchronous_unwind_tables
+		      && !ACCUMULATE_OUTGOING_ARGS)
+		    {
+		      args_size = -crtl->initial_args_size;
+		      gcc_assert (args_size > 0);
+		      crtl->initial_args_size = 0;
+		      dwarf2out_args_size (label, args_size);
+		    }
+		}
 
 	      if (GET_CODE (src) != MINUS)
 		offset = -offset;
--- gcc/testsuite/g++.dg/eh/async-unwind1.C.jj	2008-06-11 15:12:05.000000000 +0200
+++ gcc/testsuite/g++.dg/eh/async-unwind1.C	2008-06-11 15:10:59.000000000 +0200
@@ -0,0 +1,61 @@
+// PR rtl-optimization/36419
+// { dg-do run { target { { i?86-*-* x86_64-*-* } && ilp32 } } }
+// { dg-options "-Os -fasynchronous-unwind-tables -mpreferred-stack-boundary=4" }
+
+extern "C" void abort ();
+
+int v = -1;
+unsigned int n;
+
+__attribute__((noinline, used))
+void foo (int a, int)
+{
+  if (v < 0)
+    v = ((unsigned long) &a) & 15;
+  else if ((((unsigned long) &a) & 15) != v)
+    abort ();
+  if (n++ == 0)
+    throw 1;
+}
+
+__attribute__((noinline, used))
+void baz (int a, int, int, int, int, int, int)
+{
+  if (v < 0)
+    v = ((unsigned long) &a) & 15;
+  else if ((((unsigned long) &a) & 15) != v)
+    abort ();
+  if (n++ == 0)
+    throw 1;
+}
+
+struct A { A () { }; ~A (); char c[24]; };
+
+__attribute__((noinline))
+A::~A ()
+{
+  asm volatile ("" : : : "memory");
+}
+
+__attribute__((noinline))
+void bar ()
+{
+  A a;
+  try
+    {
+      foo (1, 2);
+      baz (3, 4, 5, 6, 7, 8, 9);
+    }
+  catch (...)
+    {
+    }
+  foo (1, 2);
+  baz (3, 4, 5, 6, 7, 8, 9);
+}
+
+int
+main ()
+{
+  bar ();
+  return 0;
+}

	Jakub


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