aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2006-03-30 17:47:48 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2006-03-30 17:47:48 +0000
commit79edfde8fb072da763bb08da00ed109a23311f17 (patch)
treec7abad810156d7ebdc0e5b8f1e87719b1aad993c /gcc/expr.c
parent105aa1532e59cf62d7bbfedbcbc414d9a51a02ca (diff)
downloadgcc-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
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c55
1 files changed, 49 insertions, 6 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index f579e27..059f082 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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]);