combine.c (is_parallel_of_n_reg_sets): New function.

* combine.c (is_parallel_of_n_reg_sets): New function.
	(can_split_parallel_of_n_reg_sets): New function.
	(try_combine): If I2 is a PARALLEL of two SETs, split it into
	two insns if possible.

From-SVN: r218248
This commit is contained in:
Segher Boessenkool 2014-12-01 23:36:12 +01:00 committed by Segher Boessenkool
parent 797d88589e
commit 9d2f8e16f5
2 changed files with 85 additions and 0 deletions

View File

@ -1,3 +1,10 @@
2014-12-01 Segher Boessenkool <segher@kernel.crashing.org>
* combine.c (is_parallel_of_n_reg_sets): New function.
(can_split_parallel_of_n_reg_sets): New function.
(try_combine): If I2 is a PARALLEL of two SETs, split it into
two insns if possible.
2014-12-01 Tobias Burnus <burnus@net-b.de>
Jack Howarth <howarth@bromo.med.uc.edu>

View File

@ -2461,6 +2461,59 @@ update_cfg_for_uncondjump (rtx_insn *insn)
}
}
/* Return whether INSN is a PARALLEL of exactly N register SETs followed
by an arbitrary number of CLOBBERs. */
static bool
is_parallel_of_n_reg_sets (rtx_insn *insn, int n)
{
rtx pat = PATTERN (insn);
if (GET_CODE (pat) != PARALLEL)
return false;
int len = XVECLEN (pat, 0);
if (len < n)
return false;
int i;
for (i = 0; i < n; i++)
if (GET_CODE (XVECEXP (pat, 0, i)) != SET
|| !REG_P (SET_DEST (XVECEXP (pat, 0, i))))
return false;
for ( ; i < len; i++)
if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER)
return false;
return true;
}
/* Return whether INSN, a PARALLEL of N register SETs (and maybe some
CLOBBERs), can be split into individual SETs in that order, without
changing semantics. */
static bool
can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n)
{
if (!insn_nothrow_p (insn))
return false;
rtx pat = PATTERN (insn);
int i, j;
for (i = 0; i < n; i++)
{
if (side_effects_p (SET_SRC (XVECEXP (pat, 0, i))))
return false;
rtx reg = SET_DEST (XVECEXP (pat, 0, i));
for (j = i + 1; j < n; j++)
if (reg_referenced_p (reg, XVECEXP (pat, 0, j)))
return false;
}
return true;
}
/* Try to combine the insns I0, I1 and I2 into I3.
Here I0, I1 and I2 appear earlier than I3.
I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into
@ -2817,6 +2870,31 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
alloc_insn_link (i1, regno, LOG_LINKS (i2)));
}
}
/* If I2 is a PARALLEL of two SETs of REGs (and perhaps some CLOBBERs),
make those two SETs separate I1 and I2 insns, and make an I0 that is
the original I1. */
if (i0 == 0
&& is_parallel_of_n_reg_sets (i2, 2)
&& can_split_parallel_of_n_reg_sets (i2, 2)
&& !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)), i2, i3)
&& !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 1)), i2, i3))
{
/* If there is no I1, there is no I0 either. */
i0 = i1;
/* We make I1 with the same INSN_UID as I2. This gives it
the same DF_INSN_LUID for value tracking. Our fake I1 will
never appear in the insn stream so giving it the same INSN_UID
as I2 will not cause a problem. */
i1 = gen_rtx_INSN (VOIDmode, NULL, i2, BLOCK_FOR_INSN (i2),
XVECEXP (PATTERN (i2), 0, 0), INSN_LOCATION (i2),
-1, NULL_RTX);
INSN_UID (i1) = INSN_UID (i2);
SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 1));
}
#endif
/* Verify that I2 and I1 are valid for combining. */