@@ -3843,17 +3843,79 @@ expand_gimple_tailcall (basic_block bb, gcall *stmt, bool *can_fallthru)
last = NEXT_INSN (last);
gcc_assert (BARRIER_P (last));
+ bool fatal_error = false;
*can_fallthru = false;
- while (NEXT_INSN (last))
+ for (rtx_insn *insn = NEXT_INSN (last); insn; insn = NEXT_INSN (insn))
{
/* For instance an sqrt builtin expander expands if with
sibcall in the then and label for `else`. */
- if (LABEL_P (NEXT_INSN (last)))
+ if (LABEL_P (insn))
+ break;
+
+ /* Complain if we would delete an insn that is not a move for the
+ function return value. */
+ if (NONDEBUG_INSN_P (insn))
+ {
+ bool okay = false;
+ rtx set = single_set (insn);
+ if (set)
+ {
+ rtx dest = SET_DEST (set);
+ rtx src = SET_SRC (set);
+ if (GET_CODE (src) == SIGN_EXTEND
+ || GET_CODE (src) == ZERO_EXTEND)
+ src = XEXP (src, 0);
+ if ((OBJECT_P (dest) || SUBREG_P (dest))
+ && (OBJECT_P (src) || SUBREG_P (src)))
+ okay = true;
+ /* Not too bad so far... but some weirder things are emitted
+ as well, unfortunately. */
+ if (REG_P (dest) && REGNO (dest) == STACK_POINTER_REGNUM)
+ okay = true;
+ /* mips does the following: */
+ if (REG_P (dest)
+ && GET_CODE (src) == UNSPEC
+ && XVECLEN (src, 0) == 1
+ && REG_P (XVECEXP (src, 0, 0)))
+ okay = true;
+ /* And at least tile* does this, followed by other code to
+ calculate more stack addresses. So let's ignore the rest
+ of the code. */
+ if (GET_CODE (src) == PLUS
+ && REG_P (dest)
+ && REG_P (XEXP (src, 0))
+ && IN_RANGE (REGNO (XEXP (src, 0)),
+ FIRST_VIRTUAL_REGISTER,
+ LAST_VIRTUAL_REGISTER))
+ break;
+ }
+ else if (GET_CODE (PATTERN (insn)) == CLOBBER)
+ okay = true;
+ if (!okay)
+ fatal_error = true;
+ }
+ }
+
+ if (fatal_error)
+ {
+ fprintf (stderr, "DELETING:\n");
+ for (rtx_insn *insn = NEXT_INSN (last); insn; insn = NEXT_INSN (insn))
+ debug_rtx (insn);
+
+ gcc_assert (0);
+ }
+
+ for (rtx_insn *insn = NEXT_INSN (last); insn; insn = NEXT_INSN (last))
+ {
+ /* For instance an sqrt builtin expander expands if with
+ sibcall in the then and label for `else`. */
+ if (LABEL_P (insn))
{
*can_fallthru = true;
break;
}
- delete_insn (NEXT_INSN (last));
+
+ delete_insn (insn);
}
e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_ABNORMAL