Commit 0e3a99ae by Artjoms Sinkarovs Committed by Richard Biener

c-typeck.c (scalar_to_vector): New function.

2011-08-10  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

	* c-typeck.c (scalar_to_vector): New function. Try scalar to
	vector conversion.
	(stv_conv): New enum for scalar_to_vector return type.
	(build_binary_op): Adjust.
	* doc/extend.texi: Description of scalar to vector expansion.

	c-family/
	* c-common.c (unsafe_conversion_p): New function. Check if it is
	unsafe to convert an expression to the type.
	(conversion_warning): Adjust, use unsafe_conversion_p.
	* c-common.h (unsafe_conversion_p): New function declaration.

	testsuite/
	* gcc.c-torture/execute/scal-to-vec1.c: New test.
	* gcc.c-torture/execute/scal-to-vec2.c: New test.
	* gcc.c-torture/execute/scal-to-vec3.c: New test.
	* gcc.dg/scal-to-vec1.c: New test.
	* gcc.dg/scal-to-vec2.c: New test.

From-SVN: r177622
parent 0eb77834
2011-08-10 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
* c-typeck.c (scalar_to_vector): New function. Try scalar to
vector conversion.
(stv_conv): New enum for scalar_to_vector return type.
(build_binary_op): Adjust.
* doc/extend.texi: Description of scalar to vector expansion.
2011-08-10 Richard Guenther <rguenther@suse.de>
* tree.h (get_pointer_alignment): Remove max-align argument.
......
2011-08-10 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
* c-common.c (unsafe_conversion_p): New function. Check if it is
unsafe to convert an expression to the type.
(conversion_warning): Adjust, use unsafe_conversion_p.
* c-common.h (unsafe_conversion_p): New function declaration.
2011-08-02 Jakub Jelinek <jakub@redhat.com>
* c-common.h (c_finish_omp_atomic): Adjust prototype.
......
......@@ -742,6 +742,7 @@ extern tree c_common_signed_type (tree);
extern tree c_common_signed_or_unsigned_type (int, tree);
extern void c_common_init_ts (void);
extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
extern bool unsafe_conversion_p (tree, tree, bool);
extern bool decl_with_nonnull_addr_p (const_tree);
extern tree c_fully_fold (tree, bool, bool *);
extern tree decl_constant_value_for_optimization (tree);
......
......@@ -51,6 +51,14 @@ enum impl_conv {
ic_return
};
/* Possibe cases of scalar_to_vector conversion. */
enum stv_conv {
stv_error, /* Error occured. */
stv_nothing, /* Nothing happened. */
stv_firstarg, /* First argument must be expanded. */
stv_secondarg /* Second argument must be expanded. */
};
/* The level of nesting inside "__alignof__". */
int in_alignof;
......@@ -9323,6 +9331,88 @@ push_cleanup (tree decl, tree cleanup, bool eh_only)
TREE_OPERAND (stmt, 0) = list;
STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
}
/* Convert scalar to vector for the range of operations. */
static enum stv_conv
scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
{
tree type0 = TREE_TYPE (op0);
tree type1 = TREE_TYPE (op1);
bool integer_only_op = false;
enum stv_conv ret = stv_firstarg;
gcc_assert (TREE_CODE (type0) == VECTOR_TYPE
|| TREE_CODE (type1) == VECTOR_TYPE);
switch (code)
{
case RSHIFT_EXPR:
case LSHIFT_EXPR:
if (TREE_CODE (type0) == INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
{
if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
{
error_at (loc, "conversion of scalar to vector "
"involves truncation");
return stv_error;
}
else
return stv_firstarg;
}
break;
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_AND_EXPR:
integer_only_op = true;
/* ... fall through ... */
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
case TRUNC_DIV_EXPR:
case TRUNC_MOD_EXPR:
case RDIV_EXPR:
if (TREE_CODE (type0) == VECTOR_TYPE)
{
tree tmp;
ret = stv_secondarg;
/* Swap TYPE0 with TYPE1 and OP0 with OP1 */
tmp = type0; type0 = type1; type1 = tmp;
tmp = op0; op0 = op1; op1 = tmp;
}
if (TREE_CODE (type0) == INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
{
if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
{
error_at (loc, "conversion of scalar to vector "
"involves truncation");
return stv_error;
}
return ret;
}
else if (!integer_only_op
/* Allow integer --> real conversion if safe. */
&& (TREE_CODE (type0) == REAL_TYPE
|| TREE_CODE (type0) == INTEGER_TYPE)
&& SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
{
if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
{
error_at (loc, "conversion of scalar to vector "
"involves truncation");
return stv_error;
}
return ret;
}
default:
break;
}
return stv_nothing;
}
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
......@@ -9434,7 +9524,10 @@ build_binary_op (location_t location, enum tree_code code,
else
int_const = int_const_or_overflow = false;
if (convert_p)
/* Do not apply default conversion in mixed vector/scalar expression. */
if (convert_p
&& !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE)
!= (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
{
op0 = default_conversion (op0);
op1 = default_conversion (op1);
......@@ -9506,6 +9599,51 @@ build_binary_op (location_t location, enum tree_code code,
objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
/* In case when one of the operands of the binary operation is
a vector and another is a scalar -- convert scalar to vector. */
if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
{
enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
switch (convert_flag)
{
case stv_error:
return error_mark_node;
case stv_firstarg:
{
bool maybe_const = true;
tree sc;
sc = c_fully_fold (op0, false, &maybe_const);
sc = save_expr (sc);
sc = convert (TREE_TYPE (type1), sc);
op0 = build_vector_from_val (type1, sc);
if (!maybe_const)
op0 = c_wrap_maybe_const (op0, true);
orig_type0 = type0 = TREE_TYPE (op0);
code0 = TREE_CODE (type0);
converted = 1;
break;
}
case stv_secondarg:
{
bool maybe_const = true;
tree sc;
sc = c_fully_fold (op1, false, &maybe_const);
sc = save_expr (sc);
sc = convert (TREE_TYPE (type0), sc);
op1 = build_vector_from_val (type0, sc);
if (!maybe_const)
op0 = c_wrap_maybe_const (op1, true);
orig_type1 = type1 = TREE_TYPE (op1);
code1 = TREE_CODE (type1);
converted = 1;
break;
}
default:
break;
}
}
switch (code)
{
case PLUS_EXPR:
......
......@@ -6526,18 +6526,25 @@ In C it is possible to use shifting operators @code{<<}, @code{>>} on
integer-type vectors. The operation is defined as following: @code{@{a0,
a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
@dots{}, an >> bn@}}@. Vector operands must have the same number of
elements. Additionally second operands can be a scalar integer in which
case the scalar is converted to the type used by the vector operand (with
possible truncation) and each element of this new vector is the scalar's
value.
elements.
For the convenience in C it is allowed to use a binary vector operation
where one operand is a scalar. In that case the compiler will transform
the scalar operand into a vector where each element is the scalar from
the operation. The transformation will happen only if the scalar could be
safely converted to the vector-element type.
Consider the following code.
@smallexample
typedef int v4si __attribute__ ((vector_size (16)));
v4si a, b;
v4si a, b, c;
long l;
a = b + 1; /* a = b + @{1,1,1,1@}; */
a = 2 * b; /* a = @{2,2,2,2@} * b; */
b = a >> 1; /* b = a >> @{1,1,1,1@}; */
a = l + a; /* Error, cannot convert long to int. */
@end smallexample
In C vectors can be subscripted as if the vector were an array with
......
2011-08-10 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
* gcc.c-torture/execute/scal-to-vec1.c: New test.
* gcc.c-torture/execute/scal-to-vec2.c: New test.
* gcc.c-torture/execute/scal-to-vec3.c: New test.
* gcc.dg/scal-to-vec1.c: New test.
* gcc.dg/scal-to-vec2.c: New test.
2011-08-09 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/vrp57.c: Disable CCP.
......
#define vector(elcount, type) \
__attribute__((vector_size((elcount)*sizeof(type)))) type
#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
#define operl(a, b, op) (a op b)
#define operr(a, b, op) (b op a)
#define check(type, count, vec0, vec1, num, op, lr) \
do {\
int __i; \
for (__i = 0; __i < count; __i++) {\
if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
__builtin_abort (); \
}\
} while (0)
#define veccompare(type, count, v0, v1) \
do {\
int __i; \
for (__i = 0; __i < count; __i++) { \
if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
__builtin_abort (); \
} \
} while (0)
int main (int argc, char *argv[]) {
#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
#define dvec_2 (vector(2, double)){2., 2.}
vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
vector(8, short) v1;
vector(4, float) f0 = {1., 2., 3., 4.};
vector(4, float) f1, f2;
vector(2, double) d0 = {1., 2.};
vector(2, double) d1, d2;
v1 = 2 + v0; check (short, 8, v0, v1, 2, +, l);
v1 = 2 - v0; check (short, 8, v0, v1, 2, -, l);
v1 = 2 * v0; check (short, 8, v0, v1, 2, *, l);
v1 = 2 / v0; check (short, 8, v0, v1, 2, /, l);
v1 = 2 % v0; check (short, 8, v0, v1, 2, %, l);
v1 = 2 ^ v0; check (short, 8, v0, v1, 2, ^, l);
v1 = 2 & v0; check (short, 8, v0, v1, 2, &, l);
v1 = 2 | v0; check (short, 8, v0, v1, 2, |, l);
v1 = 2 << v0; check (short, 8, v0, v1, 2, <<, l);
v1 = 2 >> v0; check (short, 8, v0, v1, 2, >>, l);
v1 = v0 + 2; check (short, 8, v0, v1, 2, +, r);
v1 = v0 - 2; check (short, 8, v0, v1, 2, -, r);
v1 = v0 * 2; check (short, 8, v0, v1, 2, *, r);
v1 = v0 / 2; check (short, 8, v0, v1, 2, /, r);
v1 = v0 % 2; check (short, 8, v0, v1, 2, %, r);
v1 = v0 ^ 2; check (short, 8, v0, v1, 2, ^, r);
v1 = v0 & 2; check (short, 8, v0, v1, 2, &, r);
v1 = v0 | 2; check (short, 8, v0, v1, 2, |, r);
f1 = 2. + f0; f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
f1 = 2. - f0; f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
f1 = 2. * f0; f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
f1 = 2. / f0; f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
f1 = f0 + 2.; f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
f1 = f0 - 2.; f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
f1 = f0 * 2.; f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
f1 = f0 / 2.; f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
d1 = 2. + d0; d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
d1 = 2. - d0; d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
d1 = 2. * d0; d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
d1 = 2. / d0; d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
d1 = d0 + 2.; d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
d1 = d0 - 2.; d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
d1 = d0 * 2.; d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
d1 = d0 / 2.; d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
return 0;
}
#define vector(elcount, type) \
__attribute__((vector_size((elcount)*sizeof(type)))) type
#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
#define operl(a, b, op) (a op b)
#define operr(a, b, op) (b op a)
#define check(type, count, vec0, vec1, num, op, lr) \
do {\
int __i; \
for (__i = 0; __i < count; __i++) {\
if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
__builtin_abort (); \
}\
} while (0)
#define veccompare(type, count, v0, v1) \
do {\
int __i; \
for (__i = 0; __i < count; __i++) { \
if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
__builtin_abort (); \
} \
} while (0)
long __attribute__ ((noinline)) vlng () { return (long)42; }
int __attribute__ ((noinline)) vint () { return (int) 43; }
short __attribute__ ((noinline)) vsrt () { return (short)42; }
char __attribute__ ((noinline)) vchr () { return (char)42; }
int main (int argc, char *argv[]) {
vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
vector(16, char) c1;
vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
vector(8, short) s1;
vector(4, int) i0 = {argc, 1, 2, 3};
vector(4, int) i1;
vector(2, long) l0 = {argc, 1};
vector(2, long) l1;
c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
return 0;
}
#define vector(elcount, type) \
__attribute__((vector_size((elcount)*sizeof(type)))) type
#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
#define veccompare(type, count, v0, v1) \
do {\
int __i; \
for (__i = 0; __i < count; __i++) { \
if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
__builtin_abort (); \
} \
} while (0)
int main (int argc, char *argv[]) {
#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
#define dvec_2 (vector(2, double)){2., 2.}
vector(4, float) f0 = {1., 2., 3., 4.};
vector(4, float) f1, f2;
vector(2, double) d0 = {1., 2.};
vector(2, double) d1, d2;
f1 = 2 + f0; f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
f1 = 2 - f0; f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
f1 = 2 * f0; f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
f1 = 2 / f0; f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
f1 = f0 + 2; f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
f1 = f0 - 2; f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
f1 = f0 * 2; f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
f1 = f0 / 2; f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
d1 = 2 + d0; d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
d1 = 2 - d0; d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
d1 = 2 * d0; d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
d1 = 2 / d0; d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
d1 = d0 + 2; d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
d1 = d0 - 2; d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
d1 = d0 * 2; d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
d1 = d0 / 2; d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
return 0;
}
/* { dg-do compile } */
/* { dg-options "-Wno-long-long" } */
#define vector(elcount, type) \
__attribute__((vector_size((elcount)*sizeof(type)))) type
#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
extern float sfl;
extern int sint;
extern long long sll;
int main (int argc, char *argv[]) {
vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
vector(8, short) v1;
vector(4, float) f0 = {1., 2., 3., 4.};
vector(4, float) f1, f2;
vector(4, int) i0 = {1,2,3,4};
vector(4, int) i1, i2;
int i = 12;
double d = 3.;
v1 = i + v0; /* { dg-error "conversion of scalar to vector" } */
v1 = 99999 + v0; /* { dg-error "conversion of scalar to vector" } */
f1 = d + f0; /* { dg-error "conversion of scalar to vector" } */
f1 = 1.3 + f0; /* { dg-error "conversion of scalar to vector" } */
f1 = sll + f0; /* { dg-error "conversion of scalar to vector" } */
f1 = ((int)998769576) + f0; /* { dg-error "conversion of scalar to vector" } */
/* convert.c should take care of this. */
i1 = sfl + i0; /* { dg-error "can't convert value to a vector" } */
i1 = 1.5 + i0; /* { dg-error "can't convert value to a vector" } */
v1 = d + v0; /* { dg-error "can't convert value to a vector" } */
return 0;
}
/* { dg-do compile } */
/* Test for C_MAYBE_CONST are folded correctly when
expanding an expression to vector. */
int f(void);
unsigned int g(void);
unsigned int h;
typedef unsigned int vec __attribute__((vector_size(16)));
vec i;
vec fv1(void) { return i + (h ? f() : g()); }
vec fv2(void) { return (h ? f() : g()) + i; }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment