aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/ifcvt.c26
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20050124-1.c41
4 files changed, 73 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8d3d43a..0596f11 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2005-01-26 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/19579
+ * ifcvt.c (noce_try_cmove_arith): If emitting instructions to set up
+ both A and B, see if they don't clobber registers the other expr uses.
+
2005-01-25 J"orn Rennecke <joern.rennecke@st.com>
* real.c (do_add): Initialize signalling and canonical members.
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 49f9065..39fced4 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -1229,6 +1229,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
rtx a = if_info->a;
rtx b = if_info->b;
rtx x = if_info->x;
+ rtx orig_a, orig_b;
rtx insn_a, insn_b;
rtx tmp, target;
int is_mem = 0;
@@ -1304,6 +1305,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
start_sequence ();
+ orig_a = a;
+ orig_b = b;
+
/* If either operand is complex, load it into a register first.
The best way to do this is to copy the original insn. In this
way we preserve any clobbers etc that the insn may have had.
@@ -1335,7 +1339,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
}
if (! general_operand (b, GET_MODE (b)))
{
- rtx set;
+ rtx set, last;
if (no_new_pseudos)
goto end_seq_and_fail;
@@ -1343,9 +1347,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
if (is_mem)
{
tmp = gen_reg_rtx (GET_MODE (b));
- tmp = emit_insn (gen_rtx_SET (VOIDmode,
- tmp,
- b));
+ tmp = gen_rtx_SET (VOIDmode, tmp, b);
}
else if (! insn_b)
goto end_seq_and_fail;
@@ -1355,8 +1357,22 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
tmp = copy_rtx (insn_b);
set = single_set (tmp);
SET_DEST (set) = b;
- tmp = emit_insn (PATTERN (tmp));
+ tmp = PATTERN (tmp);
+ }
+
+ /* If insn to set up A clobbers any registers B depends on, try to
+ swap insn that sets up A with the one that sets up B. If even
+ that doesn't help, punt. */
+ last = get_last_insn ();
+ if (last && modified_in_p (orig_b, last))
+ {
+ tmp = emit_insn_before (tmp, get_insns ());
+ if (modified_in_p (orig_a, tmp))
+ goto end_seq_and_fail;
}
+ else
+ tmp = emit_insn (tmp);
+
if (recog_memoized (tmp) < 0)
goto end_seq_and_fail;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bc2bc83..2f7606a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2005-01-26 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/19579
+ * gcc.c-torture/execute/20050124-1.c: New test.
+
2005-01-18 Jan Hubicka <jh@suse.cz>
PR tree-optimize/19337
diff --git a/gcc/testsuite/gcc.c-torture/execute/20050124-1.c b/gcc/testsuite/gcc.c-torture/execute/20050124-1.c
new file mode 100644
index 0000000..9d039ef
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20050124-1.c
@@ -0,0 +1,41 @@
+/* PR rtl-optimization/19579 */
+
+extern void abort (void);
+
+int
+foo (int i, int j)
+{
+ int k = i + 1;
+
+ if (j)
+ {
+ if (k > 0)
+ k++;
+ else if (k < 0)
+ k--;
+ }
+
+ return k;
+}
+
+int
+main (void)
+{
+ if (foo (-2, 0) != -1)
+ abort ();
+ if (foo (-1, 0) != 0)
+ abort ();
+ if (foo (0, 0) != 1)
+ abort ();
+ if (foo (1, 0) != 2)
+ abort ();
+ if (foo (-2, 1) != -2)
+ abort ();
+ if (foo (-1, 1) != 0)
+ abort ();
+ if (foo (0, 1) != 2)
+ abort ();
+ if (foo (1, 1) != 3)
+ abort ();
+ return 0;
+}