simd-1.c: New.
2002-06-16 Aldy Hernandez <aldyh@redhat.com> * 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
This commit is contained in:
parent
147d5f6f76
commit
cb2a532e9f
12 changed files with 414 additions and 62 deletions
|
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
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 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).
|
||||
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}@.
|
||||
|
||||
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:
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
30
gcc/expr.c
30
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"
|
||||
|
|
|
@ -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));
|
||||
|
|
133
gcc/optabs.c
133
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)
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
54
gcc/testsuite/gcc.c-torture/execute/simd-1.c
Normal file
54
gcc/testsuite/gcc.c-torture/execute/simd-1.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* Origin: Aldy Hernandez <aldyh@redhat.com>
|
||||
|
||||
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);
|
||||
}
|
61
gcc/testsuite/gcc.dg/simd-1.c
Normal file
61
gcc/testsuite/gcc.dg/simd-1.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-Wall" } */
|
||||
|
||||
/* Origin: Aldy Hernandez <aldyh@redhat.com>. */
|
||||
/* 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" } */
|
||||
}
|
Loading…
Add table
Reference in a new issue