http://sourceware.org/ml/gdb-patches/2012-11/msg00312.html
authorAndrew Burgess <aburgess@broadcom.com>
Fri, 25 Jan 2013 17:16:43 +0000 (17:16 +0000)
committerAndrew Burgess <aburgess@broadcom.com>
Fri, 25 Jan 2013 17:16:43 +0000 (17:16 +0000)
gdb/ChangeLog
        * valarith.c (value_vector_widen): New function for replicating a
        scalar into a vector.
        (value_binop): Use value_vector_widen to widen scalar to vector
        rather than casting, this better matches gcc C behaviour.
        * valops.c (value_casst): Update logic for casting between vector
        types, and for casting from scalar to vector, try to match gcc C
        behaviour.
        * value.h (value_vector_widen): Declare.
        * opencl-lang.c (opencl_value_cast): New opencl specific casting
        function, handle special case for casting scalar to vector.
        (opencl_relop): Use opencl_value_cast.
        (evaluate_subexp_opencl): Use opencl_value_cast instead of
        value_cast, and handle BINOP_ASSIGN, UNOP_CAST, and UNOP_CAST_TYPE
        in order to use opencl_value_cast.

gdb/testsuite/ChangeLog
        * gdb.base/gnu_vector.c: New variable for use in tests.
        * gdb.base/gnu_vector.exp: Update and extend tests to reflect
        changes in scalar to vector casting and widening.
        * gdb.python/py-type.c: New variables for use in tests.
        * gdb.python/py-type.exp: Update vector related tests to reflect
        changes in scalar to vector casting and widening.

gdb/ChangeLog
gdb/opencl-lang.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/gnu_vector.c
gdb/testsuite/gdb.base/gnu_vector.exp
gdb/testsuite/gdb.python/py-type.c
gdb/testsuite/gdb.python/py-type.exp
gdb/valarith.c
gdb/valops.c
gdb/value.h

index 23f6f074cd1cb5f59a07163005692ac5d8785024..af0d7e6b9a05c2a4294d663a9f068aeb1947b6e4 100644 (file)
@@ -1,3 +1,21 @@
+2013-01-25  Andrew Burgess  <aburgess@broadcom.com>
+           Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * valarith.c (value_vector_widen): New function for replicating a
+       scalar into a vector.
+       (value_binop): Use value_vector_widen to widen scalar to vector
+       rather than casting, this better matches gcc C behaviour.
+       * valops.c (value_casst): Update logic for casting between vector
+       types, and for casting from scalar to vector, try to match gcc C
+       behaviour.
+       * value.h (value_vector_widen): Declare.
+       * opencl-lang.c (opencl_value_cast): New opencl specific casting
+       function, handle special case for casting scalar to vector.
+       (opencl_relop): Use opencl_value_cast.
+       (evaluate_subexp_opencl): Use opencl_value_cast instead of
+       value_cast, and handle BINOP_ASSIGN, UNOP_CAST, and UNOP_CAST_TYPE
+       in order to use opencl_value_cast.
+
 2013-01-25  Yao Qi  <yao@codesourcery.com>
 
        * event-loop.c: Include "queue.h".
index 01e02c823f17d9ccb66eb7c1b172082a3511a139..819a83202aa83aef1596a795162c4d13cd9f02f3 100644 (file)
@@ -683,6 +683,58 @@ vector_relop (struct expression *exp, struct value *val1, struct value *val2,
   return ret;
 }
 
