aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/ia64/ia64.c59
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/eh/ia64-2.C57
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;
+}