diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cc088e04db7..307ac548e56 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2013-11-14 Ulrich Weigand + + * config/rs6000/rs6000.c (rs6000_emit_prologue): Do not place a + RTX_FRAME_RELATED_P marker on the UNSPEC_MOVESI_FROM_CR insn. + Instead, add USEs of all modified call-saved CR fields to the + insn storing the result to the stack slot, and provide an + appropriate REG_FRAME_RELATED_EXPR for that insn. + * config/rs6000/rs6000.md ("*crsave"): New insn pattern. + * config/rs6000/predicates.md ("crsave_operation"): New predicate. + 2013-11-14 Ulrich Weigand Alan Modra diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index b5bff044779..3f46001daf6 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1538,6 +1538,26 @@ return 1; }) +;; Return 1 if OP is valid for crsave insn, known to be a PARALLEL. +(define_predicate "crsave_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + int i; + + for (i = 1; i < count; i++) + { + rtx exp = XVECEXP (op, 0, i); + + if (GET_CODE (exp) != USE + || GET_CODE (XEXP (exp, 0)) != REG + || GET_MODE (XEXP (exp, 0)) != CCmode + || ! CR_REGNO_P (REGNO (XEXP (exp, 0)))) + return 0; + } + return 1; +}) + ;; Return 1 if OP is valid for lmw insn, known to be a PARALLEL. (define_predicate "lmw_operation" (match_code "parallel") diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index c6faa40bf24..1628bf31a1b 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -21766,21 +21766,9 @@ rs6000_emit_prologue (void) && REGNO (frame_reg_rtx) != cr_save_regno && !(using_static_chain_p && cr_save_regno == 11)) { - rtx set; - cr_save_rtx = gen_rtx_REG (SImode, cr_save_regno); START_USE (cr_save_regno); - insn = emit_insn (gen_movesi_from_cr (cr_save_rtx)); - RTX_FRAME_RELATED_P (insn) = 1; - /* Now, there's no way that dwarf2out_frame_debug_expr is going - to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'. - But that's OK. All we have to do is specify that _one_ condition - code register is saved in this stack slot. The thrower's epilogue - will then restore all the call-saved registers. - We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux. */ - set = gen_rtx_SET (VOIDmode, cr_save_rtx, - gen_rtx_REG (SImode, CR2_REGNO)); - add_reg_note (insn, REG_FRAME_RELATED_EXPR, set); + emit_insn (gen_movesi_from_cr (cr_save_rtx)); } /* Do any required saving of fpr's. If only one or two to save, do @@ -22091,26 +22079,62 @@ rs6000_emit_prologue (void) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset + frame_off)); rtx mem = gen_frame_mem (SImode, addr); - /* See the large comment above about why CR2_REGNO is used. */ - rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO); /* If we didn't copy cr before, do so now using r0. */ if (cr_save_rtx == NULL_RTX) { - rtx set; - START_USE (0); cr_save_rtx = gen_rtx_REG (SImode, 0); - insn = emit_insn (gen_movesi_from_cr (cr_save_rtx)); - RTX_FRAME_RELATED_P (insn) = 1; - set = gen_rtx_SET (VOIDmode, cr_save_rtx, magic_eh_cr_reg); - add_reg_note (insn, REG_FRAME_RELATED_EXPR, set); + emit_insn (gen_movesi_from_cr (cr_save_rtx)); } - insn = emit_move_insn (mem, cr_save_rtx); + + /* Saving CR requires a two-instruction sequence: one instruction + to move the CR to a general-purpose register, and a second + instruction that stores the GPR to memory. + + We do not emit any DWARF CFI records for the first of these, + because we cannot properly represent the fact that CR is saved in + a register. One reason is that we cannot express that multiple + CR fields are saved; another reason is that on 64-bit, the size + of the CR register in DWARF (4 bytes) differs from the size of + a general-purpose register. + + This means if any intervening instruction were to clobber one of + the call-saved CR fields, we'd have incorrect CFI. To prevent + this from happening, we mark the store to memory as a use of + those CR fields, which prevents any such instruction from being + scheduled in between the two instructions. */ + rtx crsave_v[9]; + int n_crsave = 0; + int i; + + crsave_v[n_crsave++] = gen_rtx_SET (VOIDmode, mem, cr_save_rtx); + for (i = 0; i < 8; i++) + if (save_reg_p (CR0_REGNO + i)) + crsave_v[n_crsave++] + = gen_rtx_USE (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO + i)); + + insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, + gen_rtvec_v (n_crsave, crsave_v))); END_USE (REGNO (cr_save_rtx)); - rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off, - NULL_RTX, NULL_RTX); + /* Now, there's no way that dwarf2out_frame_debug_expr is going to + understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)', + so we need to construct a frame expression manually. */ + RTX_FRAME_RELATED_P (insn) = 1; + + /* Update address to be stack-pointer relative, like + rs6000_frame_related would do. */ + addr = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, STACK_POINTER_REGNUM), + GEN_INT (info->cr_save_offset + sp_off)); + mem = gen_frame_mem (SImode, addr); + + /* We still cannot express that multiple CR fields are saved in the + CR save slot. By convention, we use a single CR regnum to represent + the fact that all call-saved CR fields are saved. We use CR2_REGNO + to be compatible with gcc-2.95 on Linux. */ + rtx set = gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, CR2_REGNO)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, set); } /* Update stack and set back pointer unless this is V.4, diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index d299a466a2d..20204682069 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -15035,6 +15035,14 @@ "mfcr %0" [(set_attr "type" "mfcr")]) +(define_insn "*crsave" + [(match_parallel 0 "crsave_operation" + [(set (match_operand:SI 1 "memory_operand" "=m") + (match_operand:SI 2 "gpc_reg_operand" "r"))])] + "" + "stw %2,%1" + [(set_attr "type" "store")]) + (define_insn "*stmw" [(match_parallel 0 "stmw_operation" [(set (match_operand:SI 1 "memory_operand" "=m") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0f95048e0ca..be9a3a56b99 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2013-11-14 Ulrich Weigand + + * g++.dg/eh/ppc64-sighandle-cr.C: New test. + 2013-11-14 Rainer Orth * gcc.dg/torture/float128-cmp-invalid.c: Require fenv_exceptions.