aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Weigand <uweigand@de.ibm.com>2013-11-14 18:24:32 +0000
committerUlrich Weigand <uweigand@gcc.gnu.org>2013-11-14 18:24:32 +0000
commitdc2faee140907409050417fc38004d94dd40ed22 (patch)
tree8360121d17838e511bb95f7c3b74096a7e800aa6
parent2e4ceca56c268b4d4d4aa093f9227b70bd2d6580 (diff)
downloadgcc-dc2faee140907409050417fc38004d94dd40ed22.zip
gcc-dc2faee140907409050417fc38004d94dd40ed22.tar.gz
gcc-dc2faee140907409050417fc38004d94dd40ed22.tar.bz2
rs6000.c (rs6000_emit_prologue): Do not place a RTX_FRAME_RELATED_P marker on the UNSPEC_MOVESI_FROM_CR insn.
ChangeLog: 2013-11-14 Ulrich Weigand <Ulrich.Weigand@de.ibm.com> * 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. testsuite/ChangeLog: 2013-11-14 Ulrich Weigand <Ulrich.Weigand@de.ibm.com> * g++.dg/eh/ppc64-sighandle-cr.C: New test. From-SVN: r204799
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/config/rs6000/predicates.md20
-rw-r--r--gcc/config/rs6000/rs6000.c74
-rw-r--r--gcc/config/rs6000/rs6000.md8
-rw-r--r--gcc/testsuite/ChangeLog4
5 files changed, 91 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cc088e0..307ac54 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,4 +1,14 @@
2013-11-14 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+ * 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 <Ulrich.Weigand@de.ibm.com>
Alan Modra <amodra@gmail.com>
* function.c (assign_parms): Use all.reg_parm_stack_space instead
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index b5bff04..3f46001 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 c6faa40..1628bf3 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);
- }
- insn = emit_move_insn (mem, cr_save_rtx);
+ emit_insn (gen_movesi_from_cr (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 d299a46..2020468 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 0f95048..be9a3a5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2013-11-14 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+ * g++.dg/eh/ppc64-sighandle-cr.C: New test.
+
2013-11-14 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* gcc.dg/torture/float128-cmp-invalid.c: Require fenv_exceptions.