vect: Fix wrong check in vect_recog_mulhs_pattern [PR101596]

As PR101596 showed, vect_recog_mulhs_pattern uses target_precision to
check the scale_term is expected or not, it could be wrong when the
precision of the actual used new_type larger than target_precision as
shown by the example.

This patch is to use precision of new_type instead of target_precision
for the scale_term matching check.

Bootstrapped & regtested on powerpc64le-linux-gnu P10,
powerpc64-linux-gnu P8, x86_64-redhat-linux and aarch64-linux-gnu.

gcc/ChangeLog:

	PR tree-optimization/101596
	* tree-vect-patterns.c (vect_recog_mulhs_pattern): Fix wrong check
	by using new_type's precision instead.

gcc/testsuite/ChangeLog:

	PR tree-optimization/101596
	* gcc.target/powerpc/pr101596-1.c: New test.
	* gcc.target/powerpc/pr101596-2.c: Likewise.
	* gcc.target/powerpc/pr101596-3.c: Likewise.
This commit is contained in:
Kewen Lin 2021-07-27 22:04:22 -05:00
parent 872da9a6f6
commit 89b3c97eed
4 changed files with 154 additions and 27 deletions

View File

@ -0,0 +1,30 @@
/* { dg-require-effective-target power10_ok } */
/* { dg-options "-mdejagnu-cpu=power10 -O2 -ftree-vectorize -fno-vect-cost-model -fdump-tree-vect-details" } */
/* Check vect_recog_mulhs_pattern can't be detected with shift count 48. */
#define N 128
typedef signed long long sLL;
typedef unsigned long long uLL;
signed int si_a[N], si_b[N];
unsigned int ui_a[N], ui_b[N];
signed short sh_c[N];
unsigned short uh_c[N];
void
test1 ()
{
for (int i = 0; i < N; i++)
sh_c[i] = ((sLL) si_a[i] * (sLL) si_b[i]) >> 48;
}
void
test2 ()
{
for (int i = 0; i < N; i++)
uh_c[i] = ((uLL) ui_a[i] * (uLL) ui_b[i]) >> 48;
}
/* { dg-final { scan-tree-dump-not "vect_recog_mulhs_pattern: detected" "vect" } } */

View File

@ -0,0 +1,30 @@
/* { dg-require-effective-target power10_ok } */
/* { dg-options "-mdejagnu-cpu=power10 -O2 -ftree-vectorize -fno-vect-cost-model -fdump-tree-vect-details" } */
/* Check vect_recog_mulhs_pattern can be detected with shift count 32. */
#define N 128
typedef signed long long sLL;
typedef unsigned long long uLL;
signed int si_a[N], si_b[N];
unsigned int ui_a[N], ui_b[N];
signed short sh_c[N];
unsigned short uh_c[N];
void
test1 ()
{
for (int i = 0; i < N; i++)
sh_c[i] = ((sLL) si_a[i] * (sLL) si_b[i]) >> 32;
}
void
test2 ()
{
for (int i = 0; i < N; i++)
uh_c[i] = ((uLL) ui_a[i] * (uLL) ui_b[i]) >> 32;
}
/* { dg-final { scan-tree-dump-times "vect_recog_mulhs_pattern: detected" 2 "vect" } } */

View File