+/* Perform a cast of ARG into TYPE.  There's sadly a lot of duplication in
+   here from valops.c:value_cast, opencl is different only in the
+   behaviour of scalar to vector casting.  As far as possibly we're going
+   to try and delegate back to the standard value_cast function. */
+
+static struct value *
+opencl_value_cast (struct type *type, struct value *arg)
+{
+  if (type != value_type (arg))
+    {
+      /* Casting scalar to vector is a special case for OpenCL, scalar
+        is cast to element type of vector then replicated into each
+        element of the vector.  First though, we need to work out if
+        this is a scalar to vector cast; code lifted from
+        valops.c:value_cast.  */
+      enum type_code code1, code2;
+      struct type *to_type;
+      int scalar;
+
+      to_type = check_typedef (type);
+
+      code1 = TYPE_CODE (to_type);
+      code2 = TYPE_CODE (check_typedef (value_type (arg)));
+
+      if (code2 == TYPE_CODE_REF)
+       code2 = TYPE_CODE (check_typedef (value_type (coerce_ref (arg))));
+
+      scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_BOOL
+               || code2 == TYPE_CODE_CHAR || code2 == TYPE_CODE_FLT
+               || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM
+               || code2 == TYPE_CODE_RANGE);
+
+      if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (to_type) && scalar)
+       {
+         struct type *eltype;
+
+         /* Cast to the element type of the vector here as
+            value_vector_widen will error if the scalar value is
+            truncated by the cast.  To avoid the error, cast (and
+            possibly truncate) here.  */
+         eltype = check_typedef (TYPE_TARGET_TYPE (to_type));
+         arg = value_cast (eltype, arg);
+
+         return value_vector_widen (arg, type);
+       }
+      else
+       /* Standard cast handler.  */
+       arg = value_cast (type, arg);
+    }
+  return arg;
+}
+
 /* Perform a relational operation on two operands.  */
 
 static struct value *
@@ -718,7 +770,7 @@ opencl_relop (struct expression *exp, struct value *arg1, struct value *arg2,
       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);
+      *v = opencl_value_cast (t1_is_vec ? type1 : type2, *v);
       val = vector_relop (exp, arg1, arg2, op);
     }
 
