diff options
author | Roger Sayle <roger@eyesopen.com> | 2006-03-30 17:47:48 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2006-03-30 17:47:48 +0000 |
commit | 79edfde8fb072da763bb08da00ed109a23311f17 (patch) | |
tree | c7abad810156d7ebdc0e5b8f1e87719b1aad993c | |
parent | 105aa1532e59cf62d7bbfedbcbc414d9a51a02ca (diff) | |
download | gcc-79edfde8fb072da763bb08da00ed109a23311f17.zip gcc-79edfde8fb072da763bb08da00ed109a23311f17.tar.gz gcc-79edfde8fb072da763bb08da00ed109a23311f17.tar.bz2 |
re PR target/17959 (-mpowerpc64 can cause worse code than without it)
PR target/17959
* expr.c (emit_group_store): Optimize group stores into a pseudo
register by using a paradoxical subreg to initialize the destination
if the first or last member of the group specifies a "low part".
From-SVN: r112543
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/expr.c | 55 |
2 files changed, 56 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e302bb7..d7410de 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2006-03-30 Roger Sayle <roger@eyesopen.com> + + PR target/17959 + * expr.c (emit_group_store): Optimize group stores into a pseudo + register by using a paradoxical subreg to initialize the destination + if the first or last member of the group specifies a "low part". + 2006-03-30 Maxim Kuvyrkov <mkuvyrkov@ispras.ru> PR target/26734 @@ -1857,7 +1857,7 @@ void emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize) { rtx *tmps, dst; - int start, i; + int start, finish, i; enum machine_mode m = GET_MODE (orig_dst); gcc_assert (GET_CODE (src) == PARALLEL); @@ -1883,11 +1883,12 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize) start = 0; else start = 1; + finish = XVECLEN (src, 0); - tmps = alloca (sizeof (rtx) * XVECLEN (src, 0)); + tmps = alloca (sizeof (rtx) * finish); /* Copy the (probable) hard regs into pseudos. */ - for (i = start; i < XVECLEN (src, 0); i++) + for (i = start; i < finish; i++) { rtx reg = XEXP (XVECEXP (src, 0, i), 0); if (!REG_P (reg) || REGNO (reg) < FIRST_PSEUDO_REGISTER) @@ -1923,14 +1924,56 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize) } else if (!MEM_P (dst) && GET_CODE (dst) != CONCAT) { + enum machine_mode outer = GET_MODE (dst); + enum machine_mode inner; + unsigned int bytepos; + bool done = false; + rtx temp; + if (!REG_P (dst) || REGNO (dst) < FIRST_PSEUDO_REGISTER) - dst = gen_reg_rtx (GET_MODE (orig_dst)); + dst = gen_reg_rtx (outer); + /* Make life a bit easier for combine. */ - emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst))); + /* If the first element of the vector is the low part + of the destination mode, use a paradoxical subreg to + initialize the destination. */ + if (start < finish) + { + inner = GET_MODE (tmps[start]); + bytepos = subreg_lowpart_offset (outer, inner); + if (INTVAL (XEXP (XVECEXP (src, 0, start), 1)) == bytepos) + { + temp = simplify_gen_subreg (outer, tmps[start], + inner, bytepos); + emit_move_insn (dst, temp); + done = true; + start++; + } + } + + /* If the first element wasn't the low part, try the last. */ + if (!done + && start < finish - 1) + { + inner = GET_MODE (tmps[finish - 1]); + bytepos = subreg_lowpart_offset (outer, inner); + if (INTVAL (XEXP (XVECEXP (src, 0, finish - 1), 1)) == bytepos) + { + temp = simplify_gen_subreg (outer, tmps[finish - 1], + inner, bytepos); + emit_move_insn (dst, temp); + done = true; + finish--; + } + } + + /* Otherwise, simply initialize the result to zero. */ + if (!done) + emit_move_insn (dst, CONST0_RTX (outer)); } /* Process the pieces. */ - for (i = start; i < XVECLEN (src, 0); i++) + for (i = start; i < finish; i++) { HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1)); enum machine_mode mode = GET_MODE (tmps[i]); |