public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/7] Update complex number support
@ 2020-03-07 15:22 Tom Tromey
  2020-03-07 15:22 ` [PATCH 1/7] Change how complex types are created Tom Tromey
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Tom Tromey @ 2020-03-07 15:22 UTC (permalink / raw)
  To: gdb-patches

A while back, I happened to notice that gdb did not handle complex
numbers very well.  You could print them but, at least in C, not enter
them; and no complex operations were supported.

This series improves this situation.  Now the C parser can read
complex numbers; some complex operations are supported; casts work
(which is important for "watch -location"); and the output is changed
to be easier to read (IMO).

Tom



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/7] Change how complex types are created
  2020-03-07 15:22 [PATCH 0/7] Update complex number support Tom Tromey
@ 2020-03-07 15:22 ` Tom Tromey
  2020-03-07 15:22 ` [PATCH 2/7] Add accessors for members of complex numbers Tom Tromey
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2020-03-07 15:22 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This patch changes how complex types are created.  init_complex_type
and arch_complex_type are unified, and complex types are reused, by
attaching them to the underlying scalar type.

gdb/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* stabsread.c (rs6000_builtin_type, read_sun_floating_type)
	(read_range_type): Update.
	* mdebugread.c (basic_type): Update.
	* go-lang.c (build_go_types): Use init_complex_type.
	* gdbtypes.h (struct main_type) <complex_type>: New member.
	(init_complex_type): Update.
	(arch_complex_type): Don't declare.
	* gdbtypes.c (init_complex_type): Remove "objfile" parameter.
	Make name if none given.  Use alloc_type_copy.  Look for cached
	complex type.
	(arch_complex_type): Remove.
	(gdbtypes_post_init): Use init_complex_type.
	* f-lang.c (build_fortran_types): Use init_complex_type.
	* dwarf2/read.c (read_base_type): Update.
	* d-lang.c (build_d_types): Use init_complex_type.
	* ctfread.c (read_base_type): Update.
---
 gdb/ChangeLog     | 19 ++++++++++++++++
 gdb/ctfread.c     |  2 +-
 gdb/d-lang.c      |  9 +++-----
 gdb/dwarf2/read.c |  2 +-
 gdb/f-lang.c      |  9 +++-----
 gdb/gdbtypes.c    | 58 +++++++++++++++++++++++++----------------------
 gdb/gdbtypes.h    |  9 ++++----
 gdb/go-lang.c     |  6 ++---
 gdb/mdebugread.c  |  6 ++---
 gdb/stabsread.c   |  8 +++----
 10 files changed, 71 insertions(+), 57 deletions(-)

diff --git a/gdb/ctfread.c b/gdb/ctfread.c
index 241d0b6da94..7784e9d35d6 100644
--- a/gdb/ctfread.c
+++ b/gdb/ctfread.c
@@ -553,7 +553,7 @@ read_base_type (struct ctf_context *ccp, ctf_id_t tid)
 	{
 	  struct type *t
 	    = ctf_init_float_type (of, cet.cte_bits / 2, NULL, name);
-	  type = init_complex_type (of, name, t);
+	  type = init_complex_type (name, t);
 	}
     }
   else
diff --git a/gdb/d-lang.c b/gdb/d-lang.c
index 76d173b61ea..31093966520 100644
--- a/gdb/d-lang.c
+++ b/gdb/d-lang.c
@@ -314,14 +314,11 @@ build_d_types (struct gdbarch *gdbarch)
     = arch_float_type (gdbarch, gdbarch_long_double_bit (gdbarch),
 		       "ireal", gdbarch_long_double_format (gdbarch));
   builtin_d_type->builtin_cfloat
-    = arch_complex_type (gdbarch, "cfloat",
-			 builtin_d_type->builtin_float);
+    = init_complex_type ("cfloat", builtin_d_type->builtin_float);
   builtin_d_type->builtin_cdouble
-    = arch_complex_type (gdbarch, "cdouble",
-			 builtin_d_type->builtin_double);
+    = init_complex_type ("cdouble", builtin_d_type->builtin_double);
   builtin_d_type->builtin_creal
-    = arch_complex_type (gdbarch, "creal",
-			 builtin_d_type->builtin_real);
+    = init_complex_type ("creal", builtin_d_type->builtin_real);
 
   /* Character types.  */
   builtin_d_type->builtin_char
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 3556908cf5a..1b553ca318c 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -16983,7 +16983,7 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
       case DW_ATE_complex_float:
 	type = dwarf2_init_complex_target_type (cu, objfile, bits / 2, name,
 						byte_order);
-	type = init_complex_type (objfile, name, type);
+	type = init_complex_type (name, type);
 	break;
       case DW_ATE_decimal_float:
 	type = init_decfloat_type (objfile, bits, name);
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index e767f52fc21..84d89f0230e 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -741,14 +741,11 @@ build_fortran_types (struct gdbarch *gdbarch)
       = arch_type (gdbarch, TYPE_CODE_ERROR, 128, "real*16");
 
   builtin_f_type->builtin_complex_s8
-    = arch_complex_type (gdbarch, "complex*8",
-			 builtin_f_type->builtin_real);
+    = init_complex_type ("complex*8", builtin_f_type->builtin_real);
   builtin_f_type->builtin_complex_s16
-    = arch_complex_type (gdbarch, "complex*16",
-			 builtin_f_type->builtin_real_s8);
+    = init_complex_type ("complex*16", builtin_f_type->builtin_real_s8);
   builtin_f_type->builtin_complex_s32
-    = arch_complex_type (gdbarch, "complex*32",
-			 builtin_f_type->builtin_real_s16);
+    = init_complex_type ("complex*32", builtin_f_type->builtin_real_s16);
 
   return builtin_f_type;
 }
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index d89df9f7409..f23def1ff71 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3025,19 +3025,40 @@ init_decfloat_type (struct objfile *objfile, int bit, const char *name)
   return t;
 }
 
-/* Allocate a TYPE_CODE_COMPLEX type structure associated with OBJFILE.
-   NAME is the type name.  TARGET_TYPE is the component float type.  */
+/* Allocate a TYPE_CODE_COMPLEX type structure.  NAME is the type
+   name.  TARGET_TYPE is the component type.  */
 
 struct type *
-init_complex_type (struct objfile *objfile,
-		   const char *name, struct type *target_type)
+init_complex_type (const char *name, struct type *target_type)
 {
   struct type *t;
 
-  t = init_type (objfile, TYPE_CODE_COMPLEX,
-		 2 * TYPE_LENGTH (target_type) * TARGET_CHAR_BIT, name);
-  TYPE_TARGET_TYPE (t) = target_type;
-  return t;
+  gdb_assert (TYPE_CODE (target_type) == TYPE_CODE_INT
+	      || TYPE_CODE (target_type) == TYPE_CODE_FLT);
+
+  if (TYPE_MAIN_TYPE (target_type)->flds_bnds.complex_type == nullptr)
+    {
+      if (name == nullptr)
+	{
+	  char *new_name
+	    = (char *) TYPE_ALLOC (target_type,
+				   strlen (TYPE_NAME (target_type))
+				   + strlen ("_Complex ") + 1);
+	  strcpy (new_name, "_Complex ");
+	  strcat (new_name, TYPE_NAME (target_type));
+	  name = new_name;
+	}
+
+      t = alloc_type_copy (target_type);
+      set_type_code (t, TYPE_CODE_COMPLEX);
+      TYPE_LENGTH (t) = 2 * TYPE_LENGTH (target_type);
+      TYPE_NAME (t) = name;
+
+      TYPE_TARGET_TYPE (t) = target_type;
+      TYPE_MAIN_TYPE (target_type)->flds_bnds.complex_type = t;
+    }
+
+  return TYPE_MAIN_TYPE (target_type)->flds_bnds.complex_type;
 }
 
 /* Allocate a TYPE_CODE_PTR type structure associated with OBJFILE.
@@ -5259,21 +5280,6 @@ arch_decfloat_type (struct gdbarch *gdbarch, int bit, const char *name)
   return t;
 }
 
-/* Allocate a TYPE_CODE_COMPLEX type structure associated with GDBARCH.
-   NAME is the type name.  TARGET_TYPE is the component float type.  */
-
-struct type *
-arch_complex_type (struct gdbarch *gdbarch,
-		   const char *name, struct type *target_type)
-{
-  struct type *t;
-
-  t = arch_type (gdbarch, TYPE_CODE_COMPLEX,
-		 2 * TYPE_LENGTH (target_type) * TARGET_CHAR_BIT, name);
-  TYPE_TARGET_TYPE (t) = target_type;
-  return t;
-}
-
 /* Allocate a TYPE_CODE_PTR type structure associated with GDBARCH.
    BIT is the pointer type size in bits.  NAME is the type name.
    TARGET_TYPE is the pointer target type.  Always sets the pointer type's
@@ -5497,11 +5503,9 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
     = arch_float_type (gdbarch, gdbarch_long_double_bit (gdbarch),
 		       "long double", gdbarch_long_double_format (gdbarch));
   builtin_type->builtin_complex
-    = arch_complex_type (gdbarch, "complex",
-			 builtin_type->builtin_float);
+    = init_complex_type ("complex", builtin_type->builtin_float);
   builtin_type->builtin_double_complex
-    = arch_complex_type (gdbarch, "double complex",
-			 builtin_type->builtin_double);
+    = init_complex_type ("double complex", builtin_type->builtin_double);
   builtin_type->builtin_string
     = arch_type (gdbarch, TYPE_CODE_STRING, TARGET_CHAR_BIT, "string");
   builtin_type->builtin_bool
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index cb674dbc1e8..77cc92e419d 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -803,6 +803,10 @@ struct main_type
 
     struct range_bounds *bounds;
 
+    /* If this is a scalar type, then this is its corresponding
+       complex type.  */
+    struct type *complex_type;
+
   } flds_bnds;
 
   /* * Slot to point to additional language-specific fields of this
@@ -1841,8 +1845,7 @@ extern struct type *init_float_type (struct objfile *, int, const char *,
 				     const struct floatformat **,
 				     enum bfd_endian = BFD_ENDIAN_UNKNOWN);
 extern struct type *init_decfloat_type (struct objfile *, int, const char *);
-extern struct type *init_complex_type (struct objfile *, const char *,
-				       struct type *);
+extern struct type *init_complex_type (const char *, struct type *);
 extern struct type *init_pointer_type (struct objfile *, int, const char *,
 				       struct type *);
 
@@ -1858,8 +1861,6 @@ extern struct type *arch_boolean_type (struct gdbarch *, int, int,
 extern struct type *arch_float_type (struct gdbarch *, int, const char *,
 				     const struct floatformat **);
 extern struct type *arch_decfloat_type (struct gdbarch *, int, const char *);
-extern struct type *arch_complex_type (struct gdbarch *, const char *,
-				       struct type *);
 extern struct type *arch_pointer_type (struct gdbarch *, int, const char *,
 				       struct type *);
 
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index 9ad456f72e8..55865aa7f36 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -665,11 +665,9 @@ build_go_types (struct gdbarch *gdbarch)
   builtin_go_type->builtin_float64
     = arch_float_type (gdbarch, 64, "float64", floatformats_ieee_double);
   builtin_go_type->builtin_complex64
-    = arch_complex_type (gdbarch, "complex64",
-			 builtin_go_type->builtin_float32);
+    = init_complex_type ("complex64", builtin_go_type->builtin_float32);
   builtin_go_type->builtin_complex128
-    = arch_complex_type (gdbarch, "complex128",
-			 builtin_go_type->builtin_float64);
+    = init_complex_type ("complex128", builtin_go_type->builtin_float64);
 
   return builtin_go_type;
 }
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index 5d2fbcd2749..7fcd29cb6b1 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -1429,13 +1429,11 @@ basic_type (int bt, struct objfile *objfile)
       break;
 
     case btComplex:
-      tp = init_complex_type (objfile, "complex",
-			      basic_type (btFloat, objfile));
+      tp = init_complex_type ("complex", basic_type (btFloat, objfile));
       break;
 
     case btDComplex:
-      tp = init_complex_type (objfile, "double complex",
-			      basic_type (btFloat, objfile));
+      tp = init_complex_type ("double complex", basic_type (btFloat, objfile));
       break;
 
     case btFixedDec:
diff --git a/gdb/stabsread.c b/gdb/stabsread.c
index a23ebf6b606..068ece2ff53 100644
--- a/gdb/stabsread.c
+++ b/gdb/stabsread.c
@@ -2186,12 +2186,12 @@ rs6000_builtin_type (int typenum, struct objfile *objfile)
       break;
     case 25:
       /* Complex type consisting of two IEEE single precision values.  */
-      rettype = init_complex_type (objfile, "complex",
+      rettype = init_complex_type ("complex",
 				   rs6000_builtin_type (12, objfile));
       break;
     case 26:
       /* Complex type consisting of two IEEE double precision values.  */
-      rettype = init_complex_type (objfile, "double complex",
+      rettype = init_complex_type ("double complex",
 				   rs6000_builtin_type (13, objfile));
       break;
     case 27:
@@ -3805,7 +3805,7 @@ read_sun_floating_type (const char **pp, int typenums[2],
       || details == NF_COMPLEX32)
     {
       rettype = dbx_init_float_type (objfile, nbits / 2);
-      return init_complex_type (objfile, NULL, rettype);
+      return init_complex_type (NULL, rettype);
     }
 
   return dbx_init_float_type (objfile, nbits);
@@ -4099,7 +4099,7 @@ read_range_type (const char **pp, int typenums[2], int type_size,
 	= dbx_init_float_type (objfile, n2 * TARGET_CHAR_BIT);
 
       if (self_subrange)
-	return init_complex_type (objfile, NULL, float_type);
+	return init_complex_type (NULL, float_type);
       else
 	return float_type;
     }
-- 
2.17.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/7] Add accessors for members of complex numbers
  2020-03-07 15:22 [PATCH 0/7] Update complex number support Tom Tromey
  2020-03-07 15:22 ` [PATCH 1/7] Change how complex types are created Tom Tromey