@@ -740,6 +792,46 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
 
   switch (op)
     {
+    /* Handle assignment and cast operators to support OpenCL-style
+       scalar-to-vector widening.  */
+    case BINOP_ASSIGN:
+      (*pos)++;
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      type1 = value_type (arg1);
+      arg2 = evaluate_subexp (type1, exp, pos, noside);
+
+      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+       return arg1;
+
+      if (deprecated_value_modifiable (arg1)
+         && VALUE_LVAL (arg1) != lval_internalvar)
+       arg2 = opencl_value_cast (type1, arg2);
+
+      return value_assign (arg1, arg2);
+
+    case UNOP_CAST:
+      type1 = exp->elts[*pos + 1].type;
+      (*pos) += 2;
+      arg1 = evaluate_subexp (type1, exp, pos, noside);
+
+      if (noside == EVAL_SKIP)
+       return value_from_longest (builtin_type (exp->gdbarch)->
+                                  builtin_int, 1);
+
+      return opencl_value_cast (type1, arg1);
+
+    case UNOP_CAST_TYPE:
+      (*pos)++;
+      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      type1 = value_type (arg1);
+      arg1 = evaluate_subexp (type1, exp, pos, noside);
+
+      if (noside == EVAL_SKIP)
+       return value_from_longest (builtin_type (exp->gdbarch)->
+                                  builtin_int, 1);
+
+      return opencl_value_cast (type1, arg1);
+
     /* Handle binary relational and equality operators that are either not
        or differently defined for GNU vectors.  */
     case BINOP_EQUAL:
@@ -852,12 +944,12 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
          /* Widen the scalar operand to a vector if necessary.  */
          if (t2_is_vec || !t3_is_vec)
            {
-             arg3 = value_cast (type2, arg3);
+             arg3 = opencl_value_cast (type2, arg3);
              type3 = value_type (arg3);
            }
          else if (!t2_is_vec || t3_is_vec)
            {
-             arg2 = value_cast (type3, arg2);
+             arg2 = opencl_value_cast (type3, arg2);
              type2 = value_type (arg2);
            }
          else if (!t2_is_vec || !t3_is_vec)
index 46c7c5713f414ec973fef148f3960891c72d1076..433dd9bc6c57c39fd22eb7812ff0bf0451a8e9ae 100644 (file)
@@ -1,3 +1,12 @@
+2013-01-25  Andrew Burgess  <aburgess@broadcom.com>
+
+       * gdb.base/gnu_vector.c: New variable for use in tests.
+       * gdb.base/gnu_vector.exp: Update and extend tests to reflect
+       changes in scalar to vector casting and widening.
+       * gdb.python/py-type.c: New variables for use in tests.
+       * gdb.python/py-type.exp: Update vector related tests to reflect
+       changes in scalar to vector casting and widening.
+
 2013-01-24  Tiago Stürmer Daitx  <tdaitx@linux.vnet.ibm.com>
 
        * gdb.base/prologue-include.c: New file.
index 76eefed34691c1afce29a2b200d668b8a10a9665..062aadbb2c38cdedac3bf71790bab477ee0a0a5b 100644 (file)
@@ -31,6 +31,7 @@ int ia = 2;
 int ib = 1;
 float fa = 2;
 float fb = 1;
+long long lla __attribute__ ((mode(DI))) = 0x0000000100000001ll;
 char4 c4 = {1, 2, 3, 4};
 int4 i4a = {2, 4, 8, 16};
 int4 i4b = {1, 2, 8, 4};
index 5f5b40f080c334e76172d84b0973f9d7708ac6f9..f65627ba76123f11cd50263c05672897659b9fac 100644 (file)
@@ -82,32 +82,52 @@ gdb_test "print f4a / f4b" "\\\$$decimal = \\{2, 2, 1, 4\\}"
 gdb_test "print +f4a" "\\\$$decimal = \\{2, 4, 8, 16\\}"
 gdb_test "print -f4a" "\\\$$decimal = \\{-2, -4, -8, -16\\}"
 
-# Test scalar to vector widening
-gdb_test "print (int2) 1" "\\\$$decimal = \\{1, 1\\}"
-gdb_test "print (longlong2) 2" "\\\$$decimal = \\{2, 2\\}"
-gdb_test "print (float2) 3" "\\\$$decimal = \\{3, 3\\}"
-gdb_test "print (double2) 4" "\\\$$decimal = \\{4, 4\\}"
-gdb_test "print (char4) 12" "\\\$$decimal = \\{12, 12, 12, 12\\}"
-gdb_test "print (uint4) ia" "\\\$$decimal = \\{2, 2, 2, 2\\}"
-gdb_test "print (int4) -3" "\\\$$decimal = \\{-3, -3, -3, -3\\}"
-gdb_test "print (float4) 4" "\\\$$decimal = \\{4, 4, 4, 4\\}"
-
+# When casting to vector the input type must have the same length as
+# the total length of the vector.
+gdb_test "print (char4) 0x01010101" "\\\$$decimal = \\{1, 1, 1, 1\\}"
+gdb_test "print (char4) ia" "\\\$$decimal = \\{2, 0, 0, 0\\}"
+gdb_test "print (int2) lla" "\\\$$decimal = \\{1, 1\\}"
+
+gdb_test "print (int2) 1" "can only cast scalar to vector of same size"
+gdb_test "print (longlong2) 2" "can only cast scalar to vector of same size"
+gdb_test "print (float2) 3" "can only cast scalar to vector of same size"
+gdb_test "print (double2) 4" "can only cast scalar to vector of same size"
+gdb_test "print (uint4) ia" "can only cast scalar to vector of same size"
+gdb_test "print (int4) -3" "can only cast scalar to vector of same size"
+gdb_test "print (float4) 4" "can only cast scalar to vector of same size"
+
+gdb_test "print i4b = ia" "can only cast scalar to vector of same size"
+gdb_test "print i4a = 3" "can only cast scalar to vector of same size"
+gdb_test "print f4a = fb" "can only cast scalar to vector of same size"
+gdb_test "print f4b = 2" "can only cast scalar to vector of same size"
+
+gdb_test "print c4 + lla" "conversion of scalar to vector involves truncation"
+gdb_test "print i4a + lla" "conversion of scalar to vector involves truncation"
+gdb_test "print lla + c4" "conversion of scalar to vector involves truncation"
+gdb_test "print lla + i4a" "conversion of scalar to vector involves truncation"
+
+gdb_test "print c4 + ib" "\\\$$decimal = \\{2, 3, 4, 5\\}"
 gdb_test "print i4a + ib" "\\\$$decimal = \\{3, 5, 9, 17\\}"
+gdb_test "print i4a + 1" "\\\$$decimal = \\{3, 5, 9, 17\\}"
+gdb_test "print 1 + i4a" "\\\$$decimal = \\{3, 5, 9, 17\\}"
 gdb_test "print fa - f4b" "\\\$$decimal = \\{1, 0, -6, -2\\}"
+gdb_test "print 2 - f4b" "\\\$$decimal = \\{1, 0, -6, -2\\}"
 gdb_test "print f4a * fb" "\\\$$decimal = \\{2, 4, 8, 16\\}"
+gdb_test "print f4a * 1" "\\\$$decimal = \\{2, 4, 8, 16\\}"
 gdb_test "print ia / i4b" "\\\$$decimal = \\{2, 1, 0, 0\\}"
+gdb_test "print 2 / i4b" "\\\$$decimal = \\{2, 1, 0, 0\\}"
 gdb_test "print i4a % ib" "\\\$$decimal = \\{0, 0, 0, 0\\}"
-
+gdb_test "print i4a % 1" "\\\$$decimal = \\{0, 0, 0, 0\\}"
 gdb_test "print ia & i4b" "\\\$$decimal = \\{0, 2, 0, 0\\}"
+gdb_test "print 2 & i4b" "\\\$$decimal = \\{0, 2, 0, 0\\}"
 gdb_test "print i4a | ib" "\\\$$decimal = \\{3, 5, 9, 17\\}"
+gdb_test "print i4a | 1" "\\\$$decimal = \\{3, 5, 9, 17\\}"
 gdb_test "print ia ^ i4b" "\\\$$decimal = \\{3, 0, 10, 6\\}"
+gdb_test "print 2 ^ i4b" "\\\$$decimal = \\{3, 0, 10, 6\\}"
 gdb_test "print i4a << ib" "\\\$$decimal = \\{4, 8, 16, 32\\}"
+gdb_test "print i4a << 1" "\\\$$decimal = \\{4, 8, 16, 32\\}"
 gdb_test "print i4a >> ib" "\\\$$decimal = \\{1, 2, 4, 8\\}"
-
-gdb_test "print i4b = ia" "\\\$$decimal = \\{2, 2, 2, 2\\}"
-gdb_test "print i4a = 3" "\\\$$decimal = \\{3, 3, 3, 3\\}"
-gdb_test "print f4a = fb" "\\\$$decimal = \\{1, 1, 1, 1\\}"
-gdb_test "print f4b = 2" "\\\$$decimal = \\{2, 2, 2, 2\\}"
+gdb_test "print i4a >> 1" "\\\$$decimal = \\{1, 2, 4, 8\\}"
 
 gdb_test "print i4a = \{2, 4, 8, 16\}" "\\\$$decimal = \\{2, 4, 8, 16\\}"
 gdb_test "print i4a <<= ib" "\\\$$decimal = \\{4, 8, 16, 32\\}"
@@ -130,6 +150,10 @@ gdb_test "print i2 + i4a" "Cannot perform operation on vectors with different ty
 gdb_test "print f4a + f2" "Cannot perform operation on vectors with different types"
 gdb_test "print f2 + f4a" "Cannot perform operation on vectors with different types"
 
+gdb_test "print (double2) f2" "Cannot convert between vector values of different sizes"
+gdb_test "print (int4) c4" "Cannot convert between vector values of different sizes"
+gdb_test "print (char4) i4a" "Cannot convert between vector values of different sizes"
+
 # Test ptype on vector types.
 gdb_test "ptype c4" "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
 gdb_test "ptype char4" "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
index 641844efd1b2f8d4fd083688a96e814c94a6350d..03015a8fddacd47c036e44108696e48974347a3b 100644 (file)
@@ -50,6 +50,9 @@ enum E
 { v1, v2, v3
 };
 
+struct s vec_data_1 = {1, 1};
+struct s vec_data_2 = {1, 2};
+
 int
 main ()
 {
index ec59bc8e7529967c2cc178147e8257e146796047..16b2de21badd0a26655c4851cd91a1f9aec44f8f 100644 (file)
@@ -118,7 +118,7 @@ proc test_fields {lang} {
     # Test gdb.Type.array.
     gdb_test "python print (ar\[0\].cast(ar\[0\].type.array(1)))" \
         ".1, 2." "cast to array with one argument"
-    gdb_test "python print (ar\[0\].cast(ar\[0\].type.array(0, 1)))" \
+    gdb_test "python print ar\[0\].cast(ar\[0\].type.array(0, 1))" \
         ".1, 2." "cast to array with two arguments"
 
     gdb_test "python print (ar\[0\].type == ar\[0\].type)" "True"
@@ -126,16 +126,19 @@ proc test_fields {lang} {
     # Test gdb.Type.vector.
     # Note: vectors cast differently than arrays.  Here ar[0] is replicated
     # for the size of the vector.
-    gdb_py_test_silent_cmd \
-        "python vec1 = ar\[0\].cast(ar\[0\].type.vector(1))" "set vec1" 1
-    gdb_test "python print (vec1)" ".1, 1." "cast to vector with one argument"
-    gdb_py_test_silent_cmd \
-        "python vec2 = ar\[0\].cast(ar\[0\].type.vector(0, 1))" "set vec2" 1
-    gdb_test "python print (vec2)" ".1, 1." "cast to vector with two arguments"
-    gdb_test "python print (vec1 == vec2)" "True"
-    gdb_py_test_silent_cmd \
-        "python vec3 = ar\[1\].cast(ar\[1\].type.vector(1))" "set vec3" 1
-    gdb_test "python print (vec1 == vec3)" "False"
+    gdb_py_test_silent_cmd "print vec_data_1" "print value (vec_data_1)" 1
+    gdb_py_test_silent_cmd "python vec_data_1 = gdb.history (0)" "get value (vec_data_1) from history" 1
+
+    gdb_py_test_silent_cmd "print vec_data_2" "print value (vec_data_2)" 1
+    gdb_py_test_silent_cmd "python vec_data_2 = gdb.history (0)" "get value (vec_data_2) from history" 1
+
+    gdb_py_test_silent_cmd "python vec1 = vec_data_1.cast(ar\[0\].type.vector(1))" "set vec1" 1
+    gdb_test "python print vec1" ".1, 1." "cast to vector with one argument"
+    gdb_py_test_silent_cmd "python vec2 = vec_data_1.cast(ar\[0\].type.vector(0, 1))" "set vec2" 1
+    gdb_test "python print vec2" ".1, 1." "cast to vector with two arguments"
+    gdb_test "python print vec1 == vec2" "True"
+    gdb_py_test_silent_cmd "python vec3 = vec_data_2.cast(ar\[0\].type.vector(1))" "set vec3" 1
+    gdb_test "python print vec1 == vec3" "False"
   }
 }
 
index 074cf36fba3a1be49e9819870a37459ddff995a8..894a87ac04864443980fc0b61ed956bcf6424ec0 100644 (file)
@@ -1346,6 +1346,49 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   return val;
 }
 
+/* Widen a scalar value SCALAR_VALUE to vector type VECTOR_TYPE by
+   replicating SCALAR_VALUE for each element of the vector.  Only scalar
+   types that can be cast to the type of one element of the vector are
+   acceptable.  The newly created vector value is returned upon success,
+   otherwise an error is thrown.  */
+
+struct value *
+value_vector_widen (struct value *scalar_value, struct type *vector_type)
+{
+  /* Widen the scalar to a vector.  */
+  struct type *eltype, *scalar_type;
+  struct value *val, *elval;
+  LONGEST low_bound, high_bound;
+  int i;
+
+  CHECK_TYPEDEF (vector_type);
+
+  gdb_assert (TYPE_CODE (vector_type) == TYPE_CODE_ARRAY
+             && TYPE_VECTOR (vector_type));
+
+  if (!get_array_bounds (vector_type, &low_bound, &high_bound))
+    error (_("Could not determine the vector bounds"));
+
+  eltype = check_typedef (TYPE_TARGET_TYPE (vector_type));
+  elval = value_cast (eltype, scalar_value);
+
+  scalar_type = check_typedef (value_type (scalar_value));
+
+  /* If we reduced the length of the scalar then check we didn't loose any
+     important bits.  */
+  if (TYPE_LENGTH (eltype) < TYPE_LENGTH (scalar_type)
+      && !value_equal (elval, scalar_value))
+    error (_("conversion of scalar to vector involves truncation"));
+
+  val = allocate_value (vector_type);
+  for (i = 0; i < high_bound - low_bound + 1; i++)
+    /* Duplicate the contents of elval into the destination vector.  */
+    memcpy (value_contents_writeable (val) + (i * TYPE_LENGTH (eltype)),
+           value_contents_all (elval), TYPE_LENGTH (eltype));
+
+  return val;
+}
+
 /* Performs a binary operation on two vector operands by calling scalar_binop
    for each pair of vector components.  */
 
@@ -1425,7 +1468,9 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
          && !is_integral_type (t))
        error (_("Argument to operation not a number or boolean."));
 
