+2018-08-03 Richard Sandiford <richard.sandiford@arm.com>
+
+ * internal-fn.h (first_commutative_argument): Declare.
+ * internal-fn.c (first_commutative_argument): New function.
+ * tree-vect-slp.c (vect_get_and_check_slp_defs): Remove extra
+ restrictions for pattern statements. Use first_commutative_argument
+ to look for commutative operands in calls to internal functions.
+
2018-08-03 Aldy Hernandez <aldyh@redhat.com>
* Makefile.in (wide-int-range.o): New.
return direct_internal_fn_supported_p (fn, tree_pair (type, type), opt_type);
}
+/* If FN is commutative in two consecutive arguments, return the
+ index of the first, otherwise return -1. */
+
+int
+first_commutative_argument (internal_fn fn)
+{
+ switch (fn)
+ {
+ case IFN_FMA:
+ case IFN_FMS:
+ case IFN_FNMA:
+ case IFN_FNMS:
+ case IFN_AVG_FLOOR:
+ case IFN_AVG_CEIL:
+ case IFN_FMIN:
+ case IFN_FMAX:
+ return 0;
+
+ case IFN_COND_ADD:
+ case IFN_COND_MUL:
+ case IFN_COND_MIN:
+ case IFN_COND_MAX:
+ case IFN_COND_AND:
+ case IFN_COND_IOR:
+ case IFN_COND_XOR:
+ case IFN_COND_FMA:
+ case IFN_COND_FMS:
+ case IFN_COND_FNMA:
+ case IFN_COND_FNMS:
+ return 1;
+
+ default:
+ return -1;
+ }
+}
+
/* Return true if IFN_SET_EDOM is supported. */
bool
opt_type);
}
+extern int first_commutative_argument (internal_fn);
+
extern bool set_edom_supported_p (void);
extern internal_fn get_conditional_internal_fn (tree_code);
+2018-08-03 Richard Sandiford <richard.sandiford@arm.com>
+
+ * gcc.dg/vect/bb-slp-over-widen-1.c: Expect AVG_FLOOR to be used
+ on vect_avg_qi targets.
+ * gcc.dg/vect/bb-slp-over-widen-2.c: Likewise.
+ * gcc.dg/vect/bb-slp-pow-1.c: New test.
+ * gcc.dg/vect/vect-avg-15.c: Likewise.
+
2018-08-03 Martin Liska <mliska@suse.cz>
* gcc.dg/predict-1.c: Adjust scanned pattern to cover 2 digits.
/* { dg-final { scan-tree-dump "demoting int to signed short" "slp2" { target { ! vect_widen_shift } } } } */
/* { dg-final { scan-tree-dump "demoting int to unsigned short" "slp2" { target { ! vect_widen_shift } } } } */
+/* { dg-final { scan-tree-dump {\.AVG_FLOOR} "slp2" { target vect_avg_qi } } } */
/* { dg-final { scan-tree-dump-times "basic block vectorized" 2 "slp2" } } */
/* { dg-final { scan-tree-dump "demoting int to signed short" "slp2" { target { ! vect_widen_shift } } } } */
/* { dg-final { scan-tree-dump "demoting int to unsigned short" "slp2" { target { ! vect_widen_shift } } } } */
+/* { dg-final { scan-tree-dump {\.AVG_FLOOR} "slp2" { target vect_avg_qi } } } */
/* { dg-final { scan-tree-dump-times "basic block vectorized" 2 "slp2" } } */
--- /dev/null
+/* { dg-additional-options "-fno-math-errno -fdisable-tree-sincos" } */
+/* { dg-require-effective-target vect_float } */
+
+void __attribute__ ((noipa))
+f (float *a)
+{
+ a[0] = a[0] * a[0];
+ a[1] = __builtin_powf (a[1], 2);
+ a[2] = a[2] * a[2];
+ a[3] = __builtin_powf (a[3], 2);
+}
+
+float a[4] = { 1, 2, 3, 4 };
+
+int
+main (void)
+{
+ f (a);
+ for (int i = 0; i < 4; ++i)
+ {
+ if (a[i] != (i + 1) * (i + 1))
+ __builtin_abort ();
+ asm volatile ("" ::: "memory");
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized" 1 "slp2" } } */
--- /dev/null
+/* { dg-additional-options "-O3" } */
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+
+#define N 80
+
+void __attribute__ ((noipa))
+f (signed char *restrict a, signed char *restrict b,
+ signed char *restrict c, int n, int step)
+{
+ for (int j = 0; j < n; ++j)
+ {
+ for (int i = 0; i < 16; ++i)
+ a[i] = (b[i] + c[i]) >> 1;
+ a += step;
+ b += step;
+ c += step;
+ }
+}
+
+#define BASE1 -126
+#define BASE2 -42
+
+signed char a[N], b[N], c[N];
+
+int
+main (void)
+{
+ check_vect ();
+
+ for (int i = 0; i < N; ++i)
+ {
+ a[i] = i;
+ b[i] = BASE1 + i * 3;
+ c[i] = BASE2 + i * 2;
+ asm volatile ("" ::: "memory");
+ }
+ f (a, b, c, N / 20, 20);
+ for (int i = 0; i < N; ++i)
+ {
+ int d = (BASE1 + BASE2 + i * 5) >> 1;
+ if (a[i] != (i % 20 < 16 ? d : i))
+ __builtin_abort ();
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */
+/* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */
+/* { dg-final { scan-tree-dump "Loop contains only SLP stmts" "vect" { target vect_avg_qi } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */
bool pattern = false;
slp_oprnd_info oprnd_info;
int first_op_idx = 1;
- bool commutative = false;
+ unsigned int commutative_op = -1U;
bool first_op_cond = false;
bool first = stmt_num == 0;
bool second = stmt_num == 1;
{
number_of_oprnds = gimple_call_num_args (stmt);
first_op_idx = 3;
+ if (gimple_call_internal_p (stmt))
+ {
+ internal_fn ifn = gimple_call_internal_fn (stmt);
+ commutative_op = first_commutative_argument (ifn);
+ }
}
else if (gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt))
{
number_of_oprnds++;
}
else
- commutative = commutative_tree_code (code);
+ commutative_op = commutative_tree_code (code) ? 0U : -1U;
}
else
return -1;
return -1;
}
- /* Check if DEF_STMT_INFO is a part of a pattern in LOOP and get
- the def stmt from the pattern. Check that all the stmts of the
- node are in the pattern. */
- if (def_stmt_info && is_pattern_stmt_p (def_stmt_info))
- {
- pattern = true;
- if (!first && !oprnd_info->first_pattern
- /* Allow different pattern state for the defs of the
- first stmt in reduction chains. */
- && (oprnd_info->first_dt != vect_reduction_def
- || (!second && !oprnd_info->second_pattern)))
- {
- if (i == 0
- && !swapped
- && commutative)
- {
- swapped = true;
- goto again;
- }
-
- if (dump_enabled_p ())
- {
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "Build SLP failed: some of the stmts"
- " are in a pattern, and others are not ");
- dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, oprnd);
- dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
- }
-
- return 1;
- }
-
- dt = STMT_VINFO_DEF_TYPE (def_stmt_info);
-
- if (dt == vect_unknown_def_type)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "Unsupported pattern.\n");
- return -1;
- }
-
- switch (gimple_code (def_stmt_info->stmt))
- {
- case GIMPLE_PHI:
- case GIMPLE_ASSIGN:
- break;
-
- default:
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "unsupported defining stmt:\n");
- return -1;
- }
- }
-
if (second)
oprnd_info->second_pattern = pattern;
|| !types_compatible_p (oprnd_info->first_op_type, type))
{
/* Try swapping operands if we got a mismatch. */
- if (i == 0
- && !swapped
- && commutative)
+ if (i == commutative_op && !swapped)
{
swapped = true;
goto again;
return -1;
}
- gassign *stmt = as_a <gassign *> (stmt_info->stmt);
if (first_op_cond)
{
+ gassign *stmt = as_a <gassign *> (stmt_info->stmt);
tree cond = gimple_assign_rhs1 (stmt);
enum tree_code code = TREE_CODE (cond);
}
}
else
- swap_ssa_operands (stmt, gimple_assign_rhs1_ptr (stmt),
- gimple_assign_rhs2_ptr (stmt));
+ {
+ unsigned int op = commutative_op + first_op_idx;
+ swap_ssa_operands (stmt_info->stmt,
+ gimple_op_ptr (stmt_info->stmt, op),
+ gimple_op_ptr (stmt_info->stmt, op + 1));
+ }
if (dump_enabled_p ())
{
dump_printf_loc (MSG_NOTE, vect_location,
"swapped operands to match def types in ");
- dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
+ dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt_info->stmt, 0);
}
}