@ 2020-03-07 15:22 ` Tom Tromey
  2020-03-07 15:22 ` [PATCH 3/7] Change how complex types are printed in C Tom Tromey
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2020-03-07 15:22 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This introduces two new functions that make it simpler to access the
components of a complex number.

gdb/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* value.h (value_real_part, value_imaginary_part): Declare.
	* valops.c (value_real_part, value_imaginary_part): New
	functions.
	* value.c (creal_internal_fn, cimag_internal_fn): Use accessors.
---
 gdb/ChangeLog |  7 +++++++
 gdb/valops.c  | 25 +++++++++++++++++++++++++
 gdb/value.c   |  5 ++---
 gdb/value.h   |  8 ++++++++
 4 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/gdb/valops.c b/gdb/valops.c
index d48474665c3..83fd2584b59 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -3877,6 +3877,31 @@ value_literal_complex (struct value *arg1,
   return val;
 }
 
+/* See value.h.  */
+
+struct value *
+value_real_part (struct value *value)
+{
+  struct type *type = check_typedef (value_type (value));
+  struct type *ttype = TYPE_TARGET_TYPE (type);
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_COMPLEX);
+  return value_from_component (value, ttype, 0);
+}
+
+/* See value.h.  */
+
+struct value *
+value_imaginary_part (struct value *value)
+{
+  struct type *type = check_typedef (value_type (value));
+  struct type *ttype = TYPE_TARGET_TYPE (type);
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_COMPLEX);
+  return value_from_component (value, ttype,
+			       TYPE_LENGTH (check_typedef (ttype)));
+}
+
 /* Cast a value into the appropriate complex data type.  */
 
 static struct value *
diff --git a/gdb/value.c b/gdb/value.c
index ceaeb835fa7..f722c272d8b 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -3962,7 +3962,7 @@ creal_internal_fn (struct gdbarch *gdbarch,
   type *ctype = check_typedef (value_type (cval));
   if (TYPE_CODE (ctype) != TYPE_CODE_COMPLEX)
     error (_("expected a complex number"));
-  return value_from_component (cval, TYPE_TARGET_TYPE (ctype), 0);
+  return value_real_part (cval);
 }
 
 /* Implementation of the convenience function $_cimag.  Extracts the
@@ -3981,8 +3981,7 @@ cimag_internal_fn (struct gdbarch *gdbarch,
   type *ctype = check_typedef (value_type (cval));
   if (TYPE_CODE (ctype) != TYPE_CODE_COMPLEX)
     error (_("expected a complex number"));
-  return value_from_component (cval, TYPE_TARGET_TYPE (ctype),
-			       TYPE_LENGTH (TYPE_TARGET_TYPE (ctype)));
+  return value_imaginary_part (cval);
 }
 
 #if GDB_SELF_TEST
diff --git a/gdb/value.h b/gdb/value.h
index df6d80c2a70..27869989fbc 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1148,6 +1148,14 @@ extern struct value *value_slice (struct value *, int, int);
 extern struct value *value_literal_complex (struct value *, struct value *,
 					    struct type *);
 
+/* Return the real part of a complex value.  */
+
+extern struct value *value_real_part (struct value *value);
+
+/* Return the imaginary part of a complex value.  */
+
+extern struct value *value_imaginary_part (struct value *value);
+
 extern struct value *find_function_in_inferior (const char *,
 						struct objfile **);
 
