Canonicalize vec_merge when mask is constant.

Use swap_communattive_operands_p for canonicalization. When both value
has same operand precedence value, then first bit in the mask should
select first operand.

The canonicalization should help backends for pattern match. .i.e. x86
backend has lots of vec_merge patterns, combine will create any form
of vec_merge(mask, or inverted mask), then backend need to add 2
patterns to match exact 1 instruction. The canonicalization can
simplify 2 patterns to 1.

gcc/ChangeLog:

	* combine.cc (maybe_swap_commutative_operands): Canonicalize
	vec_merge when mask is constant.
	* doc/md.texi: Document vec_merge canonicalization.
This commit is contained in:
liuhongt 2023-03-21 13:35:06 +08:00
parent 82aef047ed
commit 23b60aeb00
2 changed files with 29 additions and 0 deletions

View file

@ -5631,6 +5631,28 @@ maybe_swap_commutative_operands (rtx x)
SUBST (XEXP (x, 0), XEXP (x, 1));
SUBST (XEXP (x, 1), temp);
}
unsigned n_elts = 0;
if (GET_CODE (x) == VEC_MERGE
&& CONST_INT_P (XEXP (x, 2))
&& GET_MODE_NUNITS (GET_MODE (x)).is_constant (&n_elts)
&& (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1))
/* Two operands have same precedence, then
first bit of mask select first operand. */
|| (!swap_commutative_operands_p (XEXP (x, 1), XEXP (x, 0))
&& !(UINTVAL (XEXP (x, 2)) & 1))))
{
rtx temp = XEXP (x, 0);
unsigned HOST_WIDE_INT sel = UINTVAL (XEXP (x, 2));
unsigned HOST_WIDE_INT mask = HOST_WIDE_INT_1U;
if (n_elts == HOST_BITS_PER_WIDE_INT)
mask = -1;
else
mask = (HOST_WIDE_INT_1U << n_elts) - 1;
SUBST (XEXP (x, 0), XEXP (x, 1));
SUBST (XEXP (x, 1), temp);
SUBST (XEXP (x, 2), GEN_INT (~sel & mask));
}
}
/* Simplify X, a piece of RTL. We just operate on the expression at the

View file

@ -8224,6 +8224,13 @@ second operand. If a machine only supports a constant as the second
operand, only patterns that match a constant in the second operand need
be supplied.
@cindex @code{vec_merge}, canonicalization of
@item
For the @code{vec_merge} with constant mask(the third operand), the first
and the second operand can be exchanged by inverting the mask. In such cases,
a constant is always made the second operand, otherwise the least significant
bit of the mask is always set(select the first operand first).
@item
For associative operators, a sequence of operators will always chain
to the left; for instance, only the left operand of an integer @code{plus}