diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/config/ia64/ia64.c | 59 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/eh/ia64-2.C | 57 |
4 files changed, 119 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2e3f9d9..f3e2559 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2006-12-21 Jakub Jelinek <jakub@redhat.com> + + PR target/30230 + * config/ia64/ia64.c (ia64_add_bundle_selector_before): New function. + (bundling): Use it. + 2006-12-21 Nathan Sidwell <nathan@codesourcery.com> PR target/28966 diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index d0a86a3..5ee5a00 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -7646,6 +7646,53 @@ get_next_important_insn (rtx insn, rtx tail) return NULL_RTX; } +/* Add a bundle selector TEMPLATE0 before INSN. */ + +static void +ia64_add_bundle_selector_before (int template0, rtx insn) +{ + rtx b = gen_bundle_selector (GEN_INT (template0)); + + ia64_emit_insn_before (b, insn); +#if NR_BUNDLES == 10 + if ((template0 == 4 || template0 == 5) + && (flag_unwind_tables || (flag_exceptions && !USING_SJLJ_EXCEPTIONS))) + { + int i; + rtx note = NULL_RTX; + + /* In .mbb and .bbb bundles, check if CALL_INSN isn't in the + first or second slot. If it is and has REG_EH_NOTE set, copy it + to following nops, as br.call sets rp to the address of following + bundle and therefore an EH region end must be on a bundle + boundary. */ + insn = PREV_INSN (insn); + for (i = 0; i < 3; i++) + { + do + insn = next_active_insn (insn); + while (GET_CODE (insn) == INSN + && get_attr_empty (insn) == EMPTY_YES); + if (GET_CODE (insn) == CALL_INSN) + note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); + else if (note) + { + int code; + + gcc_assert ((code = recog_memoized (insn)) == CODE_FOR_nop + || code == CODE_FOR_nop_b); + if (find_reg_note (insn, REG_EH_REGION, NULL_RTX)) + note = NULL_RTX; + else + REG_NOTES (insn) + = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (note, 0), + REG_NOTES (insn)); + } + } + } +#endif +} + /* The following function does insn bundling. Bundling means inserting templates and nop insns to fit insn groups into permitted templates. Instruction scheduling uses NDFA (non-deterministic @@ -7927,8 +7974,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail) /* We are at the start of a bundle: emit the template (it should be defined). */ gcc_assert (template0 >= 0); - b = gen_bundle_selector (GEN_INT (template0)); - ia64_emit_insn_before (b, nop); + ia64_add_bundle_selector_before (template0, nop); /* If we have two bundle window, we make one bundle rotation. Otherwise template0 will be undefined (negative value). */ @@ -7954,8 +8000,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail) /* The current insn is at the bundle start: emit the template. */ gcc_assert (template0 >= 0); - b = gen_bundle_selector (GEN_INT (template0)); - ia64_emit_insn_before (b, insn); + ia64_add_bundle_selector_before (template0, insn); b = PREV_INSN (insn); insn = b; /* See comment above in analogous place for emitting nops @@ -7977,8 +8022,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail) /* See comment above in analogous place for emitting nops after the insn. */ gcc_assert (template0 >= 0); - b = gen_bundle_selector (GEN_INT (template0)); - ia64_emit_insn_before (b, insn); + ia64_add_bundle_selector_before (template0, insn); b = PREV_INSN (insn); insn = b; template0 = template1; @@ -8072,8 +8116,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail) } /* Put the MM-insn in the same slot of a bundle with the same template as the original one. */ - ia64_emit_insn_before (gen_bundle_selector (GEN_INT (template0)), - insn); + ia64_add_bundle_selector_before (template0, insn); /* To put the insn in the same slot, add necessary number of nops. */ for (j = n; j > 0; j --) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d708742..84b2cd8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-12-21 Jakub Jelinek <jakub@redhat.com> + + PR target/30230 + * g++.dg/eh/ia64-2.C: New test. + 2006-12-21 Nathan Sidwell <nathan@codesourcery.com> PR target/28966 diff --git a/gcc/testsuite/g++.dg/eh/ia64-2.C b/gcc/testsuite/g++.dg/eh/ia64-2.C new file mode 100644 index 0000000..0390bc8 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/ia64-2.C @@ -0,0 +1,57 @@ +// PR target/30230 +// This testcase failed on IA-64, where end of an EH region ended +// in the middle of a bundle (with br.call insn in first or second +// slot of .bbb/.mbb bundles and EH region end right after it). +// But br.call returns to the start of the next bundlem so during +// unwinding the call was considered to be outside of the EH region +// while it should have been inside. +// { dg-options "-O2" } +// { dg-do run } + +struct A {}; +struct B { virtual ~B(); }; +B::~B () {} +struct C { void foo (short &, B &); }; +struct D { void *d1; C *d2; virtual void virt (void) {} }; +struct E { D *e1; B *e2; }; +struct F { void bar (void *, B &); }; +F *p __attribute__((weak)); +volatile int r; + +void C::foo (short &x, B &) +{ + if (r) + throw A (); + x = 1; +} + +void F::bar (void *, B &) +{ + throw A (); +} + +void baz (E &x) +{ + short g = 0; + B b = *x.e2; + x.e1->d2->foo (g, b); + if (g) + p->bar(x.e1->d1, b); +} + +int main () +{ + F g; + D s; + E h; + p = &g; + h.e1 = &s; + try + { + baz (h); + } + catch (A &) + { + } + return 0; +} |