-      *v = value_cast (t1_is_vec ? type1 : type2, *v);
+      /* Replicate the scalar value to make a vector value.  */
+      *v = value_vector_widen (*v, t1_is_vec ? type1 : type2);
+
       val = vector_binop (arg1, arg2, op);
     }
 
index e3d36a12ca95ee530f4751eb07f4e2fefb2d8806..b9bc460fa673ac38b57194f76c684e01a2284f3b 100644 (file)
@@ -546,29 +546,13 @@ value_cast (struct type *type, struct value *arg2)
         minus one, instead of biasing the normal case.  */
       return value_from_longest (type, -1);
     }
-  else if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (type) && scalar)
-    {
-      /* Widen the scalar to a vector.  */
-      struct type *eltype;
-      struct value *val;
-      LONGEST low_bound, high_bound;
-      int i;
-
-      if (!get_array_bounds (type, &low_bound, &high_bound))
-       error (_("Could not determine the vector bounds"));
-
-      eltype = check_typedef (TYPE_TARGET_TYPE (type));
-      arg2 = value_cast (eltype, arg2);
-      val = allocate_value (type);
-
-      for (i = 0; i < high_bound - low_bound + 1; i++)
-       {
-         /* Duplicate the contents of arg2 into the destination vector.  */
-         memcpy (value_contents_writeable (val) + (i * TYPE_LENGTH (eltype)),
-                 value_contents_all (arg2), TYPE_LENGTH (eltype));
-       }
-      return val;
-    }
+  else if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
+          && code2 == TYPE_CODE_ARRAY && TYPE_VECTOR (type2)
+          && TYPE_LENGTH (type) != TYPE_LENGTH (type2))
+    error (_("Cannot convert between vector values of different sizes"));
+  else if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (type) && scalar
+          && TYPE_LENGTH (type) != TYPE_LENGTH (type2))
+    error (_("can only cast scalar to vector of same size"));
   else if (code1 == TYPE_CODE_VOID)
     {
       return value_zero (type, not_lval);
index 67f1d048508a41685fcca626ba3fd6285b4bca7f..5825f6eca1ff59acfc5d010ba0348c7ac9b51a09 100644 (file)
@@ -482,6 +482,12 @@ extern void read_value_memory (struct value *val, int embedded_offset,
                               int stack, CORE_ADDR memaddr,
                               gdb_byte *buffer, size_t length);
 
+/* Cast SCALAR_VALUE to the element type of VECTOR_TYPE, then replicate
+   into each element of a new vector value with VECTOR_TYPE.  */
+
+struct value *value_vector_widen (struct value *scalar_value,
+                                 struct type *vector_type);
+
 \f
 
 #include "symtab.h"