aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/config/rs6000/rs6000-logue.cc7
-rw-r--r--gcc/config/rs6000/rs6000.md15
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr114846.c20
3 files changed, 38 insertions, 4 deletions
diff --git a/gcc/config/rs6000/rs6000-logue.cc b/gcc/config/rs6000/rs6000-logue.cc
index 60ba15a..bd5d56b 100644
--- a/gcc/config/rs6000/rs6000-logue.cc
+++ b/gcc/config/rs6000/rs6000-logue.cc
@@ -4308,9 +4308,6 @@ rs6000_emit_epilogue (enum epilogue_type epilogue_type)
rs6000_stack_t *info = rs6000_stack_info ();
- if (epilogue_type == EPILOGUE_TYPE_NORMAL && crtl->calls_eh_return)
- epilogue_type = EPILOGUE_TYPE_EH_RETURN;
-
int strategy = info->savres_strategy;
bool using_load_multiple = !!(strategy & REST_MULTIPLE);
bool restoring_GPRs_inline = !!(strategy & REST_INLINE_GPRS);
@@ -4788,7 +4785,9 @@ rs6000_emit_epilogue (enum epilogue_type epilogue_type)
/* In the ELFv2 ABI we need to restore all call-saved CR fields from
*separate* slots if the routine calls __builtin_eh_return, so
- that they can be independently restored by the unwinder. */
+ that they can be independently restored by the unwinder. Since
+ it is for CR fields restoring, it should be done for any epilogue
+ types (not EPILOGUE_TYPE_EH_RETURN specific). */
if (DEFAULT_ABI == ABI_ELFv2 && crtl->calls_eh_return)
{
int i, cr_off = info->ehcr_offset;
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index f035e68..a5d2059 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -14274,6 +14274,8 @@
""
{
emit_insn (gen_eh_set_lr (Pmode, operands[0]));
+ emit_jump_insn (gen_eh_return_internal ());
+ emit_barrier ();
DONE;
})
@@ -14290,6 +14292,19 @@
DONE;
})
+(define_insn_and_split "eh_return_internal"
+ [(eh_return)]
+ ""
+ "#"
+ "epilogue_completed"
+ [(const_int 0)]
+{
+ if (!TARGET_SCHED_PROLOG)
+ emit_insn (gen_blockage ());
+ rs6000_emit_epilogue (EPILOGUE_TYPE_EH_RETURN);
+ DONE;
+})
+
(define_insn "prefetch"
[(prefetch (match_operand 0 "indexed_or_indirect_address" "a")
(match_operand:SI 1 "const_int_operand" "n")
diff --git a/gcc/testsuite/gcc.target/powerpc/pr114846.c b/gcc/testsuite/gcc.target/powerpc/pr114846.c
new file mode 100644
index 0000000..efe2300
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr114846.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-require-effective-target builtin_eh_return } */
+
+/* Ensure it runs successfully. */
+
+__attribute__ ((noipa))
+int f (int *a, long offset, void *handler)
+{
+ if (*a == 5)
+ return 5;
+ __builtin_eh_return (offset, handler);
+}
+
+int main ()
+{
+ int t = 5;
+ if (f (&t, 0, 0) != 5)
+ __builtin_abort ();
+ return 0;
+}