/* Prefer to use the highpart builtin when at least one vector
argument is a reference to the high half of a 128b vector, and
- all others are VECTOR_CSTs that we can extend to 128b. */
+ all others are VECTOR_CSTs or uniform vectors that we can extend
+ to 128b. */
auto_vec<unsigned int, 2> vec_constants;
auto_vec<unsigned int, 2> vec_highparts;
+ auto_vec<unsigned int, 2> vec_uniforms;
/* The arguments and signature of the new call. */
auto_vec<tree, 4> call_args;
auto_vec<tree, 4> call_types;
}
else if (TREE_CODE (arg) == VECTOR_CST)
vec_constants.safe_push (argno);
+ else if (ssa_uniform_vector_p (arg))
+ vec_uniforms.safe_push (argno);
else
return nullptr;
}
call_args[i] = vce_ssa;
}
+ location_t loc = gimple_location (stmt);
+ for (auto i : vec_uniforms)
+ {
+ tree elt = ssa_uniform_vector_p (call_args[i]);
+ tree vec_dup = gimple_build_vector_from_val (gsi, true,
+ GSI_SAME_STMT, loc,
+ call_types[i], elt);
+ call_args[i] = vec_dup;
+ }
+
gcall *new_call = gimple_build_call_vec (builtin_hi, call_args);
gimple_call_set_lhs (new_call, gimple_call_lhs (stmt));
return new_call;
--- /dev/null
+/* { dg-do compile } */
+/* { dg-additional-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_neon.h>
+
+/* We should fold to the highpart builtin when the multiplying the highpart of a
+ 128b vector with a uniform vector which can be widened.
+
+ Use vdup_n_u8 to create an 8x8 splat vector. */
+
+/*
+** foo:
+** ...
+** umull2 v([0-9]+).8h, v([0-9]+).16b, v([0-9]+).16b
+** ...
+*/
+uint16x8_t foo(uint8_t *a, uint8_t *b) {
+ const uint8x8_t uniform_vec = vdup_n_u8(*a);
+ const uint8x16_t hipart_vec = vld1q_u8(b);
+ return vmull_u8(vget_high_u8(hipart_vec), uniform_vec);
+}