===================================================================
@@ -6119,7 +6119,7 @@ produce code that uses 4 @code{SIs}.
The types defined in this manner can be used with a subset of normal C
operations. Currently, GCC will allow using the following operators
-on these types: @code{+, -, *, /, unary minus, ^, |, &, ~, %}@.
+on these types: @code{+, -, *, /, unary minus, ^, |, &, ~, %, <<, >>}@.
The operations behave like C++ @code{valarrays}. Addition is defined as
the addition of the corresponding elements of the operands. For
@@ -6135,6 +6135,22 @@ v4si a, b, c;
c = a + b;
@end smallexample
+Shifting operators @code{<<, >>} support integer vector operands doing
+element-wise shifting. Additionally one of the operands can be a
+scalar integer in which case the scalar is converted to the type used
+by the vector operand and each element of this new vector is the
+scalar's value. Consider the following code.
+
+@smallexample
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a, b, c;
+int i = 1;
+
+b = a >> 1; /* b = a >> {1,1,1,1}; */
+c = 1 << a; /* c = {1,1,1,1} << a; */
+@end smallexample
+
Subtraction, multiplication, division, and the logical operations
operate in a similar manner. Likewise, the result of using the unary
minus or complement operators on a vector type is a vector whose
===================================================================
@@ -1312,6 +1312,23 @@ build_vector_from_ctor (tree type, VEC(c
return build_vector (type, nreverse (list));
}
+/* Build a vector of type VECTYPE where all the elements are SCs. */
+tree
+build_vector_from_val (const tree sc, const tree vectype)
+{
+ tree t = NULL_TREE;
+ int i, nunits = TYPE_VECTOR_SUBPARTS (vectype);
+
+ gcc_assert (sc == error_mark_node
+ || TREE_TYPE (sc) == TREE_TYPE (vectype));
+
+ for (i = 0; i < nunits; ++i)
+ t = tree_cons (NULL_TREE, sc, t);
+
+ return build_vector (vectype, t);
+}
+
+
/* Return a new CONSTRUCTOR node whose type is TYPE and whose values
are in the VEC pointed to by VALS. */
tree
===================================================================
@@ -4020,6 +4020,7 @@ extern tree build_int_cst_type (tree, HO
extern tree build_int_cst_wide (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
extern tree build_vector (tree, tree);
extern tree build_vector_from_ctor (tree, VEC(constructor_elt,gc) *);
+extern tree build_vector_from_val (const tree, const tree);
extern tree build_constructor (tree, VEC(constructor_elt,gc) *);
extern tree build_constructor_single (tree, tree, tree);
extern tree build_constructor_from_list (tree, tree);
===================================================================
@@ -0,0 +1,47 @@
+
+#define vector __attribute__((vector_size(sizeof(int)*4) ))
+
+static vector int allones = {1, 1, 1, 1};
+static vector int allzeros = {0, 0, 0, 0};
+static vector int numbers = {0, 1, 2, 3};
+static vector int numbersleftshiftallones = {0, 2, 4, 6};
+static vector int numbersrightshiftallones = {0, 0, 1, 1};
+
+
+static vector unsigned int uallones = {1, 1, 1, 1};
+static vector unsigned int uallzeros = {0, 0, 0, 0};
+static vector unsigned int unumbers = {0, 1, 2, 3};
+static vector unsigned int unumbersleftshiftallones = {0, 2, 4, 6};
+static vector unsigned int unumbersrightshiftallones = {0, 0, 1, 1};
+
+#define TEST(result, expected) \
+do { \
+ typeof(result) result1 = result; \
+ if(sizeof (result1) != sizeof (expected)) \
+ __builtin_abort (); \
+ if (__builtin_memcmp (&result1, &expected, sizeof(result1)) != 0) \
+ __builtin_abort (); \
+}while (0);
+
+int main(void)
+{
+ vector int result;
+ TEST ((numbers << allzeros), numbers);
+ TEST ((numbers >> allzeros), numbers);
+ TEST((numbers << allones), numbersleftshiftallones);
+ TEST((numbers >> allones), numbersrightshiftallones);
+ /* Test left shift followed by a right shift, numbers should be back as
+ numbers are all small numbers and no lose of precision happens. */
+ TEST((numbers << allones) >> allones, numbers);
+
+
+
+ TEST ((unumbers << uallzeros), unumbers);
+ TEST ((unumbers >> uallzeros), unumbers);
+ TEST((unumbers << uallones), unumbersleftshiftallones);
+ TEST((unumbers >> uallones), unumbersrightshiftallones);
+ /* Test left shift followed by a right shift, numbers should be back as
+ numbers are all small numbers and no lose of precision happens. */
+ TEST((unumbers << uallones) >> uallones, unumbers);
+
+}
===================================================================
@@ -0,0 +1,16 @@
+#define vector __attribute__((vector_size(16) ))
+
+int main (int argc, char *argv[]) {
+ vector short v0 = {argc,2,3,4,5,6,7};
+ vector short v1 = {2,2,2,2,2,2,2};
+ vector short r1,r2,r3,r4;
+ int i = 8;
+
+ r1 = v0 << 1;
+ r2 = 1 << v0;
+
+ r3 = v0 << v1;
+ r4 = v0 >> v1;
+
+ return 0;
+}
===================================================================
@@ -9373,6 +9373,32 @@ build_binary_op (location_t location, en
objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
+ /* For most of binary operations in case we have 'vector <op> scalar'
+ or 'scalar <op> vector', we convert a scalar to a vector. For shifts
+ truncating the shift amount is ok. For constants we just check the
+ boundaries. */
+ if ((code0 == VECTOR_TYPE || code1 == VECTOR_TYPE)
+ && (code0 != code1))
+ {
+ switch (code)
+ {
+ case RSHIFT_EXPR:
+ case LSHIFT_EXPR:
+ if (code0 == INTEGER_TYPE)
+ {
+ tree sc = save_expr (op0);
+ sc = convert (TREE_TYPE (type1), sc);
+ op0 = build_vector_from_val (sc, type1);
+ orig_type0 = type0 = TREE_TYPE (op0);
+ code0 = TREE_CODE (type0);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
switch (code)
{
case PLUS_EXPR:
@@ -9534,7 +9560,21 @@ build_binary_op (location_t location, en
Also set SHORT_SHIFT if shifting rightward. */
case RSHIFT_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+ if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
+ {
+ result_type = type0;
+ converted = 1;
+ }
+ else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+ && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+ && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+ {
+ result_type = type0;
+ converted = 1;
+ }
+ else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{
if (TREE_CODE (op1) == INTEGER_CST)
@@ -9561,9 +9601,10 @@ build_binary_op (location_t location, en
/* Use the type of the value to be shifted. */
result_type = type0;
- /* Convert the shift-count to an integer, regardless of size
- of value being shifted. */
- if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+ /* Convert the non vector shift-count to an integer, regardless
+ of size of value being shifted. */
+ if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
op1 = convert (integer_type_node, op1);
/* Avoid converting op1 to result_type later. */
converted = 1;
@@ -9571,7 +9612,21 @@ build_binary_op (location_t location, en
break;
case LSHIFT_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+ if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
+ {
+ result_type = type0;
+ converted = 1;
+ }
+ else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+ && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+ && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+ {
+ result_type = type0;
+ converted = 1;
+ }
+ else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{
if (TREE_CODE (op1) == INTEGER_CST)
@@ -9593,9 +9648,10 @@ build_binary_op (location_t location, en
/* Use the type of the value to be shifted. */
result_type = type0;
- /* Convert the shift-count to an integer, regardless of size
- of value being shifted. */
- if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+ /* Convert the non vector shift-count to an integer, regardless
+ of size of value being shifted. */
+ if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
op1 = convert (integer_type_node, op1);
/* Avoid converting op1 to result_type later. */
converted = 1;