@ -0,0 +1,58 @@
/* { dg-do run } */
/* { dg-require-effective-target power10_hw } */
/* { dg-options "-mdejagnu-cpu=power10 -O2 -ftree-vectorize -fno-vect-cost-model" } */
/* Verify the execution goes well with shift count either 32 or 48. */
#define N 128
typedef signed int si;
typedef signed short sh;
typedef signed long long sll;
typedef unsigned int ui;
typedef unsigned short uh;
typedef unsigned long long ull;
si si_a[N], si_b[N];
ui ui_a[N], ui_b[N];
sh sh_c[N];
uh uh_c[N];
#define TEST(NTYPE, TYPE, WTYPE, CNT) \
void __attribute__ ((noipa)) test_##TYPE##CNT () \
{ \
for (int i = 0; i < N; i++) \
NTYPE##_c[i] = ((WTYPE) TYPE##_a[i] * (WTYPE) TYPE##_b[i]) >> CNT; \
} \
\
void __attribute__ ((noipa, optimize ("O1"))) check_##TYPE##CNT () \
{ \
test_##TYPE##CNT (); \
for (int i = 0; i < N; i++) \
{ \
NTYPE exp = ((WTYPE) TYPE##_a[i] * (WTYPE) TYPE##_b[i]) >> CNT; \
if (NTYPE##_c[i] != exp) \
__builtin_abort (); \
} \
}
TEST (sh, si, sll, 32)
TEST (sh, si, sll, 48)
TEST (uh, ui, ull, 32)
TEST (uh, ui, ull, 48)
int
main ()
{
for (int i = 0; i < N; i++)
{
ui_a[i] = si_a[i] = 0x12345678ULL + 0x1000ULL * (i * 3 - 1);
ui_b[i] = si_b[i] = 0x87654321ULL - 0x500000ULL * (i * 5 + 1);
}
check_si32 ();
check_si48 ();
check_ui32 ();
check_ui48 ();
}

View File

@ -1986,7 +1986,7 @@ vect_recog_mulhs_pattern (vec_info *vinfo,
stmt_vec_info mulh_stmt_info;
tree scale_term;
internal_fn ifn;
bool rounding_p = false;
/* Check for the presence of the rounding term. */
if (gimple_assign_rhs_code (rshift_input_stmt) == PLUS_EXPR)
@ -2035,37 +2035,18 @@ vect_recog_mulhs_pattern (vec_info *vinfo,
/* Get the scaling term. */
scale_term = gimple_assign_rhs2 (plus_input_stmt);
/* Check that the scaling factor is correct. */
if (TREE_CODE (scale_term) != INTEGER_CST)
return NULL;
/* Check pattern 2). */
if (wi::to_widest (scale_term) + target_precision + 2
!= TYPE_PRECISION (lhs_type))
return NULL;
ifn = IFN_MULHRS;
rounding_p = true;
}
else
{
mulh_stmt_info = rshift_input_stmt_info;
scale_term = gimple_assign_rhs2 (last_stmt);
/* Check that the scaling factor is correct. */
if (TREE_CODE (scale_term) != INTEGER_CST)
return NULL;
/* Check for pattern 1). */
if (wi::to_widest (scale_term) + target_precision + 1
== TYPE_PRECISION (lhs_type))
ifn = IFN_MULHS;
/* Check for pattern 3). */
else if (wi::to_widest (scale_term) + target_precision
== TYPE_PRECISION (lhs_type))
ifn = IFN_MULH;
else
return NULL;
}
/* Check that the scaling factor is constant. */
if (TREE_CODE (scale_term) != INTEGER_CST)
return NULL;
/* Check whether the scaling input term can be seen as two widened
inputs multiplied together. */
vect_unpromoted_value unprom_mult[2];
@ -2076,13 +2057,41 @@ vect_recog_mulhs_pattern (vec_info *vinfo,
if (nops != 2)
return NULL;
vect_pattern_detected ("vect_recog_mulhs_pattern", last_stmt);
/* Adjust output precision. */
if (TYPE_PRECISION (new_type) < target_precision)
new_type = build_nonstandard_integer_type
(target_precision, TYPE_UNSIGNED (new_type));
unsigned mult_precision = TYPE_PRECISION (new_type);
internal_fn ifn;
/* Check that the scaling factor is expected. Instead of
target_precision, we should use the one that we actually
use for internal function. */
if (rounding_p)
{
/* Check pattern 2). */
if (wi::to_widest (scale_term) + mult_precision + 2
!= TYPE_PRECISION (lhs_type))
return NULL;
ifn = IFN_MULHRS;
}
else
{
/* Check for pattern 1). */
if (wi::to_widest (scale_term) + mult_precision + 1
== TYPE_PRECISION (lhs_type))
ifn = IFN_MULHS;
/* Check for pattern 3). */
else if (wi::to_widest (scale_term) + mult_precision
== TYPE_PRECISION (lhs_type))
ifn = IFN_MULH;
else
return NULL;
}
vect_pattern_detected ("vect_recog_mulhs_pattern", last_stmt);
/* Check for target support. */
tree new_vectype = get_vectype_for_scalar_type (vinfo, new_type);
if (!new_vectype