diff options
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 16 | ||||
-rw-r--r-- | gcc/expr.c | 32 | ||||
-rw-r--r-- | gcc/expr.h | 3 |
4 files changed, 48 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1a6be7b3794..b0e26a9bb13 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2007-03-01 Richard Henderson <rth@redhat.com> + + * expr.c (emit_move_complex_push): Export. + (emit_move_complex_parts): Split out from ... + (emit_move_complex): ... here. + * expr.h (emit_move_complex_push, emit_move_complex_parts): Declare. + * config/i386/i386.md (movcdi): New. + 2007-03-01 Uros Bizjak <ubizjak@gmail.com> * config/i386/i386.c (ix86_modes_tieable_p): Fix typo, use also diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index bb3dd21223d..409ce0c5f78 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -2266,6 +2266,22 @@ [(const_int 0)] "ix86_split_long_move (operands); DONE;") +;; This expands to what emit_move_complex would generate if we didn't +;; have a movti pattern. Having this avoids problems with reload on +;; 32-bit targets when SSE is present, but doesn't seem to be harmful +;; to have around all the time. +(define_expand "movcdi" + [(set (match_operand:CDI 0 "nonimmediate_operand" "") + (match_operand:CDI 1 "general_operand" ""))] + "" +{ + if (push_operand (operands[0], CDImode)) + emit_move_complex_push (CDImode, operands[0], operands[1]); + else + emit_move_complex_parts (operands[0], operands[1]); + DONE; +}) + (define_expand "movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "") (match_operand:SF 1 "general_operand" ""))] diff --git a/gcc/expr.c b/gcc/expr.c index f624d95c415..1dc437cb836 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -2987,7 +2987,7 @@ emit_move_resolve_push (enum machine_mode mode, rtx x) X is known to satisfy push_operand, and MODE is known to be complex. Returns the last instruction emitted. */ -static rtx +rtx emit_move_complex_push (enum machine_mode mode, rtx x, rtx y) { enum machine_mode submode = GET_MODE_INNER (mode); @@ -3027,6 +3027,25 @@ emit_move_complex_push (enum machine_mode mode, rtx x, rtx y) read_complex_part (y, !imag_first)); } +/* A subroutine of emit_move_complex. Perform the move from Y to X + via two moves of the parts. Returns the last instruction emitted. */ + +rtx +emit_move_complex_parts (rtx x, rtx y) +{ + /* Show the output dies here. This is necessary for SUBREGs + of pseudos since we cannot track their lifetimes correctly; + hard regs shouldn't appear here except as return values. */ + if (!reload_completed && !reload_in_progress + && REG_P (x) && !reg_overlap_mentioned_p (x, y)) + emit_insn (gen_rtx_CLOBBER (VOIDmode, x)); + + write_complex_part (x, read_complex_part (y, false), false); + write_complex_part (x, read_complex_part (y, true), true); + + return get_last_insn (); +} + /* A subroutine of emit_move_insn_1. Generate a move from Y into X. MODE is known to be complex. Returns the last instruction emitted. */ @@ -3081,16 +3100,7 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y) return ret; } - /* Show the output dies here. This is necessary for SUBREGs - of pseudos since we cannot track their lifetimes correctly; - hard regs shouldn't appear here except as return values. */ - if (!reload_completed && !reload_in_progress - && REG_P (x) && !reg_overlap_mentioned_p (x, y)) - emit_insn (gen_rtx_CLOBBER (VOIDmode, x)); - - write_complex_part (x, read_complex_part (y, false), false); - write_complex_part (x, read_complex_part (y, true), true); - return get_last_insn (); + return emit_move_complex_parts (x, y); } /* A subroutine of emit_move_insn_1. Generate a move from Y into X. diff --git a/gcc/expr.h b/gcc/expr.h index 32a0a51a373..bc3feeeab80 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -465,6 +465,9 @@ extern rtx emit_move_insn (rtx, rtx); /* Emit insns to set X from Y, with no frills. */ extern rtx emit_move_insn_1 (rtx, rtx); +extern rtx emit_move_complex_push (enum machine_mode, rtx, rtx); +extern rtx emit_move_complex_parts (rtx, rtx); + /* Push a block of length SIZE (perhaps variable) and return an rtx to address the beginning of the block. */ extern rtx push_block (rtx, int, int); |