-- 
2.17.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/7] Change how complex types are printed in C
  2020-03-07 15:22 [PATCH 0/7] Update complex number support Tom Tromey
  2020-03-07 15:22 ` [PATCH 1/7] Change how complex types are created Tom Tromey
  2020-03-07 15:22 ` [PATCH 2/7] Add accessors for members of complex numbers Tom Tromey
@ 2020-03-07 15:22 ` Tom Tromey
  2020-03-07 15:22 ` [PATCH 4/7] Change the C parser to allow complex constants Tom Tromey
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2020-03-07 15:22 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

GCC accepts the "i" suffix for complex numbers.  I think this is nicer
to read than the current output, so this patch changes the C code to
print complex numbers this way.

gdb/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* c-valprint.c (c_decorations): Change complex suffix to "i".

gdb/testsuite/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* gdb.compile/compile.exp: Update.
	* gdb.compile/compile-cplus.exp: Update.
	* gdb.base/varargs.exp: Update.
	* gdb.base/floatn.exp: Update.
	* gdb.base/endianity.exp: Update.
	* gdb.base/callfuncs.exp (do_function_calls): Update.
	* gdb.base/funcargs.exp (complex_args, complex_integral_args)
	(complex_float_integral_args): Update.
	* gdb.base/complex.exp: Update.
	* gdb.base/complex-parts.exp: Update.
---
 gdb/ChangeLog                               |  4 ++++
 gdb/c-valprint.c                            |  2 +-
 gdb/testsuite/ChangeLog                     | 13 +++++++++++++
 gdb/testsuite/gdb.base/callfuncs.exp        |  6 +++---
 gdb/testsuite/gdb.base/complex-parts.exp    |  6 +++---
 gdb/testsuite/gdb.base/complex.exp          |  4 ++--
 gdb/testsuite/gdb.base/endianity.exp        |  4 ++--
 gdb/testsuite/gdb.base/floatn.exp           | 13 +++++--------
 gdb/testsuite/gdb.base/funcargs.exp         | 20 ++++++++++----------
 gdb/testsuite/gdb.base/varargs.exp          |  6 +++---
 gdb/testsuite/gdb.compile/compile-cplus.exp |  2 +-
 gdb/testsuite/gdb.compile/compile.exp       |  2 +-
 12 files changed, 48 insertions(+), 34 deletions(-)

diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 157ffd7ff7a..fd1bdeb819d 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -121,7 +121,7 @@ static const struct generic_val_print_decorations c_decorations =
 {
   "",
   " + ",
-  " * I",
+  "i",
   "true",
   "false",
   "void",
diff --git a/gdb/testsuite/gdb.base/callfuncs.exp b/gdb/testsuite/gdb.base/callfuncs.exp
index 5d98541745a..642fe0d7fd9 100644
--- a/gdb/testsuite/gdb.base/callfuncs.exp
+++ b/gdb/testsuite/gdb.base/callfuncs.exp
@@ -224,13 +224,13 @@ proc do_function_calls {prototypes} {
 
     if [support_complex_tests] {
 
-	gdb_test "p t_structs_fc(struct_val1)" ".*= 3 \\+ 3 \\* I" \
+	gdb_test "p t_structs_fc(struct_val1)" ".*= 3 \\+ 3i" \
 	    "call inferior func with struct - returns float _Complex"
 
-	gdb_test "p t_structs_dc(struct_val1)" ".*= 4 \\+ 4 \\* I" \
+	gdb_test "p t_structs_dc(struct_val1)" ".*= 4 \\+ 4i" \
 	    "call inferior func with struct - returns double _Complex"
 
-	gdb_test "p t_structs_ldc(struct_val1)" "= 5 \\+ 5 \\* I" \
+	gdb_test "p t_structs_ldc(struct_val1)" "= 5 \\+ 5i" \
 	    "call inferior func with struct - returns long double _Complex"
     }
 
diff --git a/gdb/testsuite/gdb.base/complex-parts.exp b/gdb/testsuite/gdb.base/complex-parts.exp
index 02fab04bc39..071de5c56d7 100644
--- a/gdb/testsuite/gdb.base/complex-parts.exp
+++ b/gdb/testsuite/gdb.base/complex-parts.exp
@@ -27,9 +27,9 @@ if { ![runto_main] } then {
 gdb_breakpoint [gdb_get_line_number "Break Here"]
 gdb_continue_to_breakpoint "breakpt" ".* Break Here\\. .*"
 
-gdb_test "p z1" " = 1.5 \\+ 4.5 \\* I"
-gdb_test "p z2" " = 2.5 \\+ -5.5 \\* I"
-gdb_test "p z3" " = 3.5 \\+ 6.5 \\* I"
+gdb_test "p z1" " = 1.5 \\+ 4.5i"
+gdb_test "p z2" " = 2.5 \\+ -5.5i"
+gdb_test "p z3" " = 3.5 \\+ 6.5i"
 
 gdb_test "ptype z1" " = complex double"
 gdb_test "ptype z2" " = complex float"
diff --git a/gdb/testsuite/gdb.base/complex.exp b/gdb/testsuite/gdb.base/complex.exp
index 442b830466a..b60d9372414 100644
--- a/gdb/testsuite/gdb.base/complex.exp
+++ b/gdb/testsuite/gdb.base/complex.exp
@@ -29,12 +29,12 @@ if [runto f2] then {
     if { [test_compiler_info gcc-2-*] && [test_debug_format "DWARF 2"] } then {
 	setup_xfail "*-*-*"
     }
-    gdb_test "p *y" "\\\$\[0-9\]* = \{c = 42 '\\*', f = 1 \\+ 0 \\* I\}" \
+    gdb_test "p *y" "\\\$\[0-9\]* = \{c = 42 '\\*', f = 1 \\+ 0i\}" \
 	    "print complex packed value in C"
 }
 
 if [runto f4] then {
-    gdb_test "p *y" "\\\$\[0-9\]* = \{c = 42 '\\*', f = 1 \\+ 0 \\* I\}" \
+    gdb_test "p *y" "\\\$\[0-9\]* = \{c = 42 '\\*', f = 1 \\+ 0i\}" \
 	    "print complex value in C"
 }
 
diff --git a/gdb/testsuite/gdb.base/endianity.exp b/gdb/testsuite/gdb.base/endianity.exp
index 52d5ff51048..2fa9ed3bf16 100644
--- a/gdb/testsuite/gdb.base/endianity.exp
+++ b/gdb/testsuite/gdb.base/endianity.exp
@@ -25,7 +25,7 @@ if ![runto "endianity.c:$bp_location" ] then {
   return -1
 }
 
-gdb_test "print o" "= {v = 3, w = 2, x = 7, f = 23.5, cplx = 1.25 \\+ 7.25 \\* I, d = 75}" \
+gdb_test "print o" "= {v = 3, w = 2, x = 7, f = 23.5, cplx = 1.25 \\+ 7.25i, d = 75}" \
     "print o before assignment"
 
 gdb_test "print o.v = 4" "= 4"
@@ -41,5 +41,5 @@ if { ([test_compiler_info {gcc-[0-5]-*}] || ![test_compiler_info gcc*]) } {
 gdb_test "x/x &o.v" "0x04000000"
 gdb_test "x/xh &o.w" "0x0300"
 
-gdb_test "print o" "= {v = 4, w = 3, x = 2, f = 1.5, cplx = 1.25 \\+ 7.25 \\* I, d = -23.125}" \
+gdb_test "print o" "= {v = 4, w = 3, x = 2, f = 1.5, cplx = 1.25 \\+ 7.25i, d = -23.125}" \
     "print o after assignment"
diff --git a/gdb/testsuite/gdb.base/floatn.exp b/gdb/testsuite/gdb.base/floatn.exp
index 564d01d64b0..0f087451b7c 100644
--- a/gdb/testsuite/gdb.base/floatn.exp
+++ b/gdb/testsuite/gdb.base/floatn.exp
@@ -114,11 +114,8 @@ gdb_test "print f32x" ".* = 100\\.5.*" "the value of f32x is changed to 100.5"
 gdb_test "print f64x" ".* = 200\\.25.*" "the value of f64x is changed to 200.25"
 
 # Print the original values of c32, c64, c128, c32x, c64x.
-gdb_test "print c32" ".* = 1\\.5 \\+ 1 \\* I.*" "the original value of c32 is 1.5 + 1 * I"
-gdb_test "print c64" ".* = 2\\.25 \\+ 1 \\* I.*" "the original value of c64 is 2.25 + 1 * I"
-gdb_test "print c128" ".* = 3\\.375 \\+ 1 \\* I.*" "the original value of c128 is 3.375 + 1 * I"
-gdb_test "print c32x" ".* = 10\\.5 \\+ 1 \\* I.*" "the original value of c32x is 10.5 + 1 * I"
-gdb_test "print c64x" ".* = 20\\.25 \\+ 1 \\* I.*" "the original value of c64x is 20.25 + 1 * I"
-
-# FIXME: GDB cannot parse non-trivial complex constants yet.
-
+gdb_test "print c32" ".* = 1\\.5 \\+ 1i.*" "the original value of c32 is 1.5 + 1i"
+gdb_test "print c64" ".* = 2\\.25 \\+ 1i.*" "the original value of c64 is 2.25 + 1i"
+gdb_test "print c128" ".* = 3\\.375 \\+ 1i.*" "the original value of c128 is 3.375 + 1i"
+gdb_test "print c32x" ".* = 10\\.5 \\+ 1i.*" "the original value of c32x is 10.5 + 1i"
+gdb_test "print c64x" ".* = 20\\.25 \\+ 1i.*" "the original value of c64x is 20.25 + 1i"
diff --git a/gdb/testsuite/gdb.base/funcargs.exp b/gdb/testsuite/gdb.base/funcargs.exp
index b45a8a11aa0..743c4c2758d 100644
--- a/gdb/testsuite/gdb.base/funcargs.exp
+++ b/gdb/testsuite/gdb.base/funcargs.exp
@@ -248,13 +248,13 @@ proc complex_args {} {
 
     # Run; should stop at call1a and print actual arguments.
     gdb_run_cmd
-    gdb_test "" " callca \\(f1=1 \\+ 2 \\* I, f2=1 \\+ 2 \\* I, f3=1 \\+ 2 \\* I\\) .*" "run to call2a"
+    gdb_test "" " callca \\(f1=1 \\+ 2i, f2=1 \\+ 2i, f3=1 \\+ 2i\\) .*" "run to call2a"
 
-    gdb_test "cont" ".* callcb \\(d1=3 \\+ 4 \\* I, d2=3 \\+ 4 \\* I, d3=3 \\+ 4 \\* I\\) .*" "continue to callcb"
-    gdb_test "cont" ".* callcc \\(ld1=5 \\+ 6 \\* I, ld2=5 \\+ 6 \\* I, ld3=5 \\+ 6 \\* I\\) .*" "continue to callcc"
-    gdb_test "cont" ".* callcd \\(fc1=1 \\+ 2 \\* I, dc1=3 \\+ 4 \\* I, ldc1=5 \\+ 6 \\* I\\) .*" "continue to callcd"
-    gdb_test "cont" ".* callce \\(dc1=3 \\+ 4 \\* I, ldc1=5 \\+ 6 \\* I, fc1=1 \\+ 2 \\* I\\) .*" "continue to callce"
-    gdb_test "cont" ".* callcf \\(ldc1=5 \\+ 6 \\* I, fc1=1 \\+ 2 \\* I, dc1=3 \\+ 4 \\* I\\) .*" "continue to callcf"
+    gdb_test "cont" ".* callcb \\(d1=3 \\+ 4i, d2=3 \\+ 4i, d3=3 \\+ 4i\\) .*" "continue to callcb"
+    gdb_test "cont" ".* callcc \\(ld1=5 \\+ 6i, ld2=5 \\+ 6i, ld3=5 \\+ 6i\\) .*" "continue to callcc"
+    gdb_test "cont" ".* callcd \\(fc1=1 \\+ 2i, dc1=3 \\+ 4i, ldc1=5 \\+ 6i\\) .*" "continue to callcd"
+    gdb_test "cont" ".* callce \\(dc1=3 \\+ 4i, ldc1=5 \\+ 6i, fc1=1 \\+ 2i\\) .*" "continue to callce"
+    gdb_test "cont" ".* callcf \\(ldc1=5 \\+ 6i, fc1=1 \\+ 2i, dc1=3 \\+ 4i\\) .*" "continue to callcf"
 }
 
 
@@ -271,9 +271,9 @@ proc complex_integral_args {} {
 
     # Run; should stop at call1a and print actual arguments.
     gdb_run_cmd
-    gdb_test "" " callc1a \\(c=97 'a', s=1, i=2, ui=7, l=3, fc1=1 \\+ 2 \\* I, dc1=3 \\+ 4 \\* I, ldc1=5 \\+ 6 \\* I\\) .*" "run to callc1a"
+    gdb_test "" " callc1a \\(c=97 'a', s=1, i=2, ui=7, l=3, fc1=1 \\+ 2i, dc1=3 \\+ 4i, ldc1=5 \\+ 6i\\) .*" "run to callc1a"
 
-    gdb_test "cont" ".* callc1b \\(ldc1=5 \\+ 6 \\* I\\, c=97 'a', s=1, i=2, fc1=1 \\+ 2 \\* I, ui=7, l=3, dc1=3 \\+ 4 \\* I\\) .*" "continue to callc1b"
+    gdb_test "cont" ".* callc1b \\(ldc1=5 \\+ 6i\\, c=97 'a', s=1, i=2, fc1=1 \\+ 2i, ui=7, l=3, dc1=3 \\+ 4i\\) .*" "continue to callc1b"
 }
 
 #
@@ -289,9 +289,9 @@ proc complex_float_integral_args {} {
 
     # Run; should stop at call1a and print actual arguments.
     gdb_run_cmd
-    gdb_test "" " callc2a \\(c=97 'a', s=1, i=2, ui=7, l=3, f=4, d=5, fc1=1 \\+ 2 \\* I, dc1=3 \\+ 4 \\* I, ldc1=5 \\+ 6 \\* I\\) .*" "run to callc2a"
+    gdb_test "" " callc2a \\(c=97 'a', s=1, i=2, ui=7, l=3, f=4, d=5, fc1=1 \\+ 2i, dc1=3 \\+ 4i, ldc1=5 \\+ 6i\\) .*" "run to callc2a"
 
-    gdb_test "cont" ".* callc2b \\(fc1=1 \\+ 2 \\* I, c=97 'a', s=1, i=2, ui=7, ldc1=5 \\+ 6 \\* I\\, l=3, f=4, d=5, dc1=3 \\+ 4 \\* I\\) .*" "continue to callc2b"
+    gdb_test "cont" ".* callc2b \\(fc1=1 \\+ 2i, c=97 'a', s=1, i=2, ui=7, ldc1=5 \\+ 6i\\, l=3, f=4, d=5, dc1=3 \\+ 4i\\) .*" "continue to callc2b"
 }
 
 #
diff --git a/gdb/testsuite/gdb.base/varargs.exp b/gdb/testsuite/gdb.base/varargs.exp
index 1b5ad0085f5..f6f4f659653 100644
--- a/gdb/testsuite/gdb.base/varargs.exp
+++ b/gdb/testsuite/gdb.base/varargs.exp
@@ -101,12 +101,12 @@ if [support_complex_tests] {
     global gdb_prompt
 
     set test "print find_max_float_real(4, fc1, fc2, fc3, fc4)"
-    gdb_test $test ".*= 4 \\+ 4 \\* I"
+    gdb_test $test ".*= 4 \\+ 4i"
 
     set test "print find_max_double_real(4, dc1, dc2, dc3, dc4)"
-    gdb_test $test ".*= 4 \\+ 4 \\* I"
+    gdb_test $test ".*= 4 \\+ 4i"
 
     set test "print find_max_long_double_real(4, ldc1, ldc2, ldc3, ldc4)"
-    gdb_test $test ".*= 4 \\+ 4 \\* I"
+    gdb_test $test ".*= 4 \\+ 4i"
 
 }
diff --git a/gdb/testsuite/gdb.compile/compile-cplus.exp b/gdb/testsuite/gdb.compile/compile-cplus.exp
index ffc62eab244..cca5b205200 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus.exp
@@ -219,7 +219,7 @@ gdb_test "print struct_object.arrayfield" \
     " = \\{0, 0, 7, 0, 0\\}"
 
 gdb_test_no_output "compile code struct_object.complexfield = 7 + 5i"
-gdb_test "print struct_object.complexfield" " = 7 \\+ 5 \\* I"
+gdb_test "print struct_object.complexfield" " = 7 \\+ 5i"
 
 gdb_test_no_output "compile code struct_object.boolfield = 1"
 gdb_test "print struct_object.boolfield" " = true"
diff --git a/gdb/testsuite/gdb.compile/compile.exp b/gdb/testsuite/gdb.compile/compile.exp
index 9ad4181b2fe..d9c3e6668ec 100644
--- a/gdb/testsuite/gdb.compile/compile.exp
+++ b/gdb/testsuite/gdb.compile/compile.exp
@@ -237,7 +237,7 @@ if {$skip_struct_object} {
 	" = \\{0, 0, 7, 0, 0\\}"
 
     gdb_test_no_output "compile code struct_object.complexfield = 7 + 5i"
-    gdb_test "print struct_object.complexfield" " = 7 \\+ 5 \\* I"
+    gdb_test "print struct_object.complexfield" " = 7 \\+ 5i"
 
     gdb_test_no_output "compile code struct_object.boolfield = 1"
     gdb_test "print struct_object.boolfield" " = true"
-- 
2.17.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 4/7] Change the C parser to allow complex constants
  2020-03-07 15:22 [PATCH 0/7] Update complex number support Tom Tromey
                   ` (2 preceding siblings ...)
  2020-03-07 15:22 ` [PATCH 3/7] Change how complex types are printed in C Tom Tromey
@ 2020-03-07 15:22 ` Tom Tromey
  2020-03-07 15:22 ` [PATCH 5/7] Allow printing of complex integers Tom Tromey
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2020-03-07 15:22 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes the C parser to allow complex constants.  Now something
like "print 23i" will work.

There are no tests in this patch; they come later.

gdb/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* c-exp.y (COMPLEX_INT, COMPLEX_FLOAT): New tokens.
	(exp) <COMPLEX_INT, COMPLEX_FLOAT>: New rules.
	(parse_number): Handle complex numbers.
---
 gdb/ChangeLog |  6 ++++
 gdb/c-exp.y   | 77 +++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 75 insertions(+), 8 deletions(-)

diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 3403a857a83..e0051ba4e00 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -54,6 +54,7 @@
 #include "typeprint.h"
 #include "cp-abi.h"
 #include "type-stack.h"
+#include "target-float.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 
@@ -185,8 +186,8 @@ static void c_print_token (FILE *file, int type, YYSTYPE value);
 
 %type <type_stack> ptr_operator_ts abs_decl direct_abs_decl
 
-%token <typed_val_int> INT
-%token <typed_val_float> FLOAT
+%token <typed_val_int> INT COMPLEX_INT
+%token <typed_val_float> FLOAT COMPLEX_FLOAT
 
 /* Both NAME and TYPENAME tokens represent symbols in the input,
    and both convey their data as strings.
@@ -774,6 +775,22 @@ exp	:	INT
 			  write_exp_elt_opcode (pstate, OP_LONG); }
 	;
 
+exp	:	COMPLEX_INT
+			{
+			  write_exp_elt_opcode (pstate, OP_LONG);
+			  write_exp_elt_type (pstate, TYPE_TARGET_TYPE ($1.type));
+			  write_exp_elt_longcst (pstate, 0);
+			  write_exp_elt_opcode (pstate, OP_LONG);
+			  write_exp_elt_opcode (pstate, OP_LONG);
+			  write_exp_elt_type (pstate, TYPE_TARGET_TYPE ($1.type));
+			  write_exp_elt_longcst (pstate, (LONGEST) ($1.val));
+			  write_exp_elt_opcode (pstate, OP_LONG);
+			  write_exp_elt_opcode (pstate, OP_COMPLEX);
+			  write_exp_elt_type (pstate, $1.type);
+			  write_exp_elt_opcode (pstate, OP_COMPLEX);
+			}
+	;
+
 exp	:	CHAR
 			{
 			  struct stoken_vector vec;
@@ -803,6 +820,27 @@ exp	:	FLOAT
 			  write_exp_elt_opcode (pstate, OP_FLOAT); }
 	;
 
+exp	:	COMPLEX_FLOAT
+			{
+			  struct type *underlying
+			    = TYPE_TARGET_TYPE ($1.type);
+
+			  write_exp_elt_opcode (pstate, OP_FLOAT);
+			  write_exp_elt_type (pstate, underlying);
+			  gdb_byte val[16];
+			  target_float_from_host_double (val, underlying, 0);
+			  write_exp_elt_floatcst (pstate, val);
+			  write_exp_elt_opcode (pstate, OP_FLOAT);
+			  write_exp_elt_opcode (pstate, OP_FLOAT);
+			  write_exp_elt_type (pstate, underlying);
+			  write_exp_elt_floatcst (pstate, $1.val);
+			  write_exp_elt_opcode (pstate, OP_FLOAT);
+			  write_exp_elt_opcode (pstate, OP_COMPLEX);
+			  write_exp_elt_type (pstate, $1.type);
+			  write_exp_elt_opcode (pstate, OP_COMPLEX);
+			}
+	;
+
 exp	:	variable
 	;
 
@@ -1845,7 +1883,10 @@ parse_number (struct parser_state *par_state,
   /* Number of "L" suffixes encountered.  */
   int long_p = 0;
 
-  /* We have found a "L" or "U" suffix.  */
+  /* Imaginary number.  */
+  bool imaginary_p = false;
+
+  /* We have found a "L" or "U" (or "i") suffix.  */
   int found_suffix = 0;
 
   ULONGEST high_bit;
@@ -1858,6 +1899,12 @@ parse_number (struct parser_state *par_state,
 
   if (parsed_float)
     {
+      if (len >= 1 && p[len - 1] == 'i')
+	{
+	  imaginary_p = true;
+	  --len;
+	}
+
       /* Handle suffixes for decimal floating-point: "df", "dd" or "dl".  */
       if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'f')
 	{
@@ -1901,7 +1948,12 @@ parse_number (struct parser_state *par_state,
 			putithere->typed_val_float.type,
 			putithere->typed_val_float.val))
         return ERROR;
-      return FLOAT;
+
+      if (imaginary_p)
+	putithere->typed_val_float.type
+	  = init_complex_type (nullptr, putithere->typed_val_float.type);
+
+      return imaginary_p ? COMPLEX_FLOAT : FLOAT;
     }
 
   /* Handle base-switching prefixes 0x, 0t, 0d, 0 */
@@ -1950,7 +2002,7 @@ parse_number (struct parser_state *par_state,
       c = *p++;
       if (c >= 'A' && c <= 'Z')
 	c += 'a' - 'A';
-      if (c != 'l' && c != 'u')
+      if (c != 'l' && c != 'u' && c != 'i')
 	n *= base;
       if (c >= '0' && c <= '9')
 	{
@@ -1976,6 +2028,11 @@ parse_number (struct parser_state *par_state,
 	      unsigned_p = 1;
 	      found_suffix = 1;
 	    }
+	  else if (c == 'i')
+	    {
+	      imaginary_p = true;
+	      found_suffix = 1;
+	    }
 	  else
 	    return ERROR;	/* Char not a digit */
 	}
@@ -1985,13 +2042,13 @@ parse_number (struct parser_state *par_state,
       /* Portably test for overflow (only works for nonzero values, so make
 	 a second check for zero).  FIXME: Can't we just make n and prevn
 	 unsigned and avoid this?  */
-      if (c != 'l' && c != 'u' && (prevn >= n) && n != 0)
+      if (c != 'l' && c != 'u' && c != 'i' && (prevn >= n) && n != 0)
 	unsigned_p = 1;		/* Try something unsigned */
 
       /* Portably test for unsigned overflow.
 	 FIXME: This check is wrong; for example it doesn't find overflow
 	 on 0x123456789 when LONGEST is 32 bits.  */
-      if (c != 'l' && c != 'u' && n != 0)
+      if (c != 'l' && c != 'u' && c != 'i' && n != 0)
 	{	
 	  if (unsigned_p && prevn >= n)
 	    error (_("Numeric constant too large."));
@@ -2063,7 +2120,11 @@ parse_number (struct parser_state *par_state,
        putithere->typed_val_int.type = signed_type;
      }
 
-   return INT;
+   if (imaginary_p)
+     putithere->typed_val_int.type
+       = init_complex_type (nullptr, putithere->typed_val_int.type);
+
+   return imaginary_p ? COMPLEX_INT : INT;
 }
 
 /* Temporary obstack used for holding strings.  */
-- 
2.17.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 5/7] Allow printing of complex integers
  2020-03-07 15:22 [PATCH 0/7] Update complex number support Tom Tromey
                   ` (3 preceding siblings ...)
  2020-03-07 15:22 ` [PATCH 4/7] Change the C parser to allow complex constants Tom Tromey
@ 2020-03-07 15:22 ` Tom Tromey
  2020-03-20 21:52   ` Tom Tromey
  2020-03-07 15:22 ` [PATCH 6/7] Implement complex arithmetic Tom Tromey
  2020-03-07 15:22 ` [PATCH 7/7] Add _Complex type support to C parser Tom Tromey
  6 siblings, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2020-03-07 15:22 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

GCC allows complex integers, but gdb could not print them.  The
problem was that generic_val_print_complex assumed that complex
numbers have floating point components.  This patch corrects this
error.

gdb/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* valprint.c (generic_val_print_complex): Use
	val_print_scalar_formatted.
---
 gdb/ChangeLog  |  5 +++++
 gdb/valprint.c | 27 +++++++--------------------
 2 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/gdb/valprint.c b/gdb/valprint.c
index 8adbb3df457..93e118e12d5 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -886,28 +886,15 @@ generic_val_print_complex (struct type *type,
 			   const struct generic_val_print_decorations
 			     *decorations)
 {
-  struct gdbarch *gdbarch = get_type_arch (type);
-  int unit_size = gdbarch_addressable_memory_unit_size (gdbarch);
-  const gdb_byte *valaddr = value_contents_for_printing (original_value);
-
   fprintf_filtered (stream, "%s", decorations->complex_prefix);
-  if (options->format)
-    val_print_scalar_formatted (TYPE_TARGET_TYPE (type),
-				embedded_offset, original_value, options, 0,
-				stream);
-  else
-    print_floating (valaddr + embedded_offset * unit_size,
-		    TYPE_TARGET_TYPE (type), stream);
+  val_print_scalar_formatted (TYPE_TARGET_TYPE (type),
+			      embedded_offset, original_value, options, 0,
+			      stream);
   fprintf_filtered (stream, "%s", decorations->complex_infix);
-  if (options->format)
-    val_print_scalar_formatted (TYPE_TARGET_TYPE (type),
-				embedded_offset
-				+ type_length_units (TYPE_TARGET_TYPE (type)),
-				original_value, options, 0, stream);
-  else
-    print_floating (valaddr + embedded_offset * unit_size
-		    + TYPE_LENGTH (TYPE_TARGET_TYPE (type)),
-		    TYPE_TARGET_TYPE (type), stream);
+  val_print_scalar_formatted (TYPE_TARGET_TYPE (type),
+			      embedded_offset
+			      + type_length_units (TYPE_TARGET_TYPE (type)),
+			      original_value, options, 0, stream);
   fprintf_filtered (stream, "%s", decorations->complex_suffix);
 }
 
-- 
2.17.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 6/7] Implement complex arithmetic
  2020-03-07 15:22 [PATCH 0/7] Update complex number support Tom Tromey
                   ` (4 preceding siblings ...)
  2020-03-07 15:22 ` [PATCH 5/7] Allow printing of complex integers Tom Tromey
@ 2020-03-07 15:22 ` Tom Tromey
  2020-03-07 15:22 ` [PATCH 7/7] Add _Complex type support to C parser Tom Tromey
  6 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2020-03-07 15:22 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds support for complex arithmetic to gdb.  Now something like
"print 23 + 7i" will work.

Addition, subtraction, multiplication, division, and equality testing
are supported binary operations.

Unary +, negation, and complement are supported.  Following GCC, the ~
operator computes the complex conjugate.

gdb/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	PR exp/25299:
	* valarith.c (promotion_type, complex_binop): New functions.
	(scalar_binop): Handle complex numbers.  Use promotion_type.
	(value_pos, value_neg, value_complement): Handle complex numbers.

gdb/testsuite/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* gdb.base/complex-parts.exp: Add arithmetic tests.
---
 gdb/ChangeLog                            |   7 +
 gdb/testsuite/ChangeLog                  |   4 +
 gdb/testsuite/gdb.base/complex-parts.exp |  26 +++
 gdb/valarith.c                           | 199 ++++++++++++++++++++---
 4 files changed, 215 insertions(+), 21 deletions(-)

diff --git a/gdb/testsuite/gdb.base/complex-parts.exp b/gdb/testsuite/gdb.base/complex-parts.exp
index 071de5c56d7..0cf4abf56ec 100644
--- a/gdb/testsuite/gdb.base/complex-parts.exp
+++ b/gdb/testsuite/gdb.base/complex-parts.exp
@@ -60,3 +60,29 @@ gdb_test "p \$_cimag (i1)" "expected a complex number"
 gdb_test "p \$_creal (d1)" "expected a complex number"
 gdb_test "p \$_creal (f1)" "expected a complex number"
 gdb_test "p \$_creal (i1)" "expected a complex number"
+
+#
+# General complex number tests.
+#
+
+gdb_test "print 23 + 7i" " = 23 \\+ 7i"
+gdb_test "print 23.125f + 7i" " = 23.125 \\+ 7i"
+gdb_test "print 23 + 7.25fi" " = 23 \\+ 7.25i"
+gdb_test "print (23 + 7i) + (17 + 10i)" " = 40 \\+ 17i"
+gdb_test "print 23 + -7i" " = 23 \\+ -7i"
+gdb_test "print 23 - 7i" " = 23 \\+ -7i"
+
+gdb_test "print -(23 + 7i)" " = -23 \\+ -7i"
+gdb_test "print +(23 + 7i)" " = 23 \\+ 7i"
+gdb_test "print ~(23 + 7i)" " = 23 \\+ -7i"
+
+gdb_test "print (5 + 5i) * (2 + 2i)" " = 0 \\+ 20i"
+
+gdb_test "print (5 + 7i) == (5 + 7i)" " = 1"
+gdb_test "print (5 + 7i) == (8 + 7i)" " = 0"
+gdb_test "print (5 + 7i) == (5 + 92i)" " = 0"
+gdb_test "print (5 + 7i) != (5 + 7i)" " = 0"
+gdb_test "print (5 + 7i) != (8 + 7i)" " = 1"
+gdb_test "print (5 + 7i) != (5 + 92i)" " = 1"
+
+gdb_test "print (20 - 4i) / (3 + 2i)" " = 4 \\+ -4i"
diff --git a/gdb/valarith.c b/gdb/valarith.c
index be0e0731bee..07cb5014bb2 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -911,6 +911,157 @@ value_args_as_target_float (struct value *arg1, struct value *arg2,
 	     TYPE_NAME (type2));
 }
 
+/* A helper function that finds the type to use for a binary operation
+   involving TYPE1 and TYPE2.  */
+
+static struct type *
+promotion_type (struct type *type1, struct type *type2)
+{
+  struct type *result_type;
+
+  if (is_floating_type (type1) || is_floating_type (type2))
+    {
+      /* If only one type is floating-point, use its type.
+	 Otherwise use the bigger type.  */
+      if (!is_floating_type (type1))
+	result_type = type2;
+      else if (!is_floating_type (type2))
+	result_type = type1;
+      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
+	result_type = type2;
+      else
+	result_type = type1;
+    }
+  else
+    {
+      /* Integer types.  */
+      if (TYPE_LENGTH (type1) > TYPE_LENGTH (type2))
+	result_type = type1;
+      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
+	result_type = type2;
+      else if (TYPE_UNSIGNED (type1))
+	result_type = type1;
+      else if (TYPE_UNSIGNED (type2))
+	result_type = type2;
+      else
+	result_type = type1;
+    }
+
+  return result_type;
+}
+
+static struct value *scalar_binop (struct value *arg1, struct value *arg2,
+				   enum exp_opcode op);
+
+/* Perform a binary operation on complex operands.  */
+
+static struct value *
+complex_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
+{
+  struct type *arg1_type = check_typedef (value_type (arg1));
+  struct type *arg2_type = check_typedef (value_type (arg2));
+
+  struct value *arg1_real, *arg1_imag, *arg2_real, *arg2_imag;
+  if (TYPE_CODE (arg1_type) == TYPE_CODE_COMPLEX)
+    {
+      arg1_real = value_real_part (arg1);
+      arg1_imag = value_imaginary_part (arg1);
+    }
+  else
+    {
+      arg1_real = arg1;
+      arg1_imag = value_zero (arg1_type, not_lval);
+    }
+  if (TYPE_CODE (arg2_type) == TYPE_CODE_COMPLEX)
+    {
+      arg2_real = value_real_part (arg2);
+      arg2_imag = value_imaginary_part (arg2);
+    }
+  else
+    {
+      arg2_real = arg2;
+      arg2_imag = value_zero (arg2_type, not_lval);
+    }
+
+  struct type *comp_type = promotion_type (value_type (arg1_real),
+					   value_type (arg2_real));
+  arg1_real = value_cast (comp_type, arg1_real);
+  arg1_imag = value_cast (comp_type, arg1_imag);
+  arg2_real = value_cast (comp_type, arg2_real);
+  arg2_imag = value_cast (comp_type, arg2_imag);
+
+  struct type *result_type = init_complex_type (nullptr, comp_type);
+
+  struct value *result_real, *result_imag;
+  switch (op)
+    {
+    case BINOP_ADD:
+    case BINOP_SUB:
+      result_real = scalar_binop (arg1_real, arg2_real, op);
+      result_imag = scalar_binop (arg1_imag, arg2_imag, op);
+      break;
+
+    case BINOP_MUL:
+      {
+	struct value *x1 = scalar_binop (arg1_real, arg2_real, op);
+	struct value *x2 = scalar_binop (arg1_imag, arg2_imag, op);
+	result_real = scalar_binop (x1, x2, BINOP_SUB);
+
+	x1 = scalar_binop (arg1_real, arg2_imag, op);
+	x2 = scalar_binop (arg1_imag, arg2_real, op);
+	result_imag = scalar_binop (x1, x2, BINOP_ADD);
+      }
+      break;
+
+    case BINOP_DIV:
+      {
+	if (TYPE_CODE (arg2_type) == TYPE_CODE_COMPLEX)
+	  {
+	    struct value *conjugate = value_complement (arg2);
+	    /* We have to reconstruct ARG1, in case the type was
+	       promoted.  */
+	    arg1 = value_literal_complex (arg1_real, arg1_imag, result_type);
+
+	    struct value *numerator = scalar_binop (arg1, conjugate,
+						    BINOP_MUL);
+	    arg1_real = value_real_part (numerator);
+	    arg1_imag = value_imaginary_part (numerator);
+
+	    struct value *x1 = scalar_binop (arg2_real, arg2_real, BINOP_MUL);
+	    struct value *x2 = scalar_binop (arg2_imag, arg2_imag, BINOP_MUL);
+	    arg2_real = scalar_binop (x1, x2, BINOP_ADD);
+	  }
+
+	result_real = scalar_binop (arg1_real, arg2_real, op);
+	result_imag = scalar_binop (arg1_imag, arg2_real, op);
+      }
+      break;
+
+    case BINOP_EQUAL:
+    case BINOP_NOTEQUAL:
+      {
+	struct value *x1 = scalar_binop (arg1_real, arg2_real, op);
+	struct value *x2 = scalar_binop (arg1_imag, arg2_imag, op);
+
+	LONGEST v1 = value_as_long (x1);
+	LONGEST v2 = value_as_long (x2);
+
+	if (op == BINOP_EQUAL)
+	  v1 = v1 && v2;
+	else
+	  v1 = v1 || v2;
+
+	return value_from_longest (value_type (x1), v1);
+      }
+      break;
+
+    default:
+      error (_("Invalid binary operation on numbers."));
+    }
+
+  return value_literal_complex (result_real, result_imag, result_type);
+}
+
 /* Perform a binary operation on two operands which have reasonable
    representations as integers or floats.  This includes booleans,
    characters, integers, or floats.
@@ -929,23 +1080,17 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   type1 = check_typedef (value_type (arg1));
   type2 = check_typedef (value_type (arg2));
 
+  if (TYPE_CODE (type1) == TYPE_CODE_COMPLEX
+      || TYPE_CODE (type2) == TYPE_CODE_COMPLEX)
+    return complex_binop (arg1, arg2, op);
+
   if ((!is_floating_value (arg1) && !is_integral_type (type1))
       || (!is_floating_value (arg2) && !is_integral_type (type2)))
     error (_("Argument to arithmetic operation not a number or boolean."));
 
   if (is_floating_type (type1) || is_floating_type (type2))
     {
-      /* If only one type is floating-point, use its type.
-	 Otherwise use the bigger type.  */
-      if (!is_floating_type (type1))
-	result_type = type2;
-      else if (!is_floating_type (type2))
-	result_type = type1;
-      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
-	result_type = type2;
-      else
-	result_type = type1;
-
+      result_type = promotion_type (type1, type2);
       val = allocate_value (result_type);
 
       struct type *eff_type_v1, *eff_type_v2;
@@ -1013,16 +1158,8 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 	 if one of the operands is unsigned.  */
       if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP)
 	result_type = type1;
-      else if (TYPE_LENGTH (type1) > TYPE_LENGTH (type2))
-	result_type = type1;
-      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
-	result_type = type2;
-      else if (TYPE_UNSIGNED (type1))
-	result_type = type1;
-      else if (TYPE_UNSIGNED (type2))
-	result_type = type2;
       else
-	result_type = type1;
+	result_type = promotion_type (type1, type2);
 
       if (TYPE_UNSIGNED (result_type))
 	{
@@ -1629,7 +1766,8 @@ value_pos (struct value *arg1)
   type = check_typedef (value_type (arg1));
 
   if (is_integral_type (type) || is_floating_value (arg1)
-      || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)))
+      || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type))
+      || TYPE_CODE (type) == TYPE_CODE_COMPLEX)
     return value_from_contents (type, value_contents (arg1));
   else
     error (_("Argument to positive operation not a number."));
