diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 30da178049a..685aba31ccb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2016-04-20 Andreas Krebbel + + PR target/70674 + * config/s390/s390.c (s390_restore_gprs_from_fprs): Pick the new + stack_restore_from_fpr pattern when restoring r15. + (s390_optimize_prologue): Strip away the memory barrier in the + parallel when trying to get rid of restore insns. + * config/s390/s390.md ("stack_restore_from_fpr"): New insn + definition for loading the stack pointer from an FPR. Compared to + the normal move insn this pattern includes a full memory barrier. + 2016-04-19 Jakub Jelinek PR middle-end/70680 diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 1134d0f1e9d..a1d0930c071 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -10538,19 +10538,25 @@ s390_restore_gprs_from_fprs (void) for (i = 6; i < 16; i++) { - if (FP_REGNO_P (cfun_gpr_save_slot (i))) - { - rtx_insn *insn = - emit_move_insn (gen_rtx_REG (DImode, i), - gen_rtx_REG (DImode, cfun_gpr_save_slot (i))); - df_set_regs_ever_live (i, true); - add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (DImode, i)); - if (i == STACK_POINTER_REGNUM) - add_reg_note (insn, REG_CFA_DEF_CFA, - plus_constant (Pmode, stack_pointer_rtx, - STACK_POINTER_OFFSET)); - RTX_FRAME_RELATED_P (insn) = 1; - } + rtx_insn *insn; + + if (!FP_REGNO_P (cfun_gpr_save_slot (i))) + continue; + + rtx fpr = gen_rtx_REG (DImode, cfun_gpr_save_slot (i)); + + if (i == STACK_POINTER_REGNUM) + insn = emit_insn (gen_stack_restore_from_fpr (fpr)); + else + insn = emit_move_insn (gen_rtx_REG (DImode, i), fpr); + + df_set_regs_ever_live (i, true); + add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (DImode, i)); + if (i == STACK_POINTER_REGNUM) + add_reg_note (insn, REG_CFA_DEF_CFA, + plus_constant (Pmode, stack_pointer_rtx, + STACK_POINTER_OFFSET)); + RTX_FRAME_RELATED_P (insn) = 1; } } @@ -13032,37 +13038,46 @@ s390_optimize_prologue (void) /* Remove ldgr/lgdr instructions used for saving and restore GPRs if possible. */ - if (TARGET_Z10 - && GET_CODE (pat) == SET - && GET_MODE (SET_SRC (pat)) == DImode - && REG_P (SET_SRC (pat)) - && REG_P (SET_DEST (pat))) + if (TARGET_Z10) { - int src_regno = REGNO (SET_SRC (pat)); - int dest_regno = REGNO (SET_DEST (pat)); - int gpr_regno; - int fpr_regno; + rtx tmp_pat = pat; - if (!((GENERAL_REGNO_P (src_regno) && FP_REGNO_P (dest_regno)) - || (FP_REGNO_P (src_regno) && GENERAL_REGNO_P (dest_regno)))) - continue; + if (INSN_CODE (insn) == CODE_FOR_stack_restore_from_fpr) + tmp_pat = XVECEXP (pat, 0, 0); - gpr_regno = GENERAL_REGNO_P (src_regno) ? src_regno : dest_regno; - fpr_regno = FP_REGNO_P (src_regno) ? src_regno : dest_regno; - - /* GPR must be call-saved, FPR must be call-clobbered. */ - if (!call_really_used_regs[fpr_regno] - || call_really_used_regs[gpr_regno]) - continue; - - /* It must not happen that what we once saved in an FPR now - needs a stack slot. */ - gcc_assert (cfun_gpr_save_slot (gpr_regno) != SAVE_SLOT_STACK); - - if (cfun_gpr_save_slot (gpr_regno) == SAVE_SLOT_NONE) + if (GET_CODE (tmp_pat) == SET + && GET_MODE (SET_SRC (tmp_pat)) == DImode + && REG_P (SET_SRC (tmp_pat)) + && REG_P (SET_DEST (tmp_pat))) { - remove_insn (insn); - continue; + int src_regno = REGNO (SET_SRC (tmp_pat)); + int dest_regno = REGNO (SET_DEST (tmp_pat)); + int gpr_regno; + int fpr_regno; + + if (!((GENERAL_REGNO_P (src_regno) + && FP_REGNO_P (dest_regno)) + || (FP_REGNO_P (src_regno) + && GENERAL_REGNO_P (dest_regno)))) + continue; + + gpr_regno = GENERAL_REGNO_P (src_regno) ? src_regno : dest_regno; + fpr_regno = FP_REGNO_P (src_regno) ? src_regno : dest_regno; + + /* GPR must be call-saved, FPR must be call-clobbered. */ + if (!call_really_used_regs[fpr_regno] + || call_really_used_regs[gpr_regno]) + continue; + + /* It must not happen that what we once saved in an FPR now + needs a stack slot. */ + gcc_assert (cfun_gpr_save_slot (gpr_regno) != SAVE_SLOT_STACK); + + if (cfun_gpr_save_slot (gpr_regno) == SAVE_SLOT_NONE) + { + remove_insn (insn); + continue; + } } } diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 5a9f1c8a606..2b4e8f4b2b2 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -299,6 +299,8 @@ (BASE_REGNUM 13) ; Return address register. (RETURN_REGNUM 14) + ; Stack pointer register. + (STACK_REGNUM 15) ; Condition code register. (CC_REGNUM 33) ; Thread local storage pointer register. @@ -10387,6 +10389,14 @@ [(set_attr "length" "0")]) +(define_insn "stack_restore_from_fpr" + [(set (reg:DI STACK_REGNUM) + (match_operand:DI 0 "register_operand" "f")) + (clobber (mem:BLK (scratch)))] + "TARGET_Z10" + "lgdr\t%%r15,%0" + [(set_attr "op_type" "RRE")]) + ; ; Data prefetch patterns ; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ed50f14795c..55e7bbda21f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-04-20 Andreas Krebbel + + PR target/70674 + * gcc.target/s390/pr70674.c: New test. + 2016-04-19 Jerry DeLisle PR libgfortran/70684 diff --git a/gcc/testsuite/gcc.target/s390/pr70674.c b/gcc/testsuite/gcc.target/s390/pr70674.c new file mode 100644 index 00000000000..13bf271d95f --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr70674.c @@ -0,0 +1,13 @@ +/* Test case for PR/70674. */ + +/* { dg-do compile { target s390x-*-* } } */ +/* { dg-options "-march=z10 -mtune=z196 -O2 -fno-omit-frame-pointer -fno-asynchronous-unwind-tables" } */ + +void +foo (void) +{ + volatile int a = 5; + (void) a; +} + +/* { dg-final { scan-assembler-not "^.*lgdr.*\n.*\\(%r11\\)" } } */