From 27004606de459d624247190ca0f752a9a9a7b76f Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 22 Aug 2005 18:58:50 +0200 Subject: [PATCH] re PR rtl-optimization/23478 (Miscompilation due to reloading of a var that is also used in EH pad) PR rtl-optimization/23478 * regs.h (reg_info): Add throw_calls_crossed. (REG_N_THROWING_CALLS_CROSSED): Define. * flow.c (allocate_reg_life_data): Initialize REG_N_THROWING_CALLS_CROSSED. (propagate_one_insn, attempt_auto_inc): Update REG_N_THROWING_CALLS_CROSSED. * global.c (global_alloc): Don't allocate pseudos across calls that may throw. * g++.dg/opt/pr23478.C: New test. From-SVN: r103348 --- gcc/ChangeLog | 12 ++ gcc/flow.c | 12 +- gcc/global.c | 4 +- gcc/regs.h | 7 + gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/opt/pr23478.C | 211 +++++++++++++++++++++++++++++ 6 files changed, 248 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/opt/pr23478.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8a5e2f00c21..3663104e59c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2005-08-22 Jakub Jelinek + + PR rtl-optimization/23478 + * regs.h (reg_info): Add throw_calls_crossed. + (REG_N_THROWING_CALLS_CROSSED): Define. + * flow.c (allocate_reg_life_data): Initialize + REG_N_THROWING_CALLS_CROSSED. + (propagate_one_insn, attempt_auto_inc): Update + REG_N_THROWING_CALLS_CROSSED. + * global.c (global_alloc): Don't allocate pseudos across + calls that may throw. + 2005-08-22 Andrew Pinski PR c/18715 diff --git a/gcc/flow.c b/gcc/flow.c index 79b26d698f0..aa45def3e7c 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -104,7 +104,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA life_analysis fills in certain vectors containing information about register usage: REG_N_REFS, REG_N_DEATHS, REG_N_SETS, REG_LIVE_LENGTH, - REG_N_CALLS_CROSSED and REG_BASIC_BLOCK. + REG_N_CALLS_CROSSED, REG_N_THROWING_CALLS_CROSSED and REG_BASIC_BLOCK. life_analysis sets current_function_sp_is_unchanging if the function doesn't modify the stack pointer. */ @@ -1589,6 +1589,7 @@ allocate_reg_life_data (void) REG_N_REFS (i) = 0; REG_N_DEATHS (i) = 0; REG_N_CALLS_CROSSED (i) = 0; + REG_N_THROWING_CALLS_CROSSED (i) = 0; REG_LIVE_LENGTH (i) = 0; REG_FREQ (i) = 0; REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN; @@ -1820,6 +1821,9 @@ propagate_one_insn (struct propagate_block_info *pbi, rtx insn) reg_set_iterator rsi; EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i, rsi) REG_N_CALLS_CROSSED (i)++; + if (can_throw_internal (insn)) + EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i, rsi) + REG_N_THROWING_CALLS_CROSSED (i)++; } /* Record sets. Do this even for dead instructions, since they @@ -3512,7 +3516,11 @@ attempt_auto_inc (struct propagate_block_info *pbi, rtx inc, rtx insn, that REGNO now crosses them. */ for (temp = insn; temp != incr; temp = NEXT_INSN (temp)) if (CALL_P (temp)) - REG_N_CALLS_CROSSED (regno)++; + { + REG_N_CALLS_CROSSED (regno)++; + if (can_throw_internal (temp)) + REG_N_THROWING_CALLS_CROSSED (regno)++; + } /* Invalidate alias info for Q since we just changed its value. */ clear_reg_alias_info (q); diff --git a/gcc/global.c b/gcc/global.c index 13b81736859..f82cd08017a 100644 --- a/gcc/global.c +++ b/gcc/global.c @@ -465,7 +465,9 @@ global_alloc (FILE *file) /* Don't allocate pseudos that cross calls, if this function receives a nonlocal goto. */ && (! current_function_has_nonlocal_label - || REG_N_CALLS_CROSSED (i) == 0)) + || REG_N_CALLS_CROSSED (i) == 0) + /* Don't allocate pseudos that cross calls that may throw. */ + && REG_N_THROWING_CALLS_CROSSED (i) == 0) { if (reg_renumber[i] < 0 && reg_may_share[i] && reg_allocno[reg_may_share[i]] >= 0) diff --git a/gcc/regs.h b/gcc/regs.h index 3caa89b081b..d29e0e1aace 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -61,6 +61,7 @@ typedef struct reg_info_def int deaths; /* # of times (REG n) dies */ int live_length; /* # of instructions (REG n) is live */ int calls_crossed; /* # of calls (REG n) is live across */ + int throw_calls_crossed; /* # of calls that may throw (REG n) is live across */ int basic_block; /* # of basic blocks (REG n) is used in */ } reg_info; @@ -125,6 +126,12 @@ extern varray_type reg_n_info; #define REG_N_CALLS_CROSSED(N) (VARRAY_REG (reg_n_info, N)->calls_crossed) +/* Indexed by N, gives number of CALL_INSNS that may throw, across which + (REG n) is live. */ + +#define REG_N_THROWING_CALLS_CROSSED(N) \ + (VARRAY_REG (reg_n_info, N)->throw_calls_crossed) + /* Total number of instructions at which (REG n) is live. The larger this is, the less priority (REG n) gets for allocation in a hard register (in global-alloc). diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bd6b162405f..bb30ee1c0b3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-08-22 Jakub Jelinek + + PR rtl-optimization/23478 + * g++.dg/opt/pr23478.C: New test. + 2005-08-22 Andrew Pinski PR c/18715 diff --git a/gcc/testsuite/g++.dg/opt/pr23478.C b/gcc/testsuite/g++.dg/opt/pr23478.C new file mode 100644 index 00000000000..da1371d2514 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr23478.C @@ -0,0 +1,211 @@ +// PR rtl-optimization/23478 +// { dg-do run } +// { dg-options "-O2" } + +extern "C" void abort (); +bool tthrow; +struct C3 { int i; }; +class C14 {}; +struct C7 +{ + virtual ~C7 (); +}; + +C7::~C7 () +{ + asm volatile ("" : : : "memory"); +} +class C2 : public C7 {}; + +template class C13 +{ + bool ma; + X *mb; +public: + explicit C13 (X *p = 0) throw () : ma (p != 0), mb (p) {} + ~C13 (); +}; + +template +C13::~C13 () +{ + asm volatile ("" : : "r" (ma), "r" (mb) : "memory"); +} + +struct C1 +{ + C1 (const C3 &, const C3 &, const C3 &, const C3 *&); +}; + +C1::C1 (const C3 &, const C3 &, const C3 &, const C3 *&) +{ + if (!tthrow) + throw 24; +} + +struct C8 +{ + struct C15 {}; + typedef C15 *C9; + virtual void f1 (C2 &, long *, void *, C3 &, void *, bool) = 0; + virtual C13 f3 () const = 0; + virtual ~C8 () {} +}; + +bool +xx14 () +{ + bool b = false; + if (tthrow) + throw 6; + asm volatile ("" : : "r" (&b) : "memory"); + return b; +} + +bool +xx2 () +{ + bool b = false; + if (tthrow) + throw 6; + asm volatile ("" : : "r" (&b) : "memory"); + return b; +} + +C13 +xx9 () +{ + return C13(); +} + +C2 & +xx10 () +{ + static C2 c2; + return c2; +} + +C3 & +xx12 () +{ + static C3 c3 = { 1 }; + return c3; +} + +const C3 & +xx5 () +{ + static const C3 c3 = { 2 }; + return c3; +} + +const C3 *& +xx4 () +{ + static const C3 *p; + if (tthrow) + throw 6; + return p; +} + +long ll13; + +long +xx13 () +{ + long ret; + asm volatile ("" : "=r" (ret) : "r" (ll13)); + return ret; +} + +void +xx15 (C3 &x, C13 &y) +{ + asm volatile ("" : : "r" (&x), "r" (&y) : "memory"); +} + +long +xx16 (const void *x) +{ + long ret; + asm volatile ("" : "=r" (ret) : "0" (1), "r" (x) : "memory"); + return ret; +} + +void +xx1 (C13 x) +{ + asm volatile ("" : : "r" (&x) : "memory"); + if (tthrow) + throw 6; +} + +void +xx3 (const C7 *x) +{ + if (x) + abort (); +} + +void +xx7 () +{ + asm volatile ("" : : : "memory"); +} + +struct C5 +{ + C13 f2 (C3 &v1, const void *v2, C8 *v6); + C7 *m2[2]; + long m1[2]; +}; + +C13 +C5::f2 (C3 &v1, const void *v2, C8 *v6) +{ + C13 v13 = xx9 (); + C2 &v9 = xx10 (); + for (long i = 1; i < 2; i++) + xx3 (m2[i]); + const C3 &ld = xx5 (); + xx7 (); + if (xx2 ()) + throw ""; + xx4 (); + C3 &si = xx12 (); + for (long i = 0; i < xx16 (v2); ++i) + { + C13 sk (new C1 (xx5 (), ld, xx5 (), xx4 ())); + xx15 (si, sk); + } + long v4 = xx13 (); + for (long i = v4 - 1; i >= 0; --i) + m1[i] = i; + bool v8 = xx2 (); + for (long i = 0; i < 2 && !xx14 (); i++) + { + v6[i].f1 (v9, 0, __null, v1, __null, v8); + if (v8) + xx1 (v6[i].f3 ()); + } + return v13; +} + +int +main (void) +{ + C5 c5 = { { __null, __null }, { 0, 0 } }; + bool seen = false; + try + { + c5.f2 (xx12 (), __null, __null); + } + catch (int n) + { + if (n != 24) + abort (); + seen = true; + } + if (!seen) + abort (); +} -- 2.30.2