This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix -mno-accumulate-outgoing-args -fasynchronous-unwind-tables (PR rtl-optimization/36419)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 11 Jun 2008 09:31:08 -0400
- Subject: [PATCH] Fix -mno-accumulate-outgoing-args -fasynchronous-unwind-tables (PR rtl-optimization/36419)
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
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