@@ -1663,6 +1801,15 @@ value_neg (struct value *arg1)
 	}
       return val;
     }
+  else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX)
+    {
+      struct value *real = value_real_part (arg1);
+      struct value *imag = value_imaginary_part (arg1);
+
+      real = value_neg (real);
+      imag = value_neg (imag);
+      return value_literal_complex (real, imag, type);
+    }
   else
     error (_("Argument to negate operation not a number."));
 }
@@ -1696,6 +1843,16 @@ value_complement (struct value *arg1)
                   value_contents_all (tmp), TYPE_LENGTH (eltype));
         }
     }
+  else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX)
+    {
+      /* GCC has an extension that treats ~complex as the complex
+	 conjugate.  */
+      struct value *real = value_real_part (arg1);
+      struct value *imag = value_imaginary_part (arg1);
+
+      imag = value_neg (imag);
+      return value_literal_complex (real, imag, type);
+    }
   else
     error (_("Argument to complement operation not an integer, boolean."));
 
-- 
2.17.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 7/7] Add _Complex type support to C parser
  2020-03-07 15:22 [PATCH 0/7] Update complex number support Tom Tromey
                   ` (5 preceding siblings ...)
  2020-03-07 15:22 ` [PATCH 6/7] Implement complex arithmetic Tom Tromey
