diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 349d89a..46c8786 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -23037,7 +23037,14 @@ arm_expand_epilogue (bool really_return) see comment in arm_expand_prologue. */ emit_insn (gen_movsi (stack_pointer_rtx, gen_rtx_REG (SImode, 0))); - emit_jump_insn (simple_return_rtx); + /* Shrink-wrap tries to use one common simple-return, which makes impossible + to generate the correct unwind information when reisters need to be + restored or the sp need to be adjusted in epilogue. The RET_RTX is to + make sure that it can not be optimized as SIMPLE_RETURN_RTX. */ + if (saved_regs_mask || (amount != 0)) + emit_jump_insn (ret_rtx); + else + emit_jump_insn (simple_return_rtx); } /* Implementation of insn prologue_thumb1_interwork. This is the first diff --git a/gcc/function.c b/gcc/function.c index 9efbc3a..c9bfe10 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -5822,6 +5822,45 @@ emit_return_for_exit (edge exit_fallthru_edge, bool simple_p) } #endif +#ifdef HAVE_simple_return +/* Replace the RETURN in IN_RTX with SIMPLE_RETURN. */ +static rtx +replace_return_with_simple_return (rtx in_rtx) +{ + int i; + const char *format_ptr; + rtx ret = NULL; + + if (in_rtx == NULL) + return NULL; + + format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); + + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++, format_ptr++) + { + if (*format_ptr == 'e'|| *format_ptr == 'E') + { + rtx tmp = XEXP (in_rtx, i); + if (tmp) + { + if (GET_CODE (tmp) == RETURN) + { + XEXP (in_rtx, i) = simple_return_rtx; + ret = XEXP (in_rtx, i); + break; + } + else + { + ret = replace_return_with_simple_return (tmp); + if (ret) + break; + } + } + } + } + return ret; +} +#endif /* Generate the prologue and epilogue RTL if the machine supports it. Thread this into place with notes indicating where the prologue ends and where @@ -6617,6 +6656,16 @@ epilogue_done: #endif ) { +#ifdef HAVE_simple_return + /* Replace RETURN to SIMPLE_RETURN to distinguish it with normal + sibcalls, which requires epilogue. Otherwise, the JUMP2 pass + might use a common sibcall for simple-return sibcall and normal + sibcall. In this case, there is no way to generate the correct + unwind infomation. */ + if (CALL_P (insn)) + if (replace_return_with_simple_return (insn)) + INSN_CODE (insn) = -1; +#endif ei_next (&ei); continue; }