From cb2a532e9fe754ec238fe679a131e1fd1c8c340e Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 18 Jun 2002 01:35:47 +0000 Subject: [PATCH] simd-1.c: New. 2002-06-16 Aldy Hernandez * gcc.c-torture/execute/simd-1.c: New. * gcc.dg/simd-1.c: New. * doc/extend.texi (Vector Extensions): Document that we can specify simd types not specifically supported by the hardware. Document that simd types can be used as function arguments. Document that signness does make a difference in SIMD types. Misc cleanups and revisions to the "vector extensions" section. * simplify-rtx.c (simplify_subreg): Simplify subregs of vector constants. * expr.c (vector_mode_valid_p): New. * expr.h: Add vector_mode_valid_p. * defaults.h (VECTOR_MODE_SUPPORTED_P): Set default. * emit-rtl.c (immed_double_const): Do not abort on vectors. * c-common.c (type_for_mode): Always build vector nodes regardless of VECTOR_MODE_SUPPORTED_P. (handle_mode_attribute): Error if we can't emulate a nonexisting vector mode. (handle_vector_size_attribute): Same. * optabs.c (expand_binop): Open-code vector operations. (expand_unop): Open-code vector unops. (expand_vector_binop): New. (expand_vector_unop): New. * c-typeck.c (build_binary_op): Allow vectors in binops. Allow vectors in conditional operatiors. (build_unary_op): Allow vectors in unary minus. * config/rs6000/rs6000.h (ALTIVEC_VECTOR_MODE): Conditionalize on TARGET_ALTIVEC. From-SVN: r54727 --- gcc/c-common.c | 83 +++++++----- gcc/c-typeck.c | 21 +-- gcc/config/rs6000/rs6000.h | 9 +- gcc/defaults.h | 4 + gcc/doc/extend.texi | 62 ++++++--- gcc/emit-rtl.c | 5 +- gcc/expr.c | 30 +++++ gcc/expr.h | 2 + gcc/optabs.c | 133 +++++++++++++++++++ gcc/simplify-rtx.c | 18 +++ gcc/testsuite/gcc.c-torture/execute/simd-1.c | 54 ++++++++ gcc/testsuite/gcc.dg/simd-1.c | 61 +++++++++ 12 files changed, 417 insertions(+), 65 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/simd-1.c create mode 100644 gcc/testsuite/gcc.dg/simd-1.c diff --git a/gcc/c-common.c b/gcc/c-common.c index b58ba4ef474..b477fe78f16 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1602,38 +1602,33 @@ c_common_type_for_mode (mode, unsignedp) if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) return build_pointer_type (integer_type_node); -#ifdef VECTOR_MODE_SUPPORTED_P - if (VECTOR_MODE_SUPPORTED_P (mode)) - { - switch (mode) - { - case V16QImode: - return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node; - case V8HImode: - return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node; - case V4SImode: - return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node; - case V2DImode: - return unsignedp ? unsigned_V2DI_type_node : V2DI_type_node; - case V2SImode: - return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node; - case V4HImode: - return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node; - case V8QImode: - return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node; - case V16SFmode: - return V16SF_type_node; - case V4SFmode: - return V4SF_type_node; - case V2SFmode: - return V2SF_type_node; - case V2DFmode: - return V2DF_type_node; - default: - break; - } + switch (mode) + { + case V16QImode: + return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node; + case V8HImode: + return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node; + case V4SImode: + return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node; + case V2DImode: + return unsignedp ? unsigned_V2DI_type_node : V2DI_type_node; + case V2SImode: + return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node; + case V4HImode: + return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node; + case V8QImode: + return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node; + case V16SFmode: + return V16SF_type_node; + case V4SFmode: + return V4SF_type_node; + case V2SFmode: + return V2SF_type_node; + case V2DFmode: + return V2DF_type_node; + default: + break; } -#endif return 0; } @@ -5058,8 +5053,20 @@ handle_mode_attribute (node, name, args, flags, no_add_attrs) (mode, TREE_UNSIGNED (type)))) error ("no data type for mode `%s'", p); else - *node = typefm; - /* No need to layout the type here. The caller should do this. */ + { + /* If this is a vector, make sure we either have hardware + support, or we can emulate it. */ + if ((GET_MODE_CLASS (mode) == MODE_VECTOR_INT + || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT) + && !vector_mode_valid_p (mode)) + { + error ("unable to emulate '%s'", GET_MODE_NAME (mode)); + return NULL_TREE; + } + + *node = typefm; + /* No need to layout the type here. The caller should do this. */ + } } return NULL_TREE; @@ -5604,6 +5611,16 @@ handle_vector_size_attribute (node, name, args, flags, no_add_attrs) new_type = build_type_copy (new_type); + /* If this is a vector, make sure we either have hardware + support, or we can emulate it. */ + if ((GET_MODE_CLASS (mode) == MODE_VECTOR_INT + || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT) + && !vector_mode_valid_p (mode)) + { + error ("unable to emulate '%s'", GET_MODE_NAME (mode)); + return NULL_TREE; + } + /* Set the debug information here, because this is the only place where we know the underlying type for a vector made with vector_size. For debugging purposes we pretend a vector diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 76ebc3416d9..d26f87780f3 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -2046,9 +2046,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p) warning ("division by zero"); if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE - || code0 == COMPLEX_TYPE) + || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE) && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == COMPLEX_TYPE)) + || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)) { if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)) resultcode = RDIV_EXPR; @@ -2197,9 +2197,11 @@ build_binary_op (code, orig_op0, orig_op1, convert_p) but don't convert the args to int! */ build_type = integer_type_node; if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE - || code0 == COMPLEX_TYPE) + || code0 == COMPLEX_TYPE + || code0 == VECTOR_TYPE) && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == COMPLEX_TYPE)) + || code1 == COMPLEX_TYPE + || code1 == VECTOR_TYPE)) short_compare = 1; else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) { @@ -2342,9 +2344,11 @@ build_binary_op (code, orig_op0, orig_op1, convert_p) break; } - if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE) + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE + || code0 == VECTOR_TYPE) && - (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE)) + (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE + || code1 == VECTOR_TYPE)) { int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE); @@ -2763,7 +2767,8 @@ build_unary_op (code, xarg, flag) case NEGATE_EXPR: if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE - || typecode == COMPLEX_TYPE)) + || typecode == COMPLEX_TYPE + || typecode == VECTOR_TYPE)) { error ("wrong type argument to unary minus"); return error_mark_node; @@ -4079,7 +4084,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum) else if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE || codel == BOOLEAN_TYPE) - && (coder == INTEGER_TYPE || coder == REAL_TYPE + && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE || coder == BOOLEAN_TYPE)) return convert_and_check (type, rhs); diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 2d8b9244431..91aca6c5d51 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -817,10 +817,11 @@ extern int rs6000_default_long_calls; : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) #define ALTIVEC_VECTOR_MODE(MODE) \ - ((MODE) == V16QImode \ - || (MODE) == V8HImode \ - || (MODE) == V4SFmode \ - || (MODE) == V4SImode) + (TARGET_ALTIVEC && \ + ((MODE) == V16QImode \ + || (MODE) == V8HImode \ + || (MODE) == V4SFmode \ + || (MODE) == V4SImode)) /* Define this macro to be nonzero if the port is prepared to handle insns involving vector mode MODE. At the very least, it must have diff --git a/gcc/defaults.h b/gcc/defaults.h index 9db7bfe9da8..3bbf231c2f0 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -513,6 +513,10 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE! #define UNLIKELY_EXECUTED_TEXT_SECTION_NAME "text.unlikely" #endif +#ifndef VECTOR_MODE_SUPPORTED_P +#define VECTOR_MODE_SUPPORTED_P(MODE) 0 +#endif + /* Determine whether __cxa_atexit, rather than atexit, is used to register C++ destructors for local statics and global objects. */ #ifndef DEFAULT_USE_CXA_ATEXIT diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 17fffac27b8..1da05ad423d 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -4373,28 +4373,52 @@ A floating point value, as wide as a SI mode integer, usually 32 bits. A floating point value, as wide as a DI mode integer, usually 64 bits. @end table -Not all base types or combinations are always valid; which modes can be used -is determined by the target machine. For example, if targetting the i386 MMX -extensions, only @code{V8QI}, @code{V4HI} and @code{V2SI} are allowed modes. - There are no @code{V1xx} vector modes - they would be identical to the corresponding base mode. -There is no distinction between signed and unsigned vector modes. This -distinction is made by the operations that perform on the vectors, not -by the data type. - -The types defined in this manner are somewhat special, they cannot be -used with most normal C operations (i.e., a vector addition can @emph{not} -be represented by a normal addition of two vector type variables). You -can declare only variables and use them in function calls and returns, as -well as in assignments and some casts. It is possible to cast from one -vector type to another, provided they are of the same size (in fact, you -can also cast vectors to and from other datatypes of the same size). - -A port that supports vector operations provides a set of built-in functions -that can be used to operate on vectors. For example, a function to add two -vectors and multiply the result by a third could look like this: +Specifying a combination that is not valid for the current architecture +will cause gcc to synthesize the instructions using a narrower mode. +For example, if you specify a variable of type @code{V4SI} and your +architecture does not allow for this specific SIMD type, gcc will +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}@. + +The operations behave like C++ @code{valarrays}. Addition is defined as +the addition of the corresponding elements of the operands. For +example, in the code below, each of the 4 elements in @var{a} will be +added to the corresponding 4 elements in @var{b} and the resulting +vector will be stored in @var{c}. + +@example +typedef int v4si __attribute__ ((mode(V4SI))); + +v4si a, b, c; + +c = a + b; +@end example + +Subtraction, multiplication, and division operate in a similar manner. +Likewise, the result of using the unary minus operator on a vector type +is a vector whose elements are the negative value of the corresponding +elements in the operand. + +You can declare variables and use them in function calls and returns, as +well as in assignments and some casts. You can specify a vector type as +a return type for a function. Vector types can also be used as function +arguments. It is possible to cast from one vector type to another, +provided they are of the same size (in fact, you can also cast vectors +to and from other datatypes of the same size). + +You cannot operate between vectors of different lengths or different +signness without a cast. + +A port that supports hardware vector operations, usually provides a set +of built-in functions that can be used to operate on vectors. For +example, a function to add two vectors and multiply the result by a +third could look like this: @example v4si f (v4si a, v4si b, v4si c) diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 225b8c89332..77697aef7e4 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -421,7 +421,10 @@ immed_double_const (i0, i1, mode) { int width; if (GET_MODE_CLASS (mode) != MODE_INT - && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) + && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT + /* We can get a 0 for an error mark. */ + && GET_MODE_CLASS (mode) != MODE_VECTOR_INT + && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT) abort (); /* We clear out all bits that don't belong in MODE, unless they and diff --git a/gcc/expr.c b/gcc/expr.c index bba785ab33b..779bf879755 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -10791,4 +10791,34 @@ try_tablejump (index_type, index_expr, minval, range, return 1; } +/* Nonzero if the mode is a valid vector mode for this architecture. + This returns nonzero even if there is no hardware support for the + vector mode, but we can emulate with narrower modes. */ + +int +vector_mode_valid_p (mode) + enum machine_mode mode; +{ + enum mode_class class = GET_MODE_CLASS (mode); + enum machine_mode innermode; + + /* Doh! What's going on? */ + if (class != MODE_VECTOR_INT + && class != MODE_VECTOR_FLOAT) + return 0; + + /* Hardware support. Woo hoo! */ + if (VECTOR_MODE_SUPPORTED_P (mode)) + return 1; + + innermode = GET_MODE_INNER (mode); + + /* We should probably return 1 if requesting V4DI and we have no DI, + but we have V2DI, but this is probably very unlikely. */ + + /* If we have support for the inner mode, we can safely emulate it. + We may not have V2DI, but me can emulate with a pair of DIs. */ + return mov_optab->handlers[innermode].insn_code != CODE_FOR_nothing; +} + #include "gt-expr.h" diff --git a/gcc/expr.h b/gcc/expr.h index 5ebefbad8ba..b829d9b6381 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -786,3 +786,5 @@ extern void do_jump_by_parts_greater_rtx PARAMS ((enum machine_mode, extern void mark_seen_cases PARAMS ((tree, unsigned char *, HOST_WIDE_INT, int)); #endif + +extern int vector_mode_valid_p PARAMS ((enum machine_mode)); diff --git a/gcc/optabs.c b/gcc/optabs.c index 88cdf2f8b9c..61990e3eb08 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -120,6 +120,11 @@ static void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode, enum rtx_code, int, rtx)); static void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *, enum machine_mode *, int *)); +static rtx expand_vector_binop PARAMS ((enum machine_mode, optab, + rtx, rtx, rtx, int, + enum optab_methods)); +static rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx, + int)); /* Add a REG_EQUAL note to the last insn in INSNS. TARGET is being set to the result of operation CODE applied to OP0 (and OP1 if it is a binary @@ -1531,6 +1536,12 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) delete_insns_since (last); } + /* Open-code the vector operations if we have no hardware support + for them. */ + if (class == MODE_VECTOR_INT || class == MODE_VECTOR_FLOAT) + return expand_vector_binop (mode, binoptab, op0, op1, target, + unsignedp, methods); + /* We need to open-code the complex type operations: '+, -, * and /' */ /* At this point we allow operations between two similar complex @@ -1900,6 +1911,125 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) delete_insns_since (entry_last); return 0; } + +/* Like expand_binop, but for open-coding vectors binops. */ + +static rtx +expand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods) + enum machine_mode mode; + optab binoptab; + rtx op0, op1; + rtx target; + int unsignedp; + enum optab_methods methods; +{ + enum machine_mode submode; + int elts, i; + rtx t, a, b, res, seq; + enum mode_class class; + + class = GET_MODE_CLASS (mode); + + submode = GET_MODE_INNER (mode); + elts = GET_MODE_NUNITS (mode); + + if (!target) + target = gen_reg_rtx (mode); + + start_sequence (); + + /* FIXME: Optimally, we should try to do this in narrower vector + modes if available. E.g. When trying V8SI, try V4SI, else + V2SI, else decay into SI. */ + + switch (binoptab->code) + { + case PLUS: + case MINUS: + case MULT: + case DIV: + for (i = 0; i < elts; ++i) + { + t = simplify_gen_subreg (submode, target, mode, + i * UNITS_PER_WORD); + a = simplify_gen_subreg (submode, op0, mode, + i * UNITS_PER_WORD); + b = simplify_gen_subreg (submode, op1, mode, + i * UNITS_PER_WORD); + + if (binoptab->code == DIV) + { + if (class == MODE_VECTOR_FLOAT) + res = expand_binop (submode, binoptab, a, b, t, + unsignedp, methods); + else + res = expand_divmod (0, TRUNC_DIV_EXPR, submode, + a, b, t, unsignedp); + } + else + res = expand_binop (submode, binoptab, a, b, t, + unsignedp, methods); + + if (res == 0) + break; + + emit_move_insn (t, res); + } + break; + + default: + abort (); + } + + seq = get_insns (); + end_sequence (); + emit_insn (seq); + + return target; +} + +/* Like expand_unop but for open-coding vector unops. */ + +static rtx +expand_vector_unop (mode, unoptab, op0, target, unsignedp) + enum machine_mode mode; + optab unoptab; + rtx op0; + rtx target; + int unsignedp; +{ + enum machine_mode submode; + int elts, i; + rtx t, a, res, seq; + + submode = GET_MODE_INNER (mode); + elts = GET_MODE_NUNITS (mode); + + if (!target) + target = gen_reg_rtx (mode); + + start_sequence (); + + /* FIXME: Optimally, we should try to do this in narrower vector + modes if available. E.g. When trying V8SI, try V4SI, else + V2SI, else decay into SI. */ + + for (i = 0; i < elts; ++i) + { + t = simplify_gen_subreg (submode, target, mode, i * UNITS_PER_WORD); + a = simplify_gen_subreg (submode, op0, mode, i * UNITS_PER_WORD); + + res = expand_unop (submode, unoptab, a, t, unsignedp); + + emit_move_insn (t, res); + } + + seq = get_insns (); + end_sequence (); + emit_insn (seq); + + return target; +} /* Expand a binary operator which has both signed and unsigned forms. UOPTAB is the optab for unsigned operations, and SOPTAB is for @@ -2324,6 +2454,9 @@ expand_unop (mode, unoptab, op0, target, unsignedp) return target; } + if (class == MODE_VECTOR_FLOAT || class == MODE_VECTOR_INT) + return expand_vector_unop (mode, unoptab, op0, target, unsignedp); + /* It can't be done in this mode. Can we do it in a wider mode? */ if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 5a4509c602c..cdc60433654 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -2268,6 +2268,24 @@ simplify_subreg (outermode, op, innermode, byte) if (outermode == innermode && !byte) return op; + /* Simplify subregs of vector constants. */ + if (GET_CODE (op) == CONST_VECTOR) + { + int offset = byte / UNITS_PER_WORD; + rtx elt; + + /* This shouldn't happen, but let's not do anything stupid. */ + if (GET_MODE_INNER (innermode) != outermode) + return NULL_RTX; + + elt = CONST_VECTOR_ELT (op, offset); + + /* ?? We probably don't need this copy_rtx because constants + can be shared. ?? */ + + return copy_rtx (elt); + } + /* Attempt to simplify constant to non-SUBREG expression. */ if (CONSTANT_P (op)) { diff --git a/gcc/testsuite/gcc.c-torture/execute/simd-1.c b/gcc/testsuite/gcc.c-torture/execute/simd-1.c new file mode 100644 index 00000000000..cb503e457d8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/simd-1.c @@ -0,0 +1,54 @@ +/* Origin: Aldy Hernandez + + Purpose: Test generic SIMD support. This test should work + regardless of if the target has SIMD instructions. +*/ + +typedef int __attribute__((mode(V4SI))) vecint; + +vecint i = { 150, 100, 150, 200 }; +vecint j = { 10, 13, 20, 30 }; +vecint k; + +union { + vecint v; + int i[4]; +} res; + +/* This should go away once we can use == and != on vector types. */ +void +verify (int a1, int a2, int a3, int a4, + int b1, int b2, int b3, int b4) +{ + if (a1 != b1 + || a2 != b2 + || a3 != b3 + || a4 != b4) + abort (); +} + +int +main () +{ + k = i + j; + res.v = k; + + verify (res.i[0], res.i[1], res.i[2], res.i[3], 160, 113, 170, 230); + + k = i * j; + res.v = k; + + verify (res.i[0], res.i[1], res.i[2], res.i[3], 1500, 1300, 3000, 6000); + + k = i / j; + res.v = k; + + verify (res.i[0], res.i[1], res.i[2], res.i[3], 15, 7, 7, 6); + + k = -i; + res.v = k; + verify (res.i[0], res.i[1], res.i[2], res.i[3], + -150, -100, -150, -200); + + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/simd-1.c b/gcc/testsuite/gcc.dg/simd-1.c new file mode 100644 index 00000000000..fff6292d1a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/simd-1.c @@ -0,0 +1,61 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +/* Origin: Aldy Hernandez . */ +/* Purpose: Program to test generic SIMD support. */ + +typedef int __attribute__((mode(V4SI))) v4si; +typedef int __attribute__((mode(V8HI))) v8hi; +typedef int __attribute__((mode(V2SI))) v2si; +typedef unsigned int __attribute__((mode(V4SI))) uv4si; + +v4si a, b; +v2si c, d; +v8hi e; +uv4si f; + +int foo __attribute__((mode(DI))); +int foo1 __attribute__((mode(SI))); +int foo2 __attribute__((mode(V4HI))); + +void +hanneke () +{ + /* Assignment. */ + a = b; + + /* Assignment of different types. */ + b = c; /* { dg-error "incompatible types in assignment" } */ + d = a; /* { dg-error "incompatible types in assignment" } */ + + /* Casting between SIMDs of the same size. */ + e = (typeof (e)) a; + + /* Different signed SIMD assignment. */ + f = a; /* { dg-error "incompatible types in assignment" } */ + + /* Casted different signed SIMD assignment. */ + f = (uv4si) a; + + /* Assignment between scalar and SIMD of different size. */ + foo = a; /* { dg-error "incompatible types in assignment" } */ + + /* Casted assignment between scalar and SIMD of same size. */ + foo = (typeof (foo)) foo2; + + /* Casted assignment between scalar and SIMD of different size. */ + foo1 = (typeof (foo1)) foo2; /* { dg-error "can't convert between vector values of different size" } */ + + /* Operators on compatible SIMD types. */ + a += b + b; + a -= b; + a *= b; + a /= b; + a = -b; + + /* Operators on incompatible SIMD types. */ + a = b + c; /* { dg-error "can't convert between vector values of different size" } */ + a = b - c; /* { dg-error "can't convert between vector values of different size" } */ + a = b * c; /* { dg-error "can't convert between vector values of different size" } */ + a = b / c; /* { dg-error "can't convert between vector values of different size" } */ +} -- 2.30.2