aboutsummaryrefslogtreecommitdiff
path: root/gdb/opencl-lang.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/opencl-lang.c')
-rw-r--r--gdb/opencl-lang.c1162
1 files changed, 1162 insertions, 0 deletions
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
new file mode 100644
index 0000000..088d49a
--- /dev/null
+++ b/gdb/opencl-lang.c
@@ -0,0 +1,1162 @@
+/* OpenCL language support for GDB, the GNU debugger.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ Contributed by Ken Werner <ken.werner@de.ibm.com>.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include "gdbtypes.h"
+#include "symtab.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "symtab.h"
+#include "language.h"
+#include "c-lang.h"
+#include "gdb_assert.h"
+
+extern void _initialize_opencl_language (void);
+
+/* This macro generates enum values from a given type. */
+
+#define OCL_P_TYPE(TYPE)\
+ opencl_primitive_type_##TYPE,\
+ opencl_primitive_type_##TYPE##2,\
+ opencl_primitive_type_##TYPE##3,\
+ opencl_primitive_type_##TYPE##4,\
+ opencl_primitive_type_##TYPE##8,\
+ opencl_primitive_type_##TYPE##16
+
+enum opencl_primitive_types {
+ OCL_P_TYPE (char),
+ OCL_P_TYPE (uchar),
+ OCL_P_TYPE (short),
+ OCL_P_TYPE (ushort),
+ OCL_P_TYPE (int),
+ OCL_P_TYPE (uint),
+ OCL_P_TYPE (long),
+ OCL_P_TYPE (ulong),
+ OCL_P_TYPE (half),
+ OCL_P_TYPE (float),
+ OCL_P_TYPE (double),
+ opencl_primitive_type_bool,
+ opencl_primitive_type_unsigned_char,
+ opencl_primitive_type_unsigned_short,
+ opencl_primitive_type_unsigned_int,
+ opencl_primitive_type_unsigned_long,
+ opencl_primitive_type_size_t,
+ opencl_primitive_type_ptrdiff_t,
+ opencl_primitive_type_intptr_t,
+ opencl_primitive_type_uintptr_t,
+ opencl_primitive_type_void,
+ nr_opencl_primitive_types
+};
+
+/* This macro generates the type struct declarations from a given type. */
+
+#define STRUCT_OCL_TYPE(TYPE)\
+ struct type *builtin_##TYPE;\
+ struct type *builtin_##TYPE##2;\
+ struct type *builtin_##TYPE##3;\
+ struct type *builtin_##TYPE##4;\
+ struct type *builtin_##TYPE##8;\
+ struct type *builtin_##TYPE##16
+
+struct builtin_opencl_type
+{
+ STRUCT_OCL_TYPE (char);
+ STRUCT_OCL_TYPE (uchar);
+ STRUCT_OCL_TYPE (short);
+ STRUCT_OCL_TYPE (ushort);
+ STRUCT_OCL_TYPE (int);
+ STRUCT_OCL_TYPE (uint);
+ STRUCT_OCL_TYPE (long);
+ STRUCT_OCL_TYPE (ulong);
+ STRUCT_OCL_TYPE (half);
+ STRUCT_OCL_TYPE (float);
+ STRUCT_OCL_TYPE (double);
+ struct type *builtin_bool;
+ struct type *builtin_unsigned_char;
+ struct type *builtin_unsigned_short;
+ struct type *builtin_unsigned_int;
+ struct type *builtin_unsigned_long;
+ struct type *builtin_size_t;
+ struct type *builtin_ptrdiff_t;
+ struct type *builtin_intptr_t;
+ struct type *builtin_uintptr_t;
+ struct type *builtin_void;
+};
+
+static struct gdbarch_data *opencl_type_data;
+
+const struct builtin_opencl_type *
+builtin_opencl_type (struct gdbarch *gdbarch)
+{
+ return gdbarch_data (gdbarch, opencl_type_data);
+}
+
+/* Returns the corresponding OpenCL vector type from the given type code,
+ the length of the element type, the unsigned flag and the amount of
+ elements (N). */
+
+static struct type *
+lookup_opencl_vector_type (struct gdbarch *gdbarch, enum type_code code,
+ unsigned int el_length, unsigned int flag_unsigned,
+ int n)
+{
+ int i;
+ unsigned int length;
+ struct type *type = NULL;
+ struct type **types = (struct type **) builtin_opencl_type (gdbarch);
+
+ /* Check if n describes a valid OpenCL vector size (2, 3, 4, 8, 16). */
+ if (n != 2 && n != 3 && n != 4 && n != 8 && n != 16)
+ error (_("Invalid OpenCL vector size: %d"), n);
+
+ /* Triple vectors have the size of a quad vector. */
+ length = (n == 3) ? el_length * 4 : el_length * n;
+
+ for (i = 0; i < nr_opencl_primitive_types; i++)
+ {
+ LONGEST lowb, highb;
+
+ if (TYPE_CODE (types[i]) == TYPE_CODE_ARRAY && TYPE_VECTOR (types[i])
+ && get_array_bounds (types[i], &lowb, &highb)
+ && TYPE_CODE (TYPE_TARGET_TYPE (types[i])) == code
+ && TYPE_UNSIGNED (TYPE_TARGET_TYPE (types[i])) == flag_unsigned
+ && TYPE_LENGTH (TYPE_TARGET_TYPE (types[i])) == el_length
+ && TYPE_LENGTH (types[i]) == length
+ && highb - lowb + 1 == n)
+ {
+ type = types[i];
+ break;
+ }
+ }
+
+ return type;
+}
+
+/* Returns nonzero if the array ARR contains duplicates within
+ the first N elements. */
+
+static int
+array_has_dups (int *arr, int n)
+{
+ int i, j;
+
+ for (i = 0; i < n; i++)
+ {
+ for (j = i + 1; j < n; j++)
+ {
+ if (arr[i] == arr[j])
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* The OpenCL component access syntax allows to create lvalues referring to
+ selected elements of an original OpenCL vector in arbitrary order. This
+ structure holds the information to describe such lvalues. */
+
+struct lval_closure
+{
+ /* Reference count. */
+ int refc;
+ /* The number of indices. */
+ int n;
+ /* The element indices themselves. */
+ int *indices;
+ /* A pointer to the original value. */
+ struct value *val;
+};
+
+/* Allocates an instance of struct lval_closure. */
+
+static struct lval_closure *
+allocate_lval_closure (int *indices, int n, struct value *val)
+{
+ struct lval_closure *c = XZALLOC (struct lval_closure);
+
+ c->refc = 1;
+ c->n = n;
+ c->indices = XCALLOC (n, int);
+ memcpy (c->indices, indices, n * sizeof (int));
+ value_incref (val); /* Increment the reference counter of the value. */
+ c->val = val;
+
+ return c;
+}
+
+static void
+lval_func_read (struct value *v)
+{
+ struct lval_closure *c = (struct lval_closure *) value_computed_closure (v);
+ struct type *type = check_typedef (value_type (v));
+ struct type *eltype = TYPE_TARGET_TYPE (check_typedef (value_type (c->val)));
+ int offset = value_offset (v);
+ int elsize = TYPE_LENGTH (eltype);
+ int n, i, j = 0;
+ LONGEST lowb = 0;
+ LONGEST highb = 0;
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && !get_array_bounds (type, &lowb, &highb))
+ error (_("Could not determine the vector bounds"));
+
+ /* Assume elsize aligned offset. */
+ gdb_assert (offset % elsize == 0);
+ offset /= elsize;
+ n = offset + highb - lowb + 1;
+ gdb_assert (n <= c->n);
+
+ for (i = offset; i < n; i++)
+ memcpy (value_contents_raw (v) + j++ * elsize,
+ value_contents (c->val) + c->indices[i] * elsize,
+ elsize);
+}
+
+static void
+lval_func_write (struct value *v, struct value *fromval)
+{
+ struct value *mark = value_mark ();
+ struct lval_closure *c = (struct lval_closure *) value_computed_closure (v);
+ struct type *type = check_typedef (value_type (v));
+ struct type *eltype = TYPE_TARGET_TYPE (check_typedef (value_type (c->val)));
+ int offset = value_offset (v);
+ int elsize = TYPE_LENGTH (eltype);
+ int n, i, j = 0;
+ LONGEST lowb = 0;
+ LONGEST highb = 0;
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && !get_array_bounds (type, &lowb, &highb))
+ error (_("Could not determine the vector bounds"));
+
+ /* Assume elsize aligned offset. */
+ gdb_assert (offset % elsize == 0);
+ offset /= elsize;
+ n = offset + highb - lowb + 1;
+
+ /* Since accesses to the fourth component of a triple vector is undefined we
+ just skip writes to the fourth element. Imagine something like this:
+ int3 i3 = (int3)(0, 1, 2);
+ i3.hi.hi = 5;
+ In this case n would be 4 (offset=12/4 + 1) while c->n would be 3. */
+ if (n > c->n)
+ n = c->n;
+
+ for (i = offset; i < n; i++)
+ {
+ struct value *from_elm_val = allocate_value (eltype);
+ struct value *to_elm_val = value_subscript (c->val, c->indices[i]);
+
+ memcpy (value_contents_writeable (from_elm_val),
+ value_contents (fromval) + j++ * elsize,
+ elsize);
+ value_assign (to_elm_val, from_elm_val);
+ }
+
+ value_free_to_mark (mark);
+}
+
+/* Return nonzero if all bits in V within OFFSET and LENGTH are valid. */
+
+static int
+lval_func_check_validity (const struct value *v, int offset, int length)
+{
+ struct lval_closure *c = (struct lval_closure *) value_computed_closure (v);
+ /* Size of the target type in bits. */
+ int elsize =
+ TYPE_LENGTH (TYPE_TARGET_TYPE (check_typedef (value_type (c->val)))) * 8;
+ int startrest = offset % elsize;
+ int start = offset / elsize;
+ int endrest = (offset + length) % elsize;
+ int end = (offset + length) / elsize;
+ int i;
+
+ if (endrest)
+ end++;
+
+ if (end > c->n)
+ return 0;
+
+ for (i = start; i < end; i++)
+ {
+ int startoffset = (i == start) ? startrest : 0;
+ int length = (i == end) ? endrest : elsize;
+
+ if (!value_bits_valid (c->val, c->indices[i] * elsize + startoffset,
+ length))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Return nonzero if any bit in V is valid. */
+
+static int
+lval_func_check_any_valid (const struct value *v)
+{
+ struct lval_closure *c = (struct lval_closure *) value_computed_closure (v);
+ /* Size of the target type in bits. */
+ int elsize =
+ TYPE_LENGTH (TYPE_TARGET_TYPE (check_typedef (value_type (c->val)))) * 8;
+ int i;
+
+ for (i = 0; i < c->n; i++)
+ if (value_bits_valid (c->val, c->indices[i] * elsize, elsize))
+ return 1;
+
+ return 0;
+}
+
+static void *
+lval_func_copy_closure (const struct value *v)
+{
+ struct lval_closure *c = (struct lval_closure *) value_computed_closure (v);
+
+ ++c->refc;
+
+ return c;
+}
+
+static void
+lval_func_free_closure (struct value *v)
+{
+ struct lval_closure *c = (struct lval_closure *) value_computed_closure (v);
+
+ --c->refc;
+
+ if (c->refc == 0)
+ {
+ xfree (c->indices);
+ xfree (c);
+ value_free (c->val); /* Decrement the reference counter of the value. */
+ }
+}
+
+static struct lval_funcs opencl_value_funcs =
+ {
+ lval_func_read,
+ lval_func_write,
+ lval_func_check_validity,
+ lval_func_check_any_valid,
+ lval_func_copy_closure,
+ lval_func_free_closure
+ };
+
+/* Creates a sub-vector from VAL. The elements are selected by the indices of
+ an array with the length of N. Supported values for NOSIDE are
+ EVAL_NORMAL and EVAL_AVOID_SIDE_EFFECTS. */
+
+static struct value *
+create_value (struct gdbarch *gdbarch, struct value *val, enum noside noside,
+ int *indices, int n)
+{
+ struct type *type = check_typedef (value_type (val));
+ struct type *elm_type = TYPE_TARGET_TYPE (type);
+ struct value *ret;
+
+ /* Check if a single component of a vector is requested which means
+ the resulting type is a (primitive) scalar type. */
+ if (n == 1)
+ {
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ ret = value_zero (elm_type, not_lval);
+ else
+ ret = value_subscript (val, indices[0]);
+ }
+ else
+ {
+ /* Multiple components of the vector are requested which means the
+ resulting type is a vector as well. */
+ struct type *dst_type =
+ lookup_opencl_vector_type (gdbarch, TYPE_CODE (elm_type),
+ TYPE_LENGTH (elm_type),
+ TYPE_UNSIGNED (elm_type), n);
+
+ if (dst_type == NULL)
+ dst_type = init_vector_type (elm_type, n);
+
+ make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type), dst_type, NULL);
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ ret = allocate_value (dst_type);
+ else
+ {
+ /* Check whether to create a lvalue or not. */
+ if (VALUE_LVAL (val) != not_lval && !array_has_dups (indices, n))
+ {
+ struct lval_closure *c = allocate_lval_closure (indices, n, val);
+ ret = allocate_computed_value (dst_type, &opencl_value_funcs, c);
+ }
+ else
+ {
+ int i;
+
+ ret = allocate_value (dst_type);
+
+ /* Copy src val contents into the destination value. */
+ for (i = 0; i < n; i++)
+ memcpy (value_contents_writeable (ret)
+ + (i * TYPE_LENGTH (elm_type)),
+ value_contents (val)
+ + (indices[i] * TYPE_LENGTH (elm_type)),
+ TYPE_LENGTH (elm_type));
+ }
+ }
+ }
+ return ret;
+}
+
+/* OpenCL vector component access. */
+
+static struct value *
+opencl_component_ref (struct expression *exp, struct value *val, char *comps,
+ enum noside noside)
+{
+ LONGEST lowb, highb;
+ int src_len;
+ struct value *v;
+ int indices[16], i;
+ int dst_len;
+
+ if (!get_array_bounds (check_typedef (value_type (val)), &lowb, &highb))
+ error (_("Could not determine the vector bounds"));
+
+ src_len = highb - lowb + 1;
+
+ /* Throw an error if the amount of array elements does not fit a
+ valid OpenCL vector size (2, 3, 4, 8, 16). */
+ if (src_len != 2 && src_len != 3 && src_len != 4 && src_len != 8
+ && src_len != 16)
+ error (_("Invalid OpenCL vector size"));
+
+ if (strcmp (comps, "lo") == 0 )
+ {
+ dst_len = (src_len == 3) ? 2 : src_len / 2;
+
+ for (i = 0; i < dst_len; i++)
+ indices[i] = i;
+ }
+ else if (strcmp (comps, "hi") == 0)
+ {
+ dst_len = (src_len == 3) ? 2 : src_len / 2;
+
+ for (i = 0; i < dst_len; i++)
+ indices[i] = dst_len + i;
+ }
+ else if (strcmp (comps, "even") == 0)
+ {
+ dst_len = (src_len == 3) ? 2 : src_len / 2;
+
+ for (i = 0; i < dst_len; i++)
+ indices[i] = i*2;
+ }
+ else if (strcmp (comps, "odd") == 0)
+ {
+ dst_len = (src_len == 3) ? 2 : src_len / 2;
+
+ for (i = 0; i < dst_len; i++)
+ indices[i] = i*2+1;
+ }
+ else if (strncasecmp (comps, "s", 1) == 0)
+ {
+#define HEXCHAR_TO_INT(C) ((C >= '0' && C <= '9') ? \
+ C-'0' : ((C >= 'A' && C <= 'F') ? \
+ C-'A'+10 : ((C >= 'a' && C <= 'f') ? \
+ C-'a'+10 : -1)))
+
+ dst_len = strlen (comps);
+ /* Skip the s/S-prefix. */
+ dst_len--;
+
+ for (i = 0; i < dst_len; i++)
+ {
+ indices[i] = HEXCHAR_TO_INT(comps[i+1]);
+ /* Check if the requested component is invalid or exceeds
+ the vector. */
+ if (indices[i] < 0 || indices[i] >= src_len)
+ error (_("Invalid OpenCL vector component accessor %s"), comps);
+ }
+ }
+ else
+ {
+ dst_len = strlen (comps);
+
+ for (i = 0; i < dst_len; i++)
+ {
+ /* x, y, z, w */
+ switch (comps[i])
+ {
+ case 'x':
+ indices[i] = 0;
+ break;
+ case 'y':
+ indices[i] = 1;
+ break;
+ case 'z':
+ if (src_len < 3)
+ error (_("Invalid OpenCL vector component accessor %s"), comps);
+ indices[i] = 2;
+ break;
+ case 'w':
+ if (src_len < 4)
+ error (_("Invalid OpenCL vector component accessor %s"), comps);
+ indices[i] = 3;
+ break;
+ default:
+ error (_("Invalid OpenCL vector component accessor %s"), comps);
+ break;
+ }
+ }
+ }
+
+ /* Throw an error if the amount of requested components does not
+ result in a valid length (1, 2, 3, 4, 8, 16). */
+ if (dst_len != 1 && dst_len != 2 && dst_len != 3 && dst_len != 4
+ && dst_len != 8 && dst_len != 16)
+ error (_("Invalid OpenCL vector component accessor %s"), comps);
+
+ v = create_value (exp->gdbarch, val, noside, indices, dst_len);
+
+ return v;
+}
+
+/* Perform the unary logical not (!) operation. */
+
+static struct value *
+opencl_logical_not (struct expression *exp, struct value *arg)
+{
+ struct type *type = check_typedef (value_type (arg));
+ struct type *rettype;
+ struct value *ret;
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type))
+ {
+ struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
+ LONGEST lowb, highb;
+ int i;
+
+ if (!get_array_bounds (type, &lowb, &highb))
+ error (_("Could not determine the vector bounds"));
+
+ /* Determine the resulting type of the operation and allocate the
+ value. */
+ rettype = lookup_opencl_vector_type (exp->gdbarch, TYPE_CODE_INT,
+ TYPE_LENGTH (eltype), 0,
+ highb - lowb + 1);
+ ret = allocate_value (rettype);
+
+ for (i = 0; i < highb - lowb + 1; i++)
+ {
+ /* For vector types, the unary operator shall return a 0 if the
+ value of its operand compares unequal to 0, and -1 (i.e. all bits
+ set) if the value of its operand compares equal to 0. */
+ int tmp = value_logical_not (value_subscript (arg, i)) ? -1 : 0;
+ memset (value_contents_writeable (ret) + i * TYPE_LENGTH (eltype),
+ tmp, TYPE_LENGTH (eltype));
+ }
+ }
+ else
+ {
+ rettype = language_bool_type (exp->language_defn, exp->gdbarch);
+ ret = value_from_longest (rettype, value_logical_not (arg));
+ }
+
+ return ret;
+}
+
+/* Perform a relational operation on two scalar operands. */
+
+static int
+scalar_relop (struct value *val1, struct value *val2, enum exp_opcode op)
+{
+ int ret;
+
+ switch (op)
+ {
+ case BINOP_EQUAL:
+ ret = value_equal (val1, val2);
+ break;
+ case BINOP_NOTEQUAL:
+ ret = !value_equal (val1, val2);
+ break;
+ case BINOP_LESS:
+ ret = value_less (val1, val2);
+ break;
+ case BINOP_GTR:
+ ret = value_less (val2, val1);
+ break;
+ case BINOP_GEQ:
+ ret = value_less (val2, val1) || value_equal (val1, val2);
+ break;
+ case BINOP_LEQ:
+ ret = value_less (val1, val2) || value_equal (val1, val2);
+ break;
+ case BINOP_LOGICAL_AND:
+ ret = !value_logical_not (val1) && !value_logical_not (val2);
+ break;
+ case BINOP_LOGICAL_OR:
+ ret = !value_logical_not (val1) || !value_logical_not (val2);
+ break;
+ default:
+ error (_("Attempt to perform an unsupported operation"));
+ break;
+ }
+ return ret;
+}
+
+/* Perform a relational operation on two vector operands. */
+
+static struct value *
+vector_relop (struct expression *exp, struct value *val1, struct value *val2,
+ enum exp_opcode op)
+{
+ struct value *ret;
+ struct type *type1, *type2, *eltype1, *eltype2, *rettype;
+ int t1_is_vec, t2_is_vec, i;
+ LONGEST lowb1, lowb2, highb1, highb2;
+
+ type1 = check_typedef (value_type (val1));
+ type2 = check_typedef (value_type (val2));
+
+ t1_is_vec = (TYPE_CODE (type1) == TYPE_CODE_ARRAY && TYPE_VECTOR (type1));
+ t2_is_vec = (TYPE_CODE (type2) == TYPE_CODE_ARRAY && TYPE_VECTOR (type2));
+
+ if (!t1_is_vec || !t2_is_vec)
+ error (_("Vector operations are not supported on scalar types"));
+
+ eltype1 = check_typedef (TYPE_TARGET_TYPE (type1));
+ eltype2 = check_typedef (TYPE_TARGET_TYPE (type2));
+
+ if (!get_array_bounds (type1,&lowb1, &highb1)
+ || !get_array_bounds (type2, &lowb2, &highb2))
+ error (_("Could not determine the vector bounds"));
+
+ /* Check whether the vector types are compatible. */
+ if (TYPE_CODE (eltype1) != TYPE_CODE (eltype2)
+ || TYPE_LENGTH (eltype1) != TYPE_LENGTH (eltype2)
+ || TYPE_UNSIGNED (eltype1) != TYPE_UNSIGNED (eltype2)
+ || lowb1 != lowb2 || highb1 != highb2)
+ error (_("Cannot perform operation on vectors with different types"));
+
+ /* Determine the resulting type of the operation and allocate the value. */
+ rettype = lookup_opencl_vector_type (exp->gdbarch, TYPE_CODE_INT,
+ TYPE_LENGTH (eltype1), 0,
+ highb1 - lowb1 + 1);
+ ret = allocate_value (rettype);
+
+ for (i = 0; i < highb1 - lowb1 + 1; i++)
+ {
+ /* For vector types, the relational, equality and logical operators shall
+ return 0 if the specified relation is false and -1 (i.e. all bits set)
+ if the specified relation is true. */
+ int tmp = scalar_relop (value_subscript (val1, i),
+ value_subscript (val2, i), op) ? -1 : 0;
+ memset (value_contents_writeable (ret) + i * TYPE_LENGTH (eltype1),
+ tmp, TYPE_LENGTH (eltype1));
+ }
+
+ return ret;
+}
+
+/* Perform a relational operation on two operands. */
+
+static struct value *
+opencl_relop (struct expression *exp, struct value *arg1, struct value *arg2,
+ enum exp_opcode op)
+{
+ struct value *val;
+ struct type *type1 = check_typedef (value_type (arg1));
+ struct type *type2 = check_typedef (value_type (arg2));
+ int t1_is_vec = (TYPE_CODE (type1) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type1));
+ int t2_is_vec = (TYPE_CODE (type2) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type2));
+
+ if (!t1_is_vec && !t2_is_vec)
+ {
+ int tmp = scalar_relop (arg1, arg2, op);
+ struct type *type =
+ language_bool_type (exp->language_defn, exp->gdbarch);
+
+ val = value_from_longest (type, tmp);
+ }
+ else if (t1_is_vec && t2_is_vec)
+ {
+ val = vector_relop (exp, arg1, arg2, op);
+ }
+ else
+ {
+ /* Widen the scalar operand to a vector. */
+ struct value **v = t1_is_vec ? &arg2 : &arg1;
+ struct type *t = t1_is_vec ? type2 : type1;
+
+ if (TYPE_CODE (t) != TYPE_CODE_FLT && !is_integral_type (t))
+ error (_("Argument to operation not a number or boolean."));
+
+ *v = value_cast (t1_is_vec ? type1 : type2, *v);
+ val = vector_relop (exp, arg1, arg2, op);
+ }
+
+ return val;
+}
+
+/* Expression evaluator for the OpenCL. Most operations are delegated to
+ evaluate_subexp_standard; see that function for a description of the
+ arguments. */
+
+static struct value *
+evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
+ int *pos, enum noside noside)
+{
+ enum exp_opcode op = exp->elts[*pos].opcode;
+ struct value *arg1 = NULL;
+ struct value *arg2 = NULL;
+ struct type *type1, *type2;
+
+ switch (op)
+ {
+ /* Handle binary relational and equality operators that are either not
+ or differently defined for GNU vectors. */
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_GEQ:
+ case BINOP_LEQ:
+ (*pos)++;
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
+
+ if (noside == EVAL_SKIP)
+ return value_from_longest (builtin_type (exp->gdbarch)->
+ builtin_int, 1);
+
+ return opencl_relop (exp, arg1, arg2, op);
+
+ /* Handle the logical unary operator not(!). */
+ case UNOP_LOGICAL_NOT:
+ (*pos)++;
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ if (noside == EVAL_SKIP)
+ return value_from_longest (builtin_type (exp->gdbarch)->
+ builtin_int, 1);
+
+ return opencl_logical_not (exp, arg1);
+
+ /* Handle the logical operator and(&&) and or(||). */
+ case BINOP_LOGICAL_AND:
+ case BINOP_LOGICAL_OR:
+ (*pos)++;
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ if (noside == EVAL_SKIP)
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ return value_from_longest (builtin_type (exp->gdbarch)->
+ builtin_int, 1);
+ }
+ else
+ {
+ /* For scalar operations we need to avoid evaluating operands
+ unecessarily. However, for vector operations we always need to
+ evaluate both operands. Unfortunately we only know which of the
+ two cases apply after we know the type of the second operand.
+ Therefore we evaluate it once using EVAL_AVOID_SIDE_EFFECTS. */
+ int oldpos = *pos;
+
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ *pos = oldpos;
+ type1 = check_typedef (value_type (arg1));
+ type2 = check_typedef (value_type (arg2));
+
+ if ((TYPE_CODE (type1) == TYPE_CODE_ARRAY && TYPE_VECTOR (type1))
+ || (TYPE_CODE (type2) == TYPE_CODE_ARRAY && TYPE_VECTOR (type2)))
+ {
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+ return opencl_relop (exp, arg1, arg2, op);
+ }
+ else
+ {
+ /* For scalar built-in types, only evaluate the right
+ hand operand if the left hand operand compares
+ unequal(&&)/equal(||) to 0. */
+ int res;
+ int tmp = value_logical_not (arg1);
+
+ if (op == BINOP_LOGICAL_OR)
+ tmp = !tmp;
+
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos,
+ tmp ? EVAL_SKIP : noside);
+ type1 = language_bool_type (exp->language_defn, exp->gdbarch);
+
+ if (op == BINOP_LOGICAL_AND)
+ res = !tmp && !value_logical_not (arg2);
+ else /* BINOP_LOGICAL_OR */
+ res = tmp || !value_logical_not (arg2);
+
+ return value_from_longest (type1, res);
+ }
+ }
+
+ /* Handle the ternary selection operator. */
+ case TERNOP_COND:
+ (*pos)++;
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ type1 = check_typedef (value_type (arg1));
+ if (TYPE_CODE (type1) == TYPE_CODE_ARRAY && TYPE_VECTOR (type1))
+ {
+ struct value *arg3, *tmp, *ret;
+ struct type *eltype2, *type3, *eltype3;
+ int t2_is_vec, t3_is_vec, i;
+ LONGEST lowb1, lowb2, lowb3, highb1, highb2, highb3;
+
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ arg3 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ type2 = check_typedef (value_type (arg2));
+ type3 = check_typedef (value_type (arg3));
+ t2_is_vec
+ = TYPE_CODE (type2) == TYPE_CODE_ARRAY && TYPE_VECTOR (type2);
+ t3_is_vec
+ = TYPE_CODE (type3) == TYPE_CODE_ARRAY && TYPE_VECTOR (type3);
+
+ /* Widen the scalar operand to a vector if necessary. */
+ if (t2_is_vec || !t3_is_vec)
+ {
+ arg3 = value_cast (type2, arg3);
+ type3 = value_type (arg3);
+ }
+ else if (!t2_is_vec || t3_is_vec)
+ {
+ arg2 = value_cast (type3, arg2);
+ type2 = value_type (arg2);
+ }
+ else if (!t2_is_vec || !t3_is_vec)
+ {
+ /* Throw an error if arg2 or arg3 aren't vectors. */
+ error (_("\
+Cannot perform conditional operation on incompatible types"));
+ }
+
+ eltype2 = check_typedef (TYPE_TARGET_TYPE (type2));
+ eltype3 = check_typedef (TYPE_TARGET_TYPE (type3));
+
+ if (!get_array_bounds (type1, &lowb1, &highb1)
+ || !get_array_bounds (type2, &lowb2, &highb2)
+ || !get_array_bounds (type3, &lowb3, &highb3))
+ error (_("Could not determine the vector bounds"));
+
+ /* Throw an error if the types of arg2 or arg3 are incompatible. */
+ if (TYPE_CODE (eltype2) != TYPE_CODE (eltype3)
+ || TYPE_LENGTH (eltype2) != TYPE_LENGTH (eltype3)
+ || TYPE_UNSIGNED (eltype2) != TYPE_UNSIGNED (eltype3)
+ || lowb2 != lowb3 || highb2 != highb3)
+ error (_("\
+Cannot perform operation on vectors with different types"));
+
+ /* Throw an error if the sizes of arg1 and arg2/arg3 differ. */
+ if (lowb1 != lowb2 || lowb1 != lowb3
+ || highb1 != highb2 || highb1 != highb3)
+ error (_("\
+Cannot perform conditional operation on vectors with different sizes"));
+
+ ret = allocate_value (type2);
+
+ for (i = 0; i < highb1 - lowb1 + 1; i++)
+ {
+ tmp = value_logical_not (value_subscript (arg1, i)) ?
+ value_subscript (arg3, i) : value_subscript (arg2, i);
+ memcpy (value_contents_writeable (ret) +
+ i * TYPE_LENGTH (eltype2), value_contents_all (tmp),
+ TYPE_LENGTH (eltype2));
+ }
+
+ return ret;
+ }
+ else
+ {
+ if (value_logical_not (arg1))
+ {
+ /* Skip the second operand. */
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+
+ return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ }
+ else
+ {
+ /* Skip the third operand. */
+ arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+
+ return arg2;
+ }
+ }
+
+ /* Handle STRUCTOP_STRUCT to allow component access on OpenCL vectors. */
+ case STRUCTOP_STRUCT:
+ {
+ int pc = (*pos)++;
+ int tem = longest_to_int (exp->elts[pc + 1].longconst);
+
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ type1 = check_typedef (value_type (arg1));
+
+ if (noside == EVAL_SKIP)
+ {
+ return value_from_longest (builtin_type (exp->gdbarch)->
+ builtin_int, 1);
+ }
+ else if (TYPE_CODE (type1) == TYPE_CODE_ARRAY && TYPE_VECTOR (type1))
+ {
+ return opencl_component_ref (exp, arg1, &exp->elts[pc + 2].string,
+ noside);
+ }
+ else
+ {
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return
+ value_zero (lookup_struct_elt_type
+ (value_type (arg1),&exp->elts[pc + 2].string, 0),
+ lval_memory);
+ else
+ return value_struct_elt (&arg1, NULL,
+ &exp->elts[pc + 2].string, NULL,
+ "structure");
+ }
+ }
+ default:
+ break;
+ }
+
+ return evaluate_subexp_c (expect_type, exp, pos, noside);
+}
+
+void
+opencl_language_arch_info (struct gdbarch *gdbarch,
+ struct language_arch_info *lai)
+{
+ const struct builtin_opencl_type *builtin = builtin_opencl_type (gdbarch);
+
+ lai->string_char_type = builtin->builtin_char;
+ lai->primitive_type_vector
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, nr_opencl_primitive_types + 1,
+ struct type *);
+
+/* This macro fills the primitive_type_vector from a given type. */
+#define FILL_TYPE_VECTOR(LAI, TYPE)\
+ LAI->primitive_type_vector [opencl_primitive_type_##TYPE]\
+ = builtin->builtin_##TYPE;\
+ LAI->primitive_type_vector [opencl_primitive_type_##TYPE##2]\
+ = builtin->builtin_##TYPE##2;\
+ LAI->primitive_type_vector [opencl_primitive_type_##TYPE##3]\
+ = builtin->builtin_##TYPE##3;\
+ LAI->primitive_type_vector [opencl_primitive_type_##TYPE##4]\
+ = builtin->builtin_##TYPE##4;\
+ LAI->primitive_type_vector [opencl_primitive_type_##TYPE##8]\
+ = builtin->builtin_##TYPE##8;\
+ LAI->primitive_type_vector [opencl_primitive_type_##TYPE##16]\
+ = builtin->builtin_##TYPE##16
+
+ FILL_TYPE_VECTOR (lai, char);
+ FILL_TYPE_VECTOR (lai, uchar);
+ FILL_TYPE_VECTOR (lai, short);
+ FILL_TYPE_VECTOR (lai, ushort);
+ FILL_TYPE_VECTOR (lai, int);
+ FILL_TYPE_VECTOR (lai, uint);
+ FILL_TYPE_VECTOR (lai, long);
+ FILL_TYPE_VECTOR (lai, ulong);
+ FILL_TYPE_VECTOR (lai, half);
+ FILL_TYPE_VECTOR (lai, float);
+ FILL_TYPE_VECTOR (lai, double);
+ lai->primitive_type_vector [opencl_primitive_type_bool]
+ = builtin->builtin_bool;
+ lai->primitive_type_vector [opencl_primitive_type_unsigned_char]
+ = builtin->builtin_unsigned_char;
+ lai->primitive_type_vector [opencl_primitive_type_unsigned_short]
+ = builtin->builtin_unsigned_short;
+ lai->primitive_type_vector [opencl_primitive_type_unsigned_int]
+ = builtin->builtin_unsigned_int;
+ lai->primitive_type_vector [opencl_primitive_type_unsigned_long]
+ = builtin->builtin_unsigned_long;
+ lai->primitive_type_vector [opencl_primitive_type_half]
+ = builtin->builtin_half;
+ lai->primitive_type_vector [opencl_primitive_type_size_t]
+ = builtin->builtin_size_t;
+ lai->primitive_type_vector [opencl_primitive_type_ptrdiff_t]
+ = builtin->builtin_ptrdiff_t;
+ lai->primitive_type_vector [opencl_primitive_type_intptr_t]
+ = builtin->builtin_intptr_t;
+ lai->primitive_type_vector [opencl_primitive_type_uintptr_t]
+ = builtin->builtin_uintptr_t;
+ lai->primitive_type_vector [opencl_primitive_type_void]
+ = builtin->builtin_void;
+
+ /* Specifies the return type of logical and relational operations. */
+ lai->bool_type_symbol = "int";
+ lai->bool_type_default = builtin->builtin_int;
+}
+
+const struct exp_descriptor exp_descriptor_opencl =
+{
+ print_subexp_standard,
+ operator_length_standard,
+ operator_check_standard,
+ op_name_standard,
+ dump_subexp_body_standard,
+ evaluate_subexp_opencl
+};
+
+const struct language_defn opencl_language_defn =
+{
+ "opencl", /* Language name */
+ language_opencl,
+ range_check_off,
+ type_check_off,
+ case_sensitive_on,
+ array_row_major,
+ macro_expansion_c,
+ &exp_descriptor_opencl,
+ c_parse,
+ c_error,
+ null_post_parser,
+ c_printchar, /* Print a character constant */
+ c_printstr, /* Function to print string constant */
+ c_emit_char, /* Print a single char */
+ c_print_type, /* Print a type using appropriate syntax */
+ c_print_typedef, /* Print a typedef using appropriate syntax */
+ c_val_print, /* Print a value using appropriate syntax */
+ c_value_print, /* Print a top-level value */
+ NULL, /* Language specific skip_trampoline */
+ NULL, /* name_of_this */
+ basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ basic_lookup_transparent_type,/* lookup_transparent_type */
+ NULL, /* Language specific symbol demangler */
+ NULL, /* Language specific class_name_from_physname */
+ c_op_print_tab, /* expression operators for printing */
+ 1, /* c-style arrays */
+ 0, /* String lower bound */
+ default_word_break_characters,
+ default_make_symbol_completion_list,
+ opencl_language_arch_info,
+ default_print_array_index,
+ default_pass_by_reference,
+ c_get_string,
+ LANG_MAGIC
+};
+
+static void *
+build_opencl_types (struct gdbarch *gdbarch)
+{
+ struct builtin_opencl_type *builtin_opencl_type
+ = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct builtin_opencl_type);
+
+/* Helper macro to create strings. */
+#define STRINGIFY(S) #S
+/* This macro allocates and assigns the type struct pointers
+ for the vector types. */
+#define BUILD_OCL_VTYPES(TYPE)\
+ builtin_opencl_type->builtin_##TYPE##2\
+ = init_vector_type (builtin_opencl_type->builtin_##TYPE, 2);\
+ TYPE_NAME (builtin_opencl_type->builtin_##TYPE##2) = STRINGIFY(TYPE ## 2);\
+ builtin_opencl_type->builtin_##TYPE##3\
+ = init_vector_type (builtin_opencl_type->builtin_##TYPE, 3);\
+ TYPE_NAME (builtin_opencl_type->builtin_##TYPE##3) = STRINGIFY(TYPE ## 3);\
+ TYPE_LENGTH (builtin_opencl_type->builtin_##TYPE##3)\
+ = 4 * TYPE_LENGTH (builtin_opencl_type->builtin_##TYPE);\
+ builtin_opencl_type->builtin_##TYPE##4\
+ = init_vector_type (builtin_opencl_type->builtin_##TYPE, 4);\
+ TYPE_NAME (builtin_opencl_type->builtin_##TYPE##4) = STRINGIFY(TYPE ## 4);\
+ builtin_opencl_type->builtin_##TYPE##8\
+ = init_vector_type (builtin_opencl_type->builtin_##TYPE, 8);\
+ TYPE_NAME (builtin_opencl_type->builtin_##TYPE##8) = STRINGIFY(TYPE ## 8);\
+ builtin_opencl_type->builtin_##TYPE##16\
+ = init_vector_type (builtin_opencl_type->builtin_##TYPE, 16);\
+ TYPE_NAME (builtin_opencl_type->builtin_##TYPE##16) = STRINGIFY(TYPE ## 16)
+
+ builtin_opencl_type->builtin_char
+ = arch_integer_type (gdbarch, 8, 0, "char");
+ BUILD_OCL_VTYPES (char);
+ builtin_opencl_type->builtin_uchar
+ = arch_integer_type (gdbarch, 8, 1, "uchar");
+ BUILD_OCL_VTYPES (uchar);
+ builtin_opencl_type->builtin_short
+ = arch_integer_type (gdbarch, 16, 0, "short");
+ BUILD_OCL_VTYPES (short);
+ builtin_opencl_type->builtin_ushort
+ = arch_integer_type (gdbarch, 16, 1, "ushort");
+ BUILD_OCL_VTYPES (ushort);
+ builtin_opencl_type->builtin_int
+ = arch_integer_type (gdbarch, 32, 0, "int");
+ BUILD_OCL_VTYPES (int);
+ builtin_opencl_type->builtin_uint
+ = arch_integer_type (gdbarch, 32, 1, "uint");
+ BUILD_OCL_VTYPES (uint);
+ builtin_opencl_type->builtin_long
+ = arch_integer_type (gdbarch, 64, 0, "long");
+ BUILD_OCL_VTYPES (long);
+ builtin_opencl_type->builtin_ulong
+ = arch_integer_type (gdbarch, 64, 1, "ulong");
+ BUILD_OCL_VTYPES (ulong);
+ builtin_opencl_type->builtin_half
+ = arch_float_type (gdbarch, 16, "half", floatformats_ieee_half);
+ BUILD_OCL_VTYPES (half);
+ builtin_opencl_type->builtin_float
+ = arch_float_type (gdbarch, 32, "float", floatformats_ieee_single);
+ BUILD_OCL_VTYPES (float);
+ builtin_opencl_type->builtin_double
+ = arch_float_type (gdbarch, 64, "double", floatformats_ieee_double);
+ BUILD_OCL_VTYPES (double);
+ builtin_opencl_type->builtin_bool
+ = arch_boolean_type (gdbarch, 32, 1, "bool");
+ builtin_opencl_type->builtin_unsigned_char
+ = arch_integer_type (gdbarch, 8, 1, "unsigned char");
+ builtin_opencl_type->builtin_unsigned_short
+ = arch_integer_type (gdbarch, 16, 1, "unsigned short");
+ builtin_opencl_type->builtin_unsigned_int
+ = arch_integer_type (gdbarch, 32, 1, "unsigned int");
+ builtin_opencl_type->builtin_unsigned_long
+ = arch_integer_type (gdbarch, 64, 1, "unsigned long");
+ builtin_opencl_type->builtin_size_t
+ = arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch), 1, "size_t");
+ builtin_opencl_type->builtin_ptrdiff_t
+ = arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch), 0, "ptrdiff_t");
+ builtin_opencl_type->builtin_intptr_t
+ = arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch), 0, "intptr_t");
+ builtin_opencl_type->builtin_uintptr_t
+ = arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch), 1, "uintptr_t");
+ builtin_opencl_type->builtin_void
+ = arch_type (gdbarch, TYPE_CODE_VOID, 1, "void");
+
+ return builtin_opencl_type;
+}
+
+void
+_initialize_opencl_language (void)
+{
+ opencl_type_data = gdbarch_data_register_post_init (build_opencl_types);
+ add_language (&opencl_language_defn);
+}