diff options
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/ifcvt.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20050124-1.c | 41 |
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; +} |