diff options
author | Jakub Jelinek <jakub@redhat.com> | 2005-08-22 18:58:50 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2005-08-22 18:58:50 +0200 |
commit | 27004606de459d624247190ca0f752a9a9a7b76f (patch) | |
tree | a84c1cb04ef05b13f2b4cd991e221d8edbf8e2ec | |
parent | ad685e8112bbaf64ff9ee993cb189feaa869e741 (diff) | |
download | gcc-27004606de459d624247190ca0f752a9a9a7b76f.zip gcc-27004606de459d624247190ca0f752a9a9a7b76f.tar.gz gcc-27004606de459d624247190ca0f752a9a9a7b76f.tar.bz2 |
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
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/flow.c | 12 | ||||
-rw-r--r-- | gcc/global.c | 4 | ||||
-rw-r--r-- | gcc/regs.h | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/opt/pr23478.C | 211 |
6 files changed, 248 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8a5e2f0..3663104 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2005-08-22 Jakub Jelinek <jakub@redhat.com> + + 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 <pinskia@physics.uc.edu> PR c/18715 @@ -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 13b8173..f82cd08 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) @@ -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 bd6b162..bb30ee1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-08-22 Jakub Jelinek <jakub@redhat.com> + + PR rtl-optimization/23478 + * g++.dg/opt/pr23478.C: New test. + 2005-08-22 Andrew Pinski <pinskia@physics.uc.edu> 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 0000000..da1371d --- /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 X> class C13 +{ + bool ma; + X *mb; +public: + explicit C13 (X *p = 0) throw () : ma (p != 0), mb (p) {} + ~C13 (); +}; + +template <class X> +C13<X>::~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<C14> 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<C7> +xx9 () +{ + return C13<C7>(); +} + +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<C1> &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<C14> 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<C7> f2 (C3 &v1, const void *v2, C8 *v6); + C7 *m2[2]; + long m1[2]; +}; + +C13<C7> +C5::f2 (C3 &v1, const void *v2, C8 *v6) +{ + C13<C7> 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<C1> 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 (); +} |