@ 2020-03-07 15:22 ` Tom Tromey
  6 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2020-03-07 15:22 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes the C parser to add support for complex types in casts.

gdb/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* c-exp.y (FLOAT_KEYWORD, COMPLEX): New tokens.
	(scalar_type): New rule, from typebase.
	(typebase): Use scalar_type.  Recognize complex types.
	(field_name): Handle FLOAT_KEYWORD.
	(ident_tokens): Add _Complex and __complex__.

gdb/testsuite/ChangeLog
2020-03-07  Tom Tromey  <tom@tromey.com>

	* gdb.base/complex-parts.exp: Add type tests.
---
 gdb/ChangeLog                            |  8 +++
 gdb/c-exp.y                              | 81 +++++++++++++++---------
 gdb/testsuite/ChangeLog                  |  4 ++
 gdb/testsuite/gdb.base/complex-parts.exp |  5 ++
 4 files changed, 68 insertions(+), 30 deletions(-)

diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index e0051ba4e00..a3f0fb07b39 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -175,7 +175,7 @@ static void c_print_token (FILE *file, int type, YYSTYPE value);
 
 %type <voidval> exp exp1 type_exp start variable qualified_name lcurly function_method
 %type <lval> rcurly
-%type <tval> type typebase
+%type <tval> type typebase scalar_type
 %type <tvec> nonempty_typelist func_mod parameter_typelist
 /* %type <bval> block */
 
@@ -238,6 +238,7 @@ static void c_print_token (FILE *file, int type, YYSTYPE value);
 /* Special type cases, put in to allow the parser to distinguish different
    legal basetypes.  */
 %token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD
+%token FLOAT_KEYWORD COMPLEX
 
 %token <sval> DOLLAR_VARIABLE
 
@@ -1323,20 +1324,11 @@ func_mod:	'(' ')'
 type	:	ptype
 	;
 
-/* Implements (approximately): (type-qualifier)* type-specifier.
+/* A helper production that recognizes scalar types that can validly
+   be used with _Complex.  */
 
-   When type-specifier is only ever a single word, like 'float' then these
-   arrive as pre-built TYPENAME tokens thanks to the classify_name
-   function.  However, when a type-specifier can contain multiple words,
-   for example 'double' can appear as just 'double' or 'long double', and
-   similarly 'long' can appear as just 'long' or in 'long double', then
-   these type-specifiers are parsed into their own tokens in the function
-   lex_one_token and the ident_tokens array.  These separate tokens are all
-   recognised here.  */
-typebase
-	:	TYPENAME
-			{ $$ = $1.type; }
-	|	INT_KEYWORD
+scalar_type:
+		INT_KEYWORD
 			{ $$ = lookup_signed_typename (pstate->language (),
 						       "int"); }
 	|	LONG
@@ -1419,11 +1411,49 @@ typebase
 						"double",
 						NULL,
 						0); }
+	|	FLOAT_KEYWORD
+			{ $$ = lookup_typename (pstate->language (),
+						"float",
+						NULL,
+						0); }
 	|	LONG DOUBLE_KEYWORD
 			{ $$ = lookup_typename (pstate->language (),
 						"long double",
 						NULL,
 						0); }
+	|	UNSIGNED type_name
+			{ $$ = lookup_unsigned_typename (pstate->language (),
+							 TYPE_NAME($2.type)); }
+	|	UNSIGNED
+			{ $$ = lookup_unsigned_typename (pstate->language (),
+							 "int"); }
+	|	SIGNED_KEYWORD type_name
+			{ $$ = lookup_signed_typename (pstate->language (),
+						       TYPE_NAME($2.type)); }
+	|	SIGNED_KEYWORD
+			{ $$ = lookup_signed_typename (pstate->language (),
+						       "int"); }
+	;
+
+/* Implements (approximately): (type-qualifier)* type-specifier.
+
+   When type-specifier is only ever a single word, like 'float' then these
+   arrive as pre-built TYPENAME tokens thanks to the classify_name
+   function.  However, when a type-specifier can contain multiple words,
+   for example 'double' can appear as just 'double' or 'long double', and
+   similarly 'long' can appear as just 'long' or in 'long double', then
+   these type-specifiers are parsed into their own tokens in the function
+   lex_one_token and the ident_tokens array.  These separate tokens are all
+   recognised here.  */
+typebase
+	:	TYPENAME
+			{ $$ = $1.type; }
+	|	scalar_type
+			{ $$ = $1; }
+	|	COMPLEX scalar_type
+			{
+			  $$ = init_complex_type (nullptr, $2);
+			}
 	|	STRUCT name
 			{ $$
 			    = lookup_struct (copy_name ($2).c_str (),
@@ -1490,18 +1520,6 @@ typebase
 						       $2.length);
 			  $$ = NULL;
 			}
-	|	UNSIGNED type_name
-			{ $$ = lookup_unsigned_typename (pstate->language (),
-							 TYPE_NAME($2.type)); }
-	|	UNSIGNED
-			{ $$ = lookup_unsigned_typename (pstate->language (),
-							 "int"); }
-	|	SIGNED_KEYWORD type_name
-			{ $$ = lookup_signed_typename (pstate->language (),
-						       TYPE_NAME($2.type)); }
-	|	SIGNED_KEYWORD
-			{ $$ = lookup_signed_typename (pstate->language (),
-						       "int"); }
                 /* It appears that this rule for templates is never
                    reduced; template recognition happens by lookahead
                    in the token processing code in yylex. */
@@ -1727,12 +1745,11 @@ oper:	OPERATOR NEW
    match the 'name' rule to appear as fields within a struct.  The example
    that initially motivated this was the RISC-V target which models the
    floating point registers as a union with fields called 'float' and
-   'double'.  The 'float' string becomes a TYPENAME token and can appear
-   anywhere a 'name' can, however 'double' is its own token,
-   DOUBLE_KEYWORD, and doesn't match the 'name' rule.*/
+   'double'.  */
 field_name
 	:	name
 	|	DOUBLE_KEYWORD { $$ = typename_stoken ("double"); }
+	|	FLOAT_KEYWORD { $$ = typename_stoken ("float"); }
 	|	INT_KEYWORD { $$ = typename_stoken ("int"); }
 	|	LONG { $$ = typename_stoken ("long"); }
 	|	SHORT { $$ = typename_stoken ("short"); }
@@ -2460,7 +2477,7 @@ static const struct token tokentab2[] =
 /* Identifier-like tokens.  Only type-specifiers than can appear in
    multi-word type names (for example 'double' can appear in 'long
    double') need to be listed here.  type-specifiers that are only ever
-   single word (like 'float') are handled by the classify_name function.  */
+   single word (like 'char') are handled by the classify_name function.  */
 static const struct token ident_tokens[] =
   {
     {"unsigned", UNSIGNED, OP_NULL, 0},
@@ -2472,6 +2489,7 @@ static const struct token ident_tokens[] =
     {"_Alignof", ALIGNOF, OP_NULL, 0},
     {"alignof", ALIGNOF, OP_NULL, FLAG_CXX},
     {"double", DOUBLE_KEYWORD, OP_NULL, 0},
+    {"float", FLOAT_KEYWORD, OP_NULL, 0},
     {"false", FALSEKEYWORD, OP_NULL, FLAG_CXX},
     {"class", CLASS, OP_NULL, FLAG_CXX},
     {"union", UNION, OP_NULL, 0},
@@ -2479,6 +2497,9 @@ static const struct token ident_tokens[] =
     {"const", CONST_KEYWORD, OP_NULL, 0},
     {"enum", ENUM, OP_NULL, 0},
     {"long", LONG, OP_NULL, 0},
+    {"_Complex", COMPLEX, OP_NULL, 0},
+    {"__complex__", COMPLEX, OP_NULL, 0},
+
     {"true", TRUEKEYWORD, OP_NULL, FLAG_CXX},
     {"int", INT_KEYWORD, OP_NULL, 0},
     {"new", NEW, OP_NULL, FLAG_CXX},
diff --git a/gdb/testsuite/gdb.base/complex-parts.exp b/gdb/testsuite/gdb.base/complex-parts.exp
index 0cf4abf56ec..38aad395ad2 100644
--- a/gdb/testsuite/gdb.base/complex-parts.exp
+++ b/gdb/testsuite/gdb.base/complex-parts.exp
@@ -86,3 +86,8 @@ gdb_test "print (5 + 7i) != (8 + 7i)" " = 1"
 gdb_test "print (5 + 7i) != (5 + 92i)" " = 1"
 
 gdb_test "print (20 - 4i) / (3 + 2i)" " = 4 \\+ -4i"
+
+gdb_test "print (_Complex int) 4" " = 4 \\+ 0i"
+gdb_test "print (_Complex float) 4.5" " = 4.5 \\+ 0i"
+gdb_test "ptype __complex__ short" " = _Complex short"
+gdb_test "print (_Complex int) (23.75 + 8.88i)" " = 23 \\+ 8i"
-- 
2.17.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 5/7] Allow printing of complex integers
  2020-03-07 15:22 ` [PATCH 5/7] Allow printing of complex integers Tom Tromey
