if (!TARGET_Z10 || !TARGET_HARD_FLOAT || !crtl->is_leaf)
return;
- for (i = 6; i < 16; i++)
+ /* Restore the GPRs starting with the stack pointer. That way the
+ stack pointer already has its original value when it comes to
+ restoring the hard frame pointer. So we can set the cfa reg back
+ to the stack pointer. */
+ for (i = STACK_POINTER_REGNUM; i >= 6; i--)
{
rtx_insn *insn;
df_set_regs_ever_live (i, true);
add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (DImode, i));
- if (i == STACK_POINTER_REGNUM)
+
+ /* If either the stack pointer or the frame pointer get restored
+ set the CFA value to its value at function start. Doing this
+ for the frame pointer results in .cfi_def_cfa_register 15
+ what is ok since if the stack pointer got modified it has
+ been restored already. */
+ if (i == STACK_POINTER_REGNUM || i == HARD_FRAME_POINTER_REGNUM)
add_reg_note (insn, REG_CFA_DEF_CFA,
plus_constant (Pmode, stack_pointer_rtx,
STACK_POINTER_OFFSET));
return default_case_values_threshold ();
}
+/* Evaluate the insns between HEAD and TAIL and do back-end to install
+ back-end specific dependencies.
+
+ Establish an ANTI dependency between r11 and r15 restores from FPRs
+ to prevent the instructions scheduler from reordering them since
+ this would break CFI. No further handling in the sched_reorder
+ hook is required since the r11 and r15 restore will never appear in
+ the same ready list with that change. */
+void
+s390_sched_dependencies_evaluation (rtx_insn *head, rtx_insn *tail)
+{
+ if (!frame_pointer_needed || !epilogue_completed)
+ return;
+
+ while (head != tail && DEBUG_INSN_P (head))
+ head = NEXT_INSN (head);
+
+ rtx_insn *r15_restore = NULL, *r11_restore = NULL;
+
+ for (rtx_insn *insn = tail; insn != head; insn = PREV_INSN (insn))
+ {
+ rtx set = single_set (insn);
+ if (!INSN_P (insn)
+ || !RTX_FRAME_RELATED_P (insn)
+ || set == NULL_RTX
+ || !REG_P (SET_DEST (set))
+ || !FP_REG_P (SET_SRC (set)))
+ continue;
+
+ if (REGNO (SET_DEST (set)) == HARD_FRAME_POINTER_REGNUM)
+ r11_restore = insn;
+
+ if (REGNO (SET_DEST (set)) == STACK_POINTER_REGNUM)
+ r15_restore = insn;
+ }
+
+ if (r11_restore == NULL || r15_restore == NULL)
+ return;
+ add_dependence (r11_restore, r15_restore, REG_DEP_ANTI);
+}
+
+
+
/* Initialize GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#undef TARGET_CASE_VALUES_THRESHOLD
#define TARGET_CASE_VALUES_THRESHOLD s390_case_values_threshold
+#undef TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK
+#define TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK \
+ s390_sched_dependencies_evaluation
+
+
/* Use only short displacement, since long displacement is not available for
the floating point instructions. */
#undef TARGET_MAX_ANCHOR_OFFSET