@ 2020-03-20 21:52   ` Tom Tromey
  0 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2020-03-20 21:52 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

Tom> GCC allows complex integers, but gdb could not print them.  The
Tom> problem was that generic_val_print_complex assumed that complex
Tom> numbers have floating point components.  This patch corrects this
Tom> error.

Tom> gdb/ChangeLog
Tom> 2020-03-07  Tom Tromey  <tom@tromey.com>

Tom> 	* valprint.c (generic_val_print_complex): Use
Tom> 	val_print_scalar_formatted.

It turns out I already fixed this in the val_print removal series, so
this patch is no longer needed.

Tom





^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2020-03-21  5:27 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-07 15:22 [PATCH 0/7] Update complex number support Tom Tromey
2020-03-07 15:22 ` [PATCH 1/7] Change how complex types are created Tom Tromey
2020-03-07 15:22 ` [PATCH 2/7] Add accessors for members of complex numbers Tom Tromey
2020-03-07 15:22 ` [PATCH 3/7] Change how complex types are printed in C Tom Tromey
2020-03-07 15:22 ` [PATCH 4/7] Change the C parser to allow complex constants Tom Tromey
2020-03-07 15:22 ` [PATCH 5/7] Allow printing of complex integers Tom Tromey
2020-03-20 21:52   ` Tom Tromey
2020-03-07 15:22 ` [PATCH 6/7] Implement complex arithmetic Tom Tromey
2020-03-07 15:22 ` [PATCH 7/7] Add _Complex type support to C parser Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).