generic PATCH: Replace CONCAT with RECORD_REGS

Greg McGary gkm@eng.ascend.com
Sat Oct 2 21:10:00 GMT 1999


Mike (or other interested parties),

Please look this over.

This patch replaces the special purpose CONCAT rtx with the general
RECORD_REGS rtl.  RECORD_REGS contains a tree pointer to the record
type it represents, and a vector of FIELD_REG rtxes.  Each FIELD_REG
rtx contains a tree pointer to the FIELD_DECL it represents and to
a REG or MEM rtx.

The rtl code names RECORD_REGS and FIELD_REG rtl are a bit ungainly,
but I disliked them least among the alternatives.  STRUCT is already
in use as a terminal symbol for the parser.  RECORD isn't yet, but
probably will come with Pascal or Ada.  FIELD is already in use.  I
could have chosen abbreviations such as RECX & FLDX, but went with
RECORD_REGS & FIELD_REGS to emphasize that they are a collection of
pseudos.  A FIELD_REG can might point to a MEM if the address of that
field is taken, though I don't think that can happen at present in the
limited case of complex numbers.

I made some effort that RECORD_REGS handling be generic, but we'll
surely find deficiencies when its use is expanded beyond complex
numbers.  Right now the type tree pointer in RECORD_REGS is unused,
and I wonder if it ought to instead point to a decl.  That can change
if/when we determine that the decl is needed.

There are no regressions with `make bootstrap compare; make check' on
native i686-pc-linux-gnu.

Greg

gcc:

Sat Oct  2 17:33:05 1999  Greg McGary  <gkm@gnu.org>

	* tree.h (TYPE_COMPLEX_SUBTYPE): New macro.

	* rtl.def (CONCAT): Remove obsolete RTL code.
	(RECORD_REGS, FIELD_REG): New RTL codes.

	* rtl.h (RECORD_REGS_FIELD_REG_VEC, RECORD_REGS_FIELD_REG,
	RECORD_REGS_NUM_FIELDS, RECORD_REGS_TYPE):
	New macros to access fields of a RECORD_REGS rtx.
	(RECORD_REGS_COMPLEX_REAL, RECORD_REGS_COMPLEX_IMAG): New macros to
	access fields of a RECORD_REGS rtx that represents a complex number.
	(RECORD_REGS_COMPLEX_P): New macro to identify a
	complex-number RECORD_REGS.
	(FIELD_REG_RTX, FIELD_REG_DECL, FIELD_REG_BYTE_OFFSET):
	New macros to access fields of a FIELD_REG rtx.

	* dbxout.c (dbxout_type): Use TYPE_COMPLEX_SUBTYPE.
	(dbxout_symbol_location): Rewrite CONCAT as RECORD_REGS.
	(dbxout_symbol_name): Accept SUFFIX arg without separator.
	Print '$' as separator.
	(dbxout_reg_parms): Use RECORD_REGS_COMPLEX_P.

	* dwarf2out.c (base_type_die): Use TYPE_COMPLEX_SUBTYPE.
	(concat_loc_descriptor): Remove function.
	(struct_loc_descriptor): New function that generalizes
	concat_loc_descriptor.
	(loc_descriptor): Call struct_loc_descriptor.
	(add_AT_location_description): Handle old CONCAT case with
	general RECORD_REGS & FIELD_REG.
	(add_location_or_const_value_attribute): s/CONCAT/RECORD_REGS/.

	* dwarfout.c (location_or_const_value_attribute):
	Handle old CONCAT case as general RECORD_REGS.

	* emit-rtl.c (gen_record_regs_rtx): New function to allocate
	pseudos for RECORD_REGS fields.
	(gen_reg_rtx, mark_user_reg, gen_realpart, gen_imagpart,
	operand_subword): Handle old CONCAT case as general RECORD_REGS.

	* expr.c
	(emit_group_load): Handle old CONCAT case as general RECORD_REGS.
	(expand_expr): Use TYPE_COMPLEX_SUBTYPE.
	Replace CONCAT with RECORD_REGS.
	(do_jump): Use TYPE_COMPLEX_SUBTYPE.

	* function.c
	(field_rtx_matches_var): New function.
	(put_var_into_stack, fixup_var_refs_insns, assign_parms):
	Handle old CONCAT case as general RECORD_REGS.

	* integrate.c (initialize_for_inline, expand_inline_function,
	copy_rtx_and_substitute, copy_rtx_and_substitute):
	Handle old CONCAT case as general RECORD_REGS.

	* c-typeck.c (common_type, build_unary_op): Use TYPE_COMPLEX_SUBTYPE.
	* convert.c (convert_to_real, convert_to_integer, convert_to_complex):
	Ditto.
	* stor-layout.c (layout_type): Ditto.
	* config/sh/sh.c (sh_va_arg): Ditto.

	* machmode.h (GET_MODE_UNIT_MODE): New macro.
	* optabs.c (expand_binop, expand_unop, expand_complex_abs): Use it.
	* expr.c (emit_move_insn_1): Ditto.

	* c-common.c (type_for_mode): Handle complex types.
	* tree.c (record_types_equal): New function.
	(type_hash_lookup): Call record_types_equal when subtypes
	don't match exactly.
	(build_complex_type): Make RECORD_TYPE be the TREE_TYPE
	of COMPLEX_TYPE.
	(build_common_tree_nodes_2): Use build_complex_type to initialize
	complex_*_type_node.

gcc/cp:

Sat Oct  2 17:33:05 1999  Greg McGary  <gkm@gnu.org>

	* method.c (process_overload_item): Use TYPE_COMPLEX_SUBTYPE.
	* typeck.c (common_type, comptypes, build_unary_op): Ditto.

gcc/f:

Sat Oct  2 17:33:05 1999  Greg McGary  <gkm@gnu.org>

	* com.c (ffecom_convert_narrow_, ffecom_convert_widen_,
	ffecom_make_complex_type_, ffecom_debug_kludge_, ffecom_expr_,
	ffecom_expr_intrinsic_, ffecom_tree_divide_,
	truthvalue_conversion): Use TYPE_COMPLEX_SUBTYPE.
	(ffecom_make_complex_type_): Make RECORD_TYPE be the TREE_TYPE
	of COMPLEX_TYPE.


Index: c-common.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-common.c,v
retrieving revision 1.72
diff -u -p -r1.72 c-common.c
--- c-common.c	1999/09/24 10:06:48	1.72
+++ c-common.c	1999/10/03 03:23:42
@@ -2247,6 +2247,21 @@ type_for_mode (mode, unsignedp)
   if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
     return build_pointer_type (integer_type_node);
 
+  if (mode == TYPE_MODE (complex_integer_type_node))
+    return complex_integer_type_node;
+  
+  if (mode == TYPE_MODE (complex_float_type_node))
+    return complex_float_type_node;
+  
+  if (mode == TYPE_MODE (complex_double_type_node))
+    return complex_double_type_node;
+  
+  if (mode == TYPE_MODE (complex_long_double_type_node))
+    return complex_long_double_type_node;
+
+  if (COMPLEX_MODE_P (mode))
+    return build_complex_type (type_for_mode (GET_MODE_UNIT_MODE (mode), 0));
+
   return 0;
 }
 
Index: c-typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-typeck.c,v
retrieving revision 1.40
diff -u -p -r1.40 c-typeck.c
--- c-typeck.c	1999/09/30 06:19:54	1.40
+++ c-typeck.c	1999/10/03 03:23:57
@@ -1,5 +1,5 @@
 /* Build expressions with type checking for C compiler.
-   Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91-97, 1998, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -216,13 +216,13 @@ common_type (t1, t2)
      required type.  */
   if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
     {
-      tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
-      tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+      tree subtype1 = code1 == COMPLEX_TYPE ? TYPE_COMPLEX_SUBTYPE (t1) : t1;
+      tree subtype2 = code2 == COMPLEX_TYPE ? TYPE_COMPLEX_SUBTYPE (t2) : t2;
       tree subtype = common_type (subtype1, subtype2);
 
-      if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+      if (code1 == COMPLEX_TYPE && TYPE_COMPLEX_SUBTYPE (t1) == subtype)
 	return build_type_attribute_variant (t1, attributes);
-      else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+      else if (code2 == COMPLEX_TYPE && TYPE_COMPLEX_SUBTYPE (t2) == subtype)
 	return build_type_attribute_variant (t2, attributes);
       else
 	return build_type_attribute_variant (build_complex_type (subtype),
@@ -2765,7 +2765,7 @@ build_unary_op (code, xarg, noconvert)
       if (TREE_CODE (arg) == COMPLEX_CST)
 	return TREE_REALPART (arg);
       else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-	return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+	return fold (build1 (REALPART_EXPR, TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg)), arg));
       else
 	return arg;
 
@@ -2773,7 +2773,7 @@ build_unary_op (code, xarg, noconvert)
       if (TREE_CODE (arg) == COMPLEX_CST)
 	return TREE_IMAGPART (arg);
       else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-	return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+	return fold (build1 (IMAGPART_EXPR, TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg)), arg));
       else
 	return convert (TREE_TYPE (arg), integer_zero_node);
       
Index: convert.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/convert.c,v
retrieving revision 1.7
diff -u -p -r1.7 convert.c
--- convert.c	1999/09/07 05:47:39	1.7
+++ convert.c	1999/10/03 03:23:58
@@ -1,5 +1,5 @@
 /* Utility routines for data type conversion for GNU C.
-   Copyright (C) 1987, 88, 91-95, 97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91-95, 97, 1998, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU C.
 
@@ -92,7 +92,7 @@ convert_to_real (type, expr)
     case COMPLEX_TYPE:
       return convert (type,
 		      fold (build1 (REALPART_EXPR,
-				    TREE_TYPE (TREE_TYPE (expr)), expr)));
+				    TYPE_COMPLEX_SUBTYPE (TREE_TYPE (expr)), expr)));
 
     case POINTER_TYPE:
     case REFERENCE_TYPE:
@@ -380,7 +380,7 @@ convert_to_integer (type, expr)
     case COMPLEX_TYPE:
       return convert (type,
 		      fold (build1 (REALPART_EXPR,
-				    TREE_TYPE (TREE_TYPE (expr)), expr)));
+				    TYPE_COMPLEX_SUBTYPE (TREE_TYPE (expr)), expr)));
 
     default:
       error ("aggregate value used where an integer was expected");
@@ -394,7 +394,7 @@ tree
 convert_to_complex (type, expr)
      tree type, expr;
 {
-  tree subtype = TREE_TYPE (type);
+  tree subtype = TYPE_COMPLEX_SUBTYPE (type);
   
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
@@ -408,28 +408,25 @@ convert_to_complex (type, expr)
 
     case COMPLEX_TYPE:
       {
-	tree elt_type = TREE_TYPE (TREE_TYPE (expr));
+	tree elt_type = TYPE_COMPLEX_SUBTYPE (TREE_TYPE (expr));
 
 	if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
 	  return expr;
 	else if (TREE_CODE (expr) == COMPLEX_EXPR)
-	  return fold (build (COMPLEX_EXPR,
-			      type,
+	  return fold (build (COMPLEX_EXPR, type,
 			      convert (subtype, TREE_OPERAND (expr, 0)),
 			      convert (subtype, TREE_OPERAND (expr, 1))));
 	else
 	  {
 	    expr = save_expr (expr);
-	    return
-	      fold (build (COMPLEX_EXPR,
-			   type, convert (subtype,
-					  fold (build1 (REALPART_EXPR,
-							TREE_TYPE (TREE_TYPE (expr)),
-							expr))),
-			   convert (subtype,
-				    fold (build1 (IMAGPART_EXPR,
-						  TREE_TYPE (TREE_TYPE (expr)),
-						  expr)))));
+	    elt_type = TYPE_COMPLEX_SUBTYPE (TREE_TYPE (expr));
+	    return fold (build (COMPLEX_EXPR, type,
+				convert (subtype,
+					 fold (build1 (REALPART_EXPR,
+						       elt_type, expr))),
+				convert (subtype,
+					 fold (build1 (IMAGPART_EXPR,
+						       elt_type, expr)))));
 	  }
       }
 
Index: dbxout.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/dbxout.c,v
retrieving revision 1.38
diff -u -p -r1.38 dbxout.c
--- dbxout.c	1999/09/23 12:36:04	1.38
+++ dbxout.c	1999/10/03 03:24:05
@@ -1,5 +1,5 @@
 /* Output dbx-format symbol table information from GNU compiler.
-   Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-97, 1998, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -1228,13 +1228,13 @@ dbxout_type (type, full, show_arg_types)
     case COMPLEX_TYPE:
       /* Differs from the REAL_TYPE by its new data type number */
 
-      if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+      if (TREE_CODE (TYPE_COMPLEX_SUBTYPE (type)) == REAL_TYPE)
 	{
 	  fprintf (asmfile, "r");
 	  dbxout_type_index (type);
 	  fputc (';', asmfile);
 	  fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
-		   int_size_in_bytes (TREE_TYPE (type)));
+		   int_size_in_bytes (TYPE_COMPLEX_SUBTYPE (type)));
 	  fputs (";0;", asmfile);
 	  CHARS (12);		/* The number is probably incorrect here.  */
 	}
@@ -2119,27 +2119,26 @@ dbxout_symbol_location (decl, type, suff
       letter = 'V';
       current_sym_addr = XEXP (XEXP (home, 0), 0);
     }
-  else if (GET_CODE (home) == CONCAT)
+  else if (GET_CODE (home) == RECORD_REGS)
     {
-      tree subtype = TREE_TYPE (type);
-
-      /* If the variable's storage is in two parts,
-	 output each as a separate stab with a modified name.  */
-      if (WORDS_BIG_ENDIAN)
-	dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 0));
-      else
-	dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 0));
-
-      /* Cast avoids warning in old compilers.  */
-      current_sym_code = (STAB_CODE_TYPE) 0;
-      current_sym_value = 0;
-      current_sym_addr = 0;
-      dbxout_prepare_symbol (decl);
+      int fi;
+      for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (home); fi++)
+	{
+	  rtx field = RECORD_REGS_FIELD (home, fi);
+	  tree field_decl = FIELD_REG_DECL (field);
 
-      if (WORDS_BIG_ENDIAN)
-	dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 1));
-      else
-	dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 1));
+	  if (fi > 0)
+	    {
+	      /* Cast avoids warning in old compilers.  */
+	      current_sym_code = (STAB_CODE_TYPE) 0;
+	      current_sym_value = 0;
+	      current_sym_addr = 0;
+	      dbxout_prepare_symbol (decl);
+	    }
+	  dbxout_symbol_location (decl, TREE_TYPE (field_decl),
+				  IDENTIFIER_POINTER (DECL_NAME (field_decl)),
+				  FIELD_REG_RTX (field));
+	}
       return;
     }
   else
@@ -2180,10 +2179,24 @@ dbxout_symbol_name (decl, suffix, letter
   char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   if (name == 0)
     name = "(anon)";
-  fprintf (asmfile, "%s \"%s%s:", ASM_STABS_OP, name,
-	   (suffix ? suffix : ""));
-
-  if (letter) putc (letter, asmfile);
+  fprintf (asmfile, "%s \"%s", ASM_STABS_OP, name);
+  if (suffix)
+    {
+      /* We should always use '.' to separate decl name and suffix,
+	 and gdb should be fixed to look for symbol names of the form
+	 `foo.bar', after finding that struct foo is not stored in
+	 memory, but rather has its fields in registers, and that
+	 `bar' is the name of such a field. */
+#ifndef NO_DOLLAR_IN_LABEL
+      putc ('$', asmfile);
+#else
+      putc ('.', asmfile);
+#endif
+      fputs (suffix, asmfile);
+    }
+  putc (':', asmfile);
+  if (letter)
+    putc (letter, asmfile);
 }
 
 static void
@@ -2502,7 +2515,7 @@ dbxout_reg_parms (parms)
 	    && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER)
 	  dbxout_symbol_location (parms, TREE_TYPE (parms),
 				  0, DECL_RTL (parms));
-	else if (GET_CODE (DECL_RTL (parms)) == CONCAT)
+	else if (RECORD_REGS_COMPLEX_P (DECL_RTL (parms)))
 	  dbxout_symbol_location (parms, TREE_TYPE (parms),
 				  0, DECL_RTL (parms));
 	/* Report parms that live in memory but not where they were passed.  */
Index: dwarf2out.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/dwarf2out.c,v
retrieving revision 1.118
diff -u -p -r1.118 dwarf2out.c
--- dwarf2out.c	1999/09/30 13:40:41	1.118
+++ dwarf2out.c	1999/10/03 03:24:31
@@ -2467,7 +2467,7 @@ static dw_loc_descr_ref reg_loc_descript
 static dw_loc_descr_ref based_loc_descr	PROTO((unsigned, long));
 static int is_based_loc			PROTO((rtx));
 static dw_loc_descr_ref mem_loc_descriptor PROTO((rtx, enum machine_mode mode));
-static dw_loc_descr_ref concat_loc_descriptor PROTO((rtx, rtx));
+static dw_loc_descr_ref record_regs_loc_descriptor PROTO((rtx));
 static dw_loc_descr_ref loc_descriptor	PROTO((rtx));
 static unsigned ceiling			PROTO((unsigned, unsigned));
 static tree field_type			PROTO((tree));
@@ -6218,7 +6218,7 @@ base_type_die (type)
       /* Dwarf2 doesn't know anything about complex ints, so use
 	 a user defined type for it.  */
     case COMPLEX_TYPE:
-      if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+      if (TREE_CODE (TYPE_COMPLEX_SUBTYPE (type)) == REAL_TYPE)
 	encoding = DW_ATE_complex_float;
       else
 	encoding = DW_ATE_lo_user;
@@ -6610,23 +6610,21 @@ mem_loc_descriptor (rtl, mode)
    This is typically a complex variable.  */
 
 static dw_loc_descr_ref
-concat_loc_descriptor (x0, x1)
-     register rtx x0, x1;
+record_regs_loc_descriptor (strux)
+     register rtx strux;
 {
   dw_loc_descr_ref cc_loc_result = NULL;
+  int fi;
 
-  if (!is_pseudo_reg (x0)
-      && (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0))))
-    add_loc_descr (&cc_loc_result, loc_descriptor (x0));
-  add_loc_descr (&cc_loc_result,
-	         new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0));
-
-  if (!is_pseudo_reg (x1)
-      && (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0))))
-    add_loc_descr (&cc_loc_result, loc_descriptor (x1));
-  add_loc_descr (&cc_loc_result,
-		 new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x1)), 0));
-
+  for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (strux); fi++)
+    {
+      rtx x = FIELD_REG_RTX (RECORD_REGS_FIELD (strux, fi));
+      if (!is_pseudo_reg (x)
+	  && (GET_CODE (x) != MEM || !is_pseudo_reg (XEXP (x, 0))))
+	add_loc_descr (&cc_loc_result, loc_descriptor (x));
+      add_loc_descr (&cc_loc_result,
+		     new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x)), 0));
+    }
   return cc_loc_result;
 }
 
@@ -6661,8 +6659,8 @@ loc_descriptor (rtl)
       loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
       break;
 
-    case CONCAT:
-      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
+    case RECORD_REGS:
+      loc_result = record_regs_loc_descriptor (rtl);
       break;
 
     default:
@@ -6872,11 +6870,17 @@ add_AT_location_description (die, attr_k
 
   if (is_pseudo_reg (rtl)
       || (GET_CODE (rtl) == MEM
-	  && is_pseudo_reg (XEXP (rtl, 0)))
-      || (GET_CODE (rtl) == CONCAT
-	  && is_pseudo_reg (XEXP (rtl, 0))
-	  && is_pseudo_reg (XEXP (rtl, 1))))
+	  && is_pseudo_reg (XEXP (rtl, 0))))
     return;
+  if (GET_CODE (rtl) == RECORD_REGS)
+    {
+      int fi;
+      for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (rtl); fi++)
+	if (!is_pseudo_reg (FIELD_REG_RTX (RECORD_REGS_FIELD (rtl, fi))))
+	  break;
+      if (fi == RECORD_REGS_NUM_FIELDS (rtl))
+	return;
+    }
 
   add_AT_loc (die, attr_kind, loc_descriptor (rtl));
 }
@@ -7211,7 +7215,7 @@ add_location_or_const_value_attribute (d
     case MEM:
     case REG:
     case SUBREG:
-    case CONCAT:
+    case RECORD_REGS:
       add_AT_location_description (die, DW_AT_location, rtl);
       break;
 
Index: dwarfout.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/dwarfout.c,v
retrieving revision 1.42
diff -u -p -r1.42 dwarfout.c
--- dwarfout.c	1999/09/07 02:36:27	1.42
+++ dwarfout.c	1999/10/03 03:24:54
@@ -2151,7 +2151,8 @@ sibling_attribute ()
 
 /* Output the form of location attributes suitable for whole variables and
    whole parameters.  Note that the location attributes for struct fields
-   are generated by the routine `data_member_location_attribute' below.  */
+   stored in memory are generated by the routine
+   `data_member_location_attribute' below.  */
 
 static void
 location_attribute (rtl)
@@ -2473,13 +2474,13 @@ location_or_const_value_attribute (decl)
       location_attribute (rtl);
       break;
 
-    case CONCAT:
-      /* ??? CONCAT is used for complex variables, which may have the real
-	 part stored in one place and the imag part stored somewhere else.
-	 DWARF1 has no way to describe a variable that lives in two different
-	 places, so we just describe where the first part lives, and hope that
-	 the second part is stored after it.  */
-      location_attribute (XEXP (rtl, 0));
+    case RECORD_REGS:
+      /* A RECORD_REGS rtx (e.g., complex variables) may have one part stored
+	 in one place and other parts stored elsewhere.  DWARF1 has no way to
+	 describe a variable that lives in mulitiple different places, so we
+	 just describe where the first part lives, and hope that subsequent
+	 parts are stored after it.  */
+      location_attribute (FIELD_REG_RTX (RECORD_REGS_FIELD (rtl, 0)));
       break;
 
     default:
Index: emit-rtl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/emit-rtl.c,v
retrieving revision 1.90
diff -u -p -r1.90 emit-rtl.c
--- emit-rtl.c	1999/09/23 20:34:19	1.90
+++ emit-rtl.c	1999/10/03 03:25:03
@@ -162,10 +162,12 @@ static rtx free_insn;
 #define last_filename (current_function->emit->x_last_filename)
 #define first_label_num (current_function->emit->x_first_label_num)
 
+static rtx gen_record_regs_rtx PROTO((tree));
 static rtx make_jump_insn_raw		PROTO((rtx));
 static rtx make_call_insn_raw		PROTO((rtx));
 static rtx find_line_note		PROTO((rtx));
 static void mark_sequence_stack         PROTO((struct sequence_stack *));
+
 
 /* There are some RTL codes that require special attention; the generation
    functions do the raw handling.  If you add to this list, modify
@@ -457,26 +459,13 @@ gen_reg_rtx (mode)
   if (no_new_pseudos)
     abort ();
 
-  if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-      || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
-    {
-      /* For complex modes, don't make a single pseudo.
-	 Instead, make a CONCAT of two pseudos.
-	 This allows noncontiguous allocation of the real and imaginary parts,
-	 which makes much better code.  Besides, allocating DCmode
-	 pseudos overstrains reload on some machines like the 386.  */
-      rtx realpart, imagpart;
-      int size = GET_MODE_UNIT_SIZE (mode);
-      enum machine_mode partmode
-	= mode_for_size (size * BITS_PER_UNIT,
-			 (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-			  ? MODE_FLOAT : MODE_INT),
-			 0);
-
-      realpart = gen_reg_rtx (partmode);
-      imagpart = gen_reg_rtx (partmode);
-      return gen_rtx_CONCAT (mode, realpart, imagpart);
-    }
+  /* For complex modes, don't make a single pseudo.  Instead, make
+     a RECORD_REGS of two FIELD_REGs containing the pseudos.  This allows
+     noncontiguous allocation of the real and imaginary parts,
+     which makes much better code.  Besides, allocating DCmode
+     pseudos overstrains reload on some machines like the 386.  */
+  if (COMPLEX_MODE_P (mode))
+    return gen_record_regs_rtx (TREE_TYPE (type_for_mode (mode, 0)));
 
   /* Make sure regno_pointer_flag and regno_reg_rtx are large
      enough to have an element for this pseudo reg number.  */
@@ -507,16 +496,50 @@ gen_reg_rtx (mode)
   return val;
 }
 
-/* Identify REG (which may be a CONCAT) as a user register.  */
+/* Generate a RECORD_REGS rtx containing fields of REG rtxes whose modes
+   match those of the fields in the record type TYPE.  This process is
+   not (yet) recursive: the record type should not contain fields that
+   are record types.  Only field decls with integral or floating modes
+   are recognized.  */
+
+static rtx
+gen_record_regs_rtx (type)
+     tree type;
+{
+  tree field;
+  int n = list_length (TYPE_FIELDS (type));
+  rtx *vector0 = (rtx *) alloca (n * sizeof (rtx));
+  rtx *vector = vector0;
+  
+  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+    {
+      if (TREE_CODE (field) == FIELD_DECL)
+	{
+	  enum machine_mode mode = DECL_MODE (field);
+	  if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
+	    abort ();
+	  if (!INTEGRAL_MODE_P (mode) && !FLOAT_MODE_P (mode))
+	    abort ();
+	  *vector++ = gen_rtx_FIELD_REG (mode, gen_reg_rtx (mode), field);
+	}
+    }
+  if (vector == vector0)
+    abort ();
+  return gen_rtx_RECORD_REGS (TYPE_MODE (type),
+			      gen_rtvec_v (vector - vector0, vector0), type);
+}
 
+/* Identify REG (which may be a RECORD_REGS) as a user register.  */
+
 void
 mark_user_reg (reg)
      rtx reg;
 {
-  if (GET_CODE (reg) == CONCAT)
+  if (GET_CODE (reg) == RECORD_REGS)
     {
-      REG_USERVAR_P (XEXP (reg, 0)) = 1;
-      REG_USERVAR_P (XEXP (reg, 1)) = 1;
+      int fi;
+      for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (reg); fi++)
+	REG_USERVAR_P (FIELD_REG_RTX (RECORD_REGS_FIELD (reg, fi))) = 1;
     }
   else if (GET_CODE (reg) == REG)
     REG_USERVAR_P (reg) = 1;
@@ -872,8 +895,9 @@ gen_realpart (mode, x)
      enum machine_mode mode;
      register rtx x;
 {
-  if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode)
-    return XEXP (x, 0);
+  if (RECORD_REGS_COMPLEX_P (x)
+      && GET_MODE (FIELD_REG_RTX (RECORD_REGS_COMPLEX_REAL (x))) == mode)
+    return FIELD_REG_RTX (RECORD_REGS_COMPLEX_REAL (x));
   else if (WORDS_BIG_ENDIAN
 	   && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
 	   && REG_P (x)
@@ -893,8 +917,9 @@ gen_imagpart (mode, x)
      enum machine_mode mode;
      register rtx x;
 {
-  if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode)
-    return XEXP (x, 1);
+  if (RECORD_REGS_COMPLEX_P (x)
+      && GET_MODE (FIELD_REG_RTX (RECORD_REGS_COMPLEX_IMAG (x))) == mode)
+    return FIELD_REG_RTX (RECORD_REGS_COMPLEX_IMAG (x));
   else if (WORDS_BIG_ENDIAN)
     return gen_lowpart (mode, x);
   else if (!WORDS_BIG_ENDIAN
@@ -1173,14 +1198,17 @@ operand_subword (op, i, validate_address
     }
   else if (GET_CODE (op) == SUBREG)
     return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
-  else if (GET_CODE (op) == CONCAT)
+  else if (RECORD_REGS_COMPLEX_P (op))
     {
       int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
       if (i < partwords)
-	return operand_subword (XEXP (op, 0), i, validate_address, mode);
-      return operand_subword (XEXP (op, 1), i - partwords,
-			      validate_address, mode);
+	return operand_subword (FIELD_REG_RTX (RECORD_REGS_COMPLEX_REAL (op)),
+				i, validate_address, mode);
+      return operand_subword (FIELD_REG_RTX (RECORD_REGS_COMPLEX_IMAG (op)),
+			      i - partwords, validate_address, mode);
     }
+  else if (GET_CODE (op) == RECORD_REGS)
+    abort ();
 
   /* Form a new MEM at the requested address.  */
   if (GET_CODE (op) == MEM)
Index: expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.174
diff -u -p -r1.174 expr.c
--- expr.c	1999/09/23 11:34:48	1.174
+++ expr.c	1999/10/03 03:25:33
@@ -1936,15 +1936,21 @@ emit_group_load (dst, orig_src, ssize, a
 					  plus_constant (XEXP (src, 0),
 							 bytepos)));
 	}
-      else if (GET_CODE (src) == CONCAT)
+      else if (GET_CODE (src) == RECORD_REGS)
 	{
-	  if (bytepos == 0
-	      && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
-	    tmps[i] = XEXP (src, 0);
-	  else if (bytepos == GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
-		   && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1))))
-	    tmps[i] = XEXP (src, 1);
-	  else
+	  int fi;
+	  for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (src); fi++)
+	    {
+	      rtx field = RECORD_REGS_FIELD (src, fi);
+	      tree field_decl = FIELD_REG_DECL (field);
+	      if (FIELD_REG_BYTE_OFFSET (field_decl) == bytepos
+		  && TYPE_SIZE_UNIT (TREE_TYPE (field_decl)) == bytelen)
+		{
+		  tmps[i] = FIELD_REG_RTX (field);
+		  break;
+		}
+	    }
+	  if (fi == RECORD_REGS_NUM_FIELDS (src))
 	    abort ();
 	}
       else
@@ -2592,11 +2598,7 @@ emit_move_insn_1 (x, y)
 
   /* Expand complex moves by moving real part and imag part, if possible.  */
   else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
-	   && BLKmode != (submode = mode_for_size ((GET_MODE_UNIT_SIZE (mode)
-						    * BITS_PER_UNIT),
-						   (class == MODE_COMPLEX_INT
-						    ? MODE_INT : MODE_FLOAT),
-						   0))
+	   && BLKmode != (submode = GET_MODE_UNIT_MODE (mode))
 	   && (mov_optab->handlers[(int) submode].insn_code
 	       != CODE_FOR_nothing))
     {
@@ -8077,7 +8079,7 @@ expand_expr (exp, target, tmode, modifie
 	    }
 
 	  else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
-		   || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
+		   || GET_CODE (op0) == RECORD_REGS || GET_CODE (op0) == ADDRESSOF)
 	    {
 	      /* If this object is in a register, it must be not
 		 be BLKmode.  */
@@ -8132,7 +8134,7 @@ expand_expr (exp, target, tmode, modifie
     /* COMPLEX type for Extended Pascal & Fortran  */
     case COMPLEX_EXPR:
       {
-	enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+	enum machine_mode mode = TYPE_MODE (TYPE_COMPLEX_SUBTYPE (TREE_TYPE (exp)));
 	rtx insns;
 
 	/* Get the rtx code of the operands.  */
@@ -8152,10 +8154,10 @@ expand_expr (exp, target, tmode, modifie
 	end_sequence ();
 
 	/* Complex construction should appear as a single unit.  */
-	/* If TARGET is a CONCAT, we got insns like RD = RS, ID = IS,
+	/* If TARGET is a RECORD_REGS, we got insns like RD = RS, ID = IS,
 	   each with a separate pseudo as destination.
 	   It's not correct for flow to treat them as a unit.  */
-	if (GET_CODE (target) != CONCAT)
+	if (GET_CODE (target) != RECORD_REGS)
 	  emit_no_conflict_block (insns, target, op0, op1, NULL_RTX);
 	else
 	  emit_insns (insns);
@@ -8173,7 +8175,7 @@ expand_expr (exp, target, tmode, modifie
 
     case CONJ_EXPR:
       {
-	enum machine_mode partmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+	enum machine_mode partmode = TYPE_MODE (TYPE_COMPLEX_SUBTYPE (TREE_TYPE (exp)));
 	rtx imag_t;
 	rtx insns;
 	
@@ -8198,10 +8200,10 @@ expand_expr (exp, target, tmode, modifie
 	end_sequence ();
 
 	/* Conjugate should appear as a single unit 
-	   If TARGET is a CONCAT, we got insns like RD = RS, ID = - IS,
+	   If TARGET is a RECORD_REGS, we got insns like RD = RS, ID = - IS,
 	   each with a separate pseudo as destination.
 	   It's not correct for flow to treat them as a unit.  */
-	if (GET_CODE (target) != CONCAT)
+	if (GET_CODE (target) != RECORD_REGS)
 	  emit_no_conflict_block (insns, target, op0, NULL_RTX, NULL_RTX);
 	else
 	  emit_insns (insns);
@@ -8919,17 +8921,17 @@ do_jump (exp, if_false_label, if_true_la
 	       (build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp),
 		       fold (build (EQ_EXPR, TREE_TYPE (exp),
 				    fold (build1 (REALPART_EXPR,
-						  TREE_TYPE (inner_type),
+						  TYPE_COMPLEX_SUBTYPE (inner_type),
 						  exp0)),
 				    fold (build1 (REALPART_EXPR,
-						  TREE_TYPE (inner_type),
+						  TYPE_COMPLEX_SUBTYPE (inner_type),
 						  exp1)))),
 		       fold (build (EQ_EXPR, TREE_TYPE (exp),
 				    fold (build1 (IMAGPART_EXPR,
-						  TREE_TYPE (inner_type),
+						  TYPE_COMPLEX_SUBTYPE (inner_type),
 						  exp0)),
 				    fold (build1 (IMAGPART_EXPR,
-						  TREE_TYPE (inner_type),
+						  TYPE_COMPLEX_SUBTYPE (inner_type),
 						  exp1)))))),
 	       if_false_label, if_true_label);
 	  }
@@ -8959,17 +8961,17 @@ do_jump (exp, if_false_label, if_true_la
 	       (build (TRUTH_ORIF_EXPR, TREE_TYPE (exp),
 		       fold (build (NE_EXPR, TREE_TYPE (exp),
 				    fold (build1 (REALPART_EXPR,
-						  TREE_TYPE (inner_type),
+						  TYPE_COMPLEX_SUBTYPE (inner_type),
 						  exp0)),
 				    fold (build1 (REALPART_EXPR,
-						  TREE_TYPE (inner_type),
+						  TYPE_COMPLEX_SUBTYPE (inner_type),
 						  exp1)))),
 		       fold (build (NE_EXPR, TREE_TYPE (exp),
 				    fold (build1 (IMAGPART_EXPR,
-						  TREE_TYPE (inner_type),
+						  TYPE_COMPLEX_SUBTYPE (inner_type),
 						  exp0)),
 				    fold (build1 (IMAGPART_EXPR,
-						  TREE_TYPE (inner_type),
+						  TYPE_COMPLEX_SUBTYPE (inner_type),
 						  exp1)))))),
 	       if_false_label, if_true_label);
 	  }
Index: fold-const.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/fold-const.c,v
retrieving revision 1.76
diff -u -p -r1.76 fold-const.c
--- fold-const.c	1999/09/20 17:12:03	1.76
+++ fold-const.c	1999/10/03 03:25:48
@@ -4714,12 +4714,12 @@ fold (expr) 
 	return build (COMPLEX_EXPR, TREE_TYPE (arg0),
 		      TREE_OPERAND (arg0, 0),
 		      fold (build1 (NEGATE_EXPR,
-				    TREE_TYPE (TREE_TYPE (arg0)),
+				    TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg0)),
 				    TREE_OPERAND (arg0, 1))));
       else if (TREE_CODE (arg0) == COMPLEX_CST)
 	return build_complex (type, TREE_OPERAND (arg0, 0),
 			      fold (build1 (NEGATE_EXPR,
-					    TREE_TYPE (TREE_TYPE (arg0)),
+					    TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg0)),
 					    TREE_OPERAND (arg0, 1))));
       else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
 	return fold (build (TREE_CODE (arg0), type,
@@ -6130,7 +6130,7 @@ fold (expr) 
 	      || TREE_CODE (arg0) == COMPLEX_CST
 	      || TREE_CODE (arg1) == COMPLEX_CST))
 	{
-	  tree subtype = TREE_TYPE (TREE_TYPE (arg0));
+	  tree subtype = TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg0));
 	  tree real0, imag0, real1, imag1;
 
 	  arg0 = save_expr (arg0);
Index: function.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/function.c,v
retrieving revision 1.118
diff -u -p -r1.118 function.c
--- function.c	1999/09/20 09:59:47	1.118
+++ function.c	1999/10/03 03:26:06
@@ -241,6 +241,7 @@ static struct fixup_replacement
   *find_fixup_replacement	PROTO((struct fixup_replacement **, rtx));
 static void fixup_var_refs_insns PROTO((rtx, enum machine_mode, int,
 					rtx, int, struct hash_table *));
+static int field_rtx_matches_var (rtx, rtx);
 static void fixup_var_refs_1	PROTO((rtx, enum machine_mode, rtx *, rtx,
 				       struct fixup_replacement **));
 static rtx fixup_memory_subreg	PROTO((rtx, rtx, int));
@@ -1292,41 +1293,40 @@ put_var_into_stack (decl)
 			    TREE_USED (decl) || DECL_INITIAL (decl) != 0,
 			    0);
     }
-  else if (GET_CODE (reg) == CONCAT)
+  else if (GET_CODE (reg) == RECORD_REGS)
     {
-      /* A CONCAT contains two pseudos; put them both in the stack.
-	 We do it so they end up consecutive.  */
-      enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
-      tree part_type = TREE_TYPE (TREE_TYPE (decl));
+      /* ??? Putting a RECORD_REGS onto the stack piecemeal works for
+	 simple structures with uniform word alignment.  For anything
+	 hairier, we should allocate stack space for the entire RECORD_REGS
+	 first, then compute stack addresses for moves using the
+	 RECORD_TYPE's FIELD_DECL offsets. */
+      int fi;
+      rtx field0_rtx;
 #ifdef FRAME_GROWS_DOWNWARD
-      /* Since part 0 should have a lower address, do it second.  */
-      put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
-			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
-			  TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-			  0);
-      put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
-			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
-			  TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-			  0);
+      for (fi = RECORD_REGS_NUM_FIELDS (reg) - 1; fi >= 0; fi--)
 #else
-      put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
-			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
-			  TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-			  0);
-      put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
-			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
-			  TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-			  0);
+      for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (reg); fi++)
 #endif
+	{
+	  rtx field = RECORD_REGS_FIELD (reg, fi);
+	  tree field_decl = FIELD_REG_DECL (field);
+	  rtx field_rtx = FIELD_REG_RTX (field);
+	  put_reg_into_stack (function, field_rtx, TREE_TYPE (field_decl),
+			      GET_MODE (field_rtx), DECL_MODE (field_decl),
+			      TREE_SIDE_EFFECTS (decl), 0,
+			      TREE_USED (decl) || DECL_INITIAL (decl) != 0,
+			      0);
+	}
 
-      /* Change the CONCAT into a combined MEM for both parts.  */
+      /* Change the RECORD_REGS into a combined MEM for both parts.  */
+      field0_rtx = FIELD_REG_RTX (RECORD_REGS_FIELD (reg, 0));
       PUT_CODE (reg, MEM);
-      MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));
+      MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (field0_rtx);
       MEM_ALIAS_SET (reg) = get_alias_set (decl);
 
-      /* The two parts are in memory order already.
-	 Use the lower parts address as ours.  */
-      XEXP (reg, 0) = XEXP (XEXP (reg, 0), 0);
+      /* All parts are in memory order already.
+	 Use the lowest part's address as ours.  */
+      XEXP (reg, 0) = XEXP (field0_rtx, 0);
       /* Prevent sharing of rtl that might lose.  */
       if (GET_CODE (XEXP (reg, 0)) == PLUS)
 	XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
@@ -1530,9 +1530,8 @@ fixup_var_refs_insns (var, promoted_mode
 	     and REG_RETVAL notes too.  */
  	  if (GET_CODE (PATTERN (insn)) == CLOBBER
 	      && (XEXP (PATTERN (insn), 0) == var
-		  || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT
-		      && (XEXP (XEXP (PATTERN (insn), 0), 0) == var
-			  || XEXP (XEXP (PATTERN (insn), 0), 1) == var))))
+		  || (GET_CODE (XEXP (PATTERN (insn), 0)) == RECORD_REGS
+		      && field_rtx_matches_var (XEXP (PATTERN (insn), 0), var))))
 	    {
 	      if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
 		/* The REG_LIBCALL note will go away since we are going to
@@ -1702,6 +1701,21 @@ fixup_var_refs_insns (var, promoted_mode
 	insn = NULL_RTX;
     }
 }
+
+/* return nonzero of VAR is the rtx of any field in STRUX.  */
+
+static int
+field_rtx_matches_var (strux, var)
+     rtx strux;
+     rtx var;
+{
+  int i;
+  for (i = 0; i < RECORD_REGS_NUM_FIELDS (strux); i++)
+    if (FIELD_REG_RTX (RECORD_REGS_FIELD (strux, i)) == var)
+      return 1;
+  return 0;
+}
+
 
 /* VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE.
    See if the rtx expression at *LOC in INSN needs to be changed.  
@@ -4412,7 +4426,7 @@ assign_parms (fndecl)
 	     may need to do it in a wider mode.  */
 
 	  register rtx parmreg;
-	  int regno, regnoi = 0, regnor = 0;
+	  int regno;
 
 	  unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
 
@@ -4554,11 +4568,20 @@ assign_parms (fndecl)
 	  /* In any case, record the parm's desired stack location
 	     in case we later discover it must live in the stack. 
 
-	     If it is a COMPLEX value, store the stack location for both
-	     halves.  */
+	     If it is a RECORD_REGS value, store the stack location for
+	     all fields.  */
 
-	  if (GET_CODE (parmreg) == CONCAT)
-	    regno = MAX (REGNO (XEXP (parmreg, 0)), REGNO (XEXP (parmreg, 1)));
+	  if (GET_CODE (parmreg) == RECORD_REGS)
+	    {
+	      int fi;
+	      regno = 0;
+	      for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (parmreg); fi++)
+		{
+		  int regnox = REGNO (FIELD_REG_RTX (RECORD_REGS_FIELD (parmreg, fi)));
+		  if (regnox > regno)
+		    regno = regnox;
+		}
+	    }
 	  else
 	    regno = REGNO (parmreg);
 
@@ -4578,24 +4601,25 @@ assign_parms (fndecl)
 	      parm_reg_stack_loc = new;
 	    }
 
-	  if (GET_CODE (parmreg) == CONCAT)
+	  if (GET_CODE (parmreg) == RECORD_REGS)
 	    {
-	      enum machine_mode submode = GET_MODE (XEXP (parmreg, 0));
-
-	      regnor = REGNO (gen_realpart (submode, parmreg));
-	      regnoi = REGNO (gen_imagpart (submode, parmreg));
-
-	      if (stack_parm != 0)
+	      int fi;
+	      for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (parmreg); fi++)
 		{
-		  parm_reg_stack_loc[regnor]
-		    = gen_realpart (submode, stack_parm);
-		  parm_reg_stack_loc[regnoi]
-		    = gen_imagpart (submode, stack_parm);
-		}
-	      else
-		{
-		  parm_reg_stack_loc[regnor] = 0;
-		  parm_reg_stack_loc[regnoi] = 0;
+		  rtx field = RECORD_REGS_FIELD (parmreg, fi);
+		  int regnox = REGNO (FIELD_REG_RTX (field));
+		  if (GET_CODE (stack_parm) != MEM)
+		    abort ();
+		  if (stack_parm)
+		    {
+		      tree field_decl = FIELD_REG_DECL (field);
+		      parm_reg_stack_loc[regnox]
+			= change_address (stack_parm, DECL_MODE (field_decl),
+					  plus_constant (XEXP (stack_parm, 0),
+							 FIELD_REG_BYTE_OFFSET (field_decl)));
+		    }
+		  else
+		    parm_reg_stack_loc[regnox] = 0;
 		}
 	    }
 	  else
@@ -4619,25 +4643,26 @@ assign_parms (fndecl)
 	      rtx sinsn, set;
 
 	      /* Mark complex types separately.  */
-	      if (GET_CODE (parmreg) == CONCAT)
+	      if (GET_CODE (parmreg) == RECORD_REGS)
 		/* Scan backwards for the set of the real and
 		   imaginary parts.  */
 		for (sinsn = linsn; sinsn != 0;
 		     sinsn = prev_nonnote_insn (sinsn))
 		  {
 		    set = single_set (sinsn);
-		    if (set != 0
-			&& SET_DEST (set) == regno_reg_rtx [regnoi])
-		      REG_NOTES (sinsn)
-			= gen_rtx_EXPR_LIST (REG_EQUIV,
-					     parm_reg_stack_loc[regnoi],
-					     REG_NOTES (sinsn));
-		    else if (set != 0
-			     && SET_DEST (set) == regno_reg_rtx [regnor])
-		      REG_NOTES (sinsn)
-			= gen_rtx_EXPR_LIST (REG_EQUIV,
-					     parm_reg_stack_loc[regnor],
-					     REG_NOTES (sinsn));
+		    if (set)
+		      {
+			int fi;
+			for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (parmreg); fi++)
+			  {
+			    int regnox = REGNO (FIELD_REG_RTX (RECORD_REGS_FIELD (parmreg, fi)));
+			    if (SET_DEST (set) == regno_reg_rtx [regnox])
+			      REG_NOTES (sinsn)
+				= gen_rtx_EXPR_LIST (REG_EQUIV,
+						     parm_reg_stack_loc[regnox],
+						     REG_NOTES (sinsn));
+			  }
+		      }
 		  }
 	      else if ((set = single_set (linsn)) != 0
 		       && SET_DEST (set) == parmreg)
Index: integrate.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/integrate.c,v
retrieving revision 1.69
diff -u -p -r1.69 integrate.c
--- integrate.c	1999/09/20 09:59:48	1.69
+++ integrate.c	1999/10/03 03:26:13
@@ -272,15 +272,15 @@ initialize_for_inline (fndecl)
 
       if (GET_CODE (p) == REG)
 	parmdecl_map[REGNO (p)] = parms;
-      else if (GET_CODE (p) == CONCAT)
+      else if (GET_CODE (p) == RECORD_REGS)
 	{
-	  rtx preal = gen_realpart (GET_MODE (XEXP (p, 0)), p);
-	  rtx pimag = gen_imagpart (GET_MODE (preal), p);
-
-	  if (GET_CODE (preal) == REG)
-	    parmdecl_map[REGNO (preal)] = parms;
-	  if (GET_CODE (pimag) == REG)
-	    parmdecl_map[REGNO (pimag)] = parms;
+	  int fi;
+	  for (fi = 0; fi < RECORD_REGS_NUM_FIELDS (p); fi++)
+	    {
+	      rtx field = FIELD_REG_RTX (RECORD_REGS_FIELD (p, fi));
+	      if (GET_CODE (field) == REG)
+		parmdecl_map[REGNO (field)] = parms;
+	    }
 	}
 
       /* This flag is cleared later
@@ -796,10 +796,10 @@ expand_inline_function (fndecl, parms, t
 	}
       else if (GET_CODE (loc) == REG)
 	process_reg_param (map, loc, copy);
-      else if (GET_CODE (loc) == CONCAT)
+      else if (RECORD_REGS_COMPLEX_P (loc))
 	{
-	  rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc);
-	  rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc);
+	  rtx locreal = FIELD_REG_RTX (RECORD_REGS_COMPLEX_REAL (loc));
+	  rtx locimag = FIELD_REG_RTX (RECORD_REGS_COMPLEX_IMAG (loc));
 	  rtx copyreal = gen_realpart (GET_MODE (locreal), copy);
 	  rtx copyimag = gen_imagpart (GET_MODE (locimag), copy);
 
@@ -1605,10 +1605,11 @@ copy_rtx_and_substitute (orig, map)
       if (GET_CODE (copy) == SUBREG)
 	return gen_rtx_SUBREG (GET_MODE (orig), SUBREG_REG (copy),
 			       SUBREG_WORD (orig) + SUBREG_WORD (copy));
-      else if (GET_CODE (copy) == CONCAT)
+      else if (RECORD_REGS_COMPLEX_P (copy))
 	{
-	  rtx retval = subreg_realpart_p (orig) ? XEXP (copy, 0) : XEXP (copy, 1);
-
+	  rtx retval = (subreg_realpart_p (orig)
+			? FIELD_REG_RTX (RECORD_REGS_COMPLEX_REAL (copy))
+			: FIELD_REG_RTX (RECORD_REGS_COMPLEX_IMAG (copy)));
 	  if (GET_MODE (retval) == GET_MODE (orig))
 	    return retval;
 	  else
@@ -1617,6 +1618,8 @@ copy_rtx_and_substitute (orig, map)
 				    (GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (orig)))
 				     / (unsigned) UNITS_PER_WORD)));
 	}
+      else if (GET_CODE (copy) == RECORD_REGS)
+	abort ();
       else
 	return gen_rtx_SUBREG (GET_MODE (orig), copy,
 			       SUBREG_WORD (orig));
Index: machmode.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/machmode.h,v
retrieving revision 1.16
diff -u -p -r1.16 machmode.h
--- machmode.h	1999/09/21 22:31:29	1.16
+++ machmode.h	1999/10/03 03:26:13
@@ -1,5 +1,5 @@
 /* Machine mode definitions for GNU C-Compiler; included by rtl.h and tree.h.
-   Copyright (C) 1991, 1993, 1994, 1996, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1991, 1993, 1994, 1996, 1998, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -80,6 +80,11 @@ extern const int mode_unit_size[];
 #define GET_MODE_NUNITS(MODE)  \
   ((GET_MODE_UNIT_SIZE ((MODE)) == 0) ? 0 \
    : (GET_MODE_SIZE ((MODE)) / GET_MODE_UNIT_SIZE ((MODE))))
+
+#define GET_MODE_UNIT_MODE(MODE)				\
+  mode_for_size (GET_MODE_UNIT_SIZE (MODE) * BITS_PER_UNIT,	\
+		 (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT	\
+		  ? MODE_FLOAT : MODE_INT), 0)
 
 /* Get the size in bits of an object of mode MODE.  */
 
Index: optabs.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/optabs.c,v
retrieving revision 1.53
diff -u -p -r1.53 optabs.c
--- optabs.c	1999/09/24 08:40:11	1.53
+++ optabs.c	1999/10/03 03:26:22
@@ -1433,10 +1433,7 @@ expand_binop (mode, binoptab, op0, op1, 
       int ok = 0;
 
       /* Find the correct mode for the real and imaginary parts */
-      enum machine_mode submode
-	= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
-			 class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
-			 0);
+      enum machine_mode submode = GET_MODE_UNIT_MODE (mode);
 
       if (submode == BLKmode)
 	abort ();
@@ -2125,10 +2122,7 @@ expand_unop (mode, unoptab, op0, target,
       rtx seq;
 
       /* Find the correct mode for the real and imaginary parts */
-      enum machine_mode submode
-	= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
-			 class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
-			 0);
+      enum machine_mode submode = GET_MODE_UNIT_MODE (mode);
 
       if (submode == BLKmode)
 	abort ();
@@ -2343,10 +2337,7 @@ expand_complex_abs (mode, op0, target, u
   rtx pat;
 
   /* Find the correct mode for the real and imaginary parts.  */
-  enum machine_mode submode
-    = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
-		     class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
-		     0);
+  enum machine_mode submode = GET_MODE_UNIT_MODE (mode);
 
   if (submode == BLKmode)
     abort ();
Index: rtl.def
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.def,v
retrieving revision 1.24
diff -u -p -r1.24 rtl.def
--- rtl.def	1999/09/15 03:28:12	1.24
+++ rtl.def	1999/10/03 03:26:26
@@ -573,11 +573,16 @@ DEF_RTL_EXPR(SUBREG, "subreg", "ei", 'x'
 
 DEF_RTL_EXPR(STRICT_LOW_PART, "strict_low_part", "e", 'x')
 
-/* (CONCAT a b) represents the virtual concatenation of a and b
-   to make a value that has as many bits as a and b put together.
-   This is used for complex values.  Normally it appears only
-   in DECL_RTLs and during RTL generation, but not in the insn chain.  */
-DEF_RTL_EXPR(CONCAT, "concat", "ee", 'o')
+/* Represent a record type as a collection of pseudo registers
+   representing individual fields.
+   operand 0: a vector of FIELD_REGs.
+   operand 1: the RECORD_TYPE tree. */
+DEF_RTL_EXPR (RECORD_REGS, "record_regs", "Et", 'o')
+
+/* A record field.
+   operand 0: a pseudo register, or a MEM if the field's address is taken.
+   operand 1: the field's FIELD_DECL */
+DEF_RTL_EXPR (FIELD_REG, "field_reg", "et", 'o')
 
 /* A memory location; operand is the address.  Can be nested inside a
    VOLATILE.  The second operand is the alias set to which this MEM
Index: rtl.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.h,v
retrieving revision 1.139
diff -u -p -r1.139 rtl.h
--- rtl.h	1999/09/28 06:28:33	1.139
+++ rtl.h	1999/10/03 03:26:32
@@ -675,6 +675,24 @@ extern const char * const note_insn_name
 #define ASM_OPERANDS_SOURCE_FILE(RTX) XCSTR ((RTX), 5, ASM_OPERANDS)
 #define ASM_OPERANDS_SOURCE_LINE(RTX) XCINT ((RTX), 6, ASM_OPERANDS)
 
+/* Macros to access the slots of a RECORD_REGS rtx.  */
+#define RECORD_REGS_FIELD_VEC(RTX) XCVEC ((RTX), 0, RECORD_REGS)
+#define RECORD_REGS_FIELD(RTX, I) RTVEC_ELT (RECORD_REGS_FIELD_VEC (RTX), (I))
+#define RECORD_REGS_NUM_FIELDS(RTX) GET_NUM_ELEM (RECORD_REGS_FIELD_VEC (RTX))
+#define RECORD_REGS_TYPE(RTX) XCTREE (RTX, 1, RECORD_REGS)
+
+/* Macros to access a RECORD_REGS complex rtx, which
+   replaces the old CONCAT rtx.  */
+#define RECORD_REGS_COMPLEX_REAL(RTX) RECORD_REGS_FIELD (RTX, 0)
+#define RECORD_REGS_COMPLEX_IMAG(RTX) RECORD_REGS_FIELD (RTX, 1)
+#define RECORD_REGS_COMPLEX_P(RTX) (GET_CODE (RTX) == RECORD_REGS \
+			       && COMPLEX_MODE_P (GET_MODE (RTX)))
+
+/* Macros to access the slots of a FIELD rtx.  */
+#define FIELD_REG_RTX(RTX) XCEXP ((RTX), 0, FIELD_REG)
+#define FIELD_REG_DECL(RTX) XCTREE ((RTX), 1, FIELD_REG)
+#define FIELD_REG_BYTE_OFFSET(RTX) (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (RTX)) / BITS_PER_UNIT)
+
 /* For a MEM rtx, 1 if it's a volatile reference.
    Also in an ASM_OPERANDS rtx.  */
 #define MEM_VOLATILE_P(RTX) ((RTX)->volatil)
Index: stmt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/stmt.c,v
retrieving revision 1.99
diff -u -p -r1.99 stmt.c
--- stmt.c	1999/09/24 01:14:54	1.99
+++ stmt.c	1999/10/03 03:26:51
@@ -1690,7 +1690,7 @@ expand_asm_operands (string, outputs, in
 				  op);
 	  else if (GET_CODE (op) == REG
 		   || GET_CODE (op) == SUBREG
-		   || GET_CODE (op) == CONCAT)
+		   || GET_CODE (op) == RECORD_REGS)
 	    {
 	      tree type = TREE_TYPE (TREE_VALUE (tail));
 	      rtx memloc = assign_temp (type, 1, 1, 1);
Index: stor-layout.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/stor-layout.c,v
retrieving revision 1.33
diff -u -p -r1.33 stor-layout.c
--- stor-layout.c	1999/09/26 18:13:28	1.33
+++ stor-layout.c	1999/10/03 03:26:53
@@ -1,5 +1,5 @@
 /* C-compiler utilities for types and variables storage layout
-   Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-97, 1998, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -757,10 +757,10 @@ layout_type (type)
       break;
 
     case COMPLEX_TYPE:
-      TREE_UNSIGNED (type) = TREE_UNSIGNED (TREE_TYPE (type));
+      TREE_UNSIGNED (type) = TREE_UNSIGNED (TYPE_COMPLEX_SUBTYPE (type));
       TYPE_MODE (type)
-	= mode_for_size (2 * TYPE_PRECISION (TREE_TYPE (type)),
-			 (TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
+	= mode_for_size (2 * TYPE_PRECISION (TYPE_COMPLEX_SUBTYPE (type)),
+			 (TREE_CODE (TYPE_COMPLEX_SUBTYPE (type)) == INTEGER_TYPE
 			  ? MODE_COMPLEX_INT : MODE_COMPLEX_FLOAT),
 			 0);
       TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)), 0L);
Index: tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.c,v
retrieving revision 1.93
diff -u -p -r1.93 tree.c
--- tree.c	1999/09/22 21:37:20	1.93
+++ tree.c	1999/10/03 03:40:26
@@ -273,6 +273,7 @@ static void set_type_quals PROTO((tree, 
 static void append_random_chars PROTO((char *));
 static void build_real_from_int_cst_1 PROTO((PTR));
 static void mark_type_hash PROTO ((void *));
+static int record_types_equal PROTO ((tree, tree));
 static void fix_sizetype PROTO ((tree));
 
 /* If non-null, a language specific helper for unsave_expr_now. */
@@ -3693,7 +3694,8 @@ type_hash_lookup (hashcode, type)
   for (h = type_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
     if (h->hashcode == hashcode
 	&& TREE_CODE (h->type) == TREE_CODE (type)
-	&& TREE_TYPE (h->type) == TREE_TYPE (type)
+	&& (TREE_TYPE (h->type) == TREE_TYPE (type)
+	    || record_types_equal (TREE_TYPE (h->type), TREE_TYPE (type)))
         && attribute_list_equal (TYPE_ATTRIBUTES (h->type),
 				   TYPE_ATTRIBUTES (type))
 	&& TYPE_ALIGN (h->type) == TYPE_ALIGN (type)
@@ -4427,31 +4429,66 @@ build_offset_type (basetype, type)
   return t;
 }
 
+/* Compare two record types for structural equivalence.  This function
+   is purpose-built for the RECORD_TYPE associated with COMPLEX_TYPE.  */
+
+static int
+record_types_equal (t1, t2)
+     tree t1, t2;
+{
+  if (TREE_CODE (t1) == RECORD_TYPE
+      && TREE_CODE (t2) == RECORD_TYPE
+      && TYPE_MODE (t1) == TYPE_MODE (t2)
+      && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))
+      && tree_int_cst_equal (TYPE_ALIGN (t1), TYPE_ALIGN (t2)))
+    {
+      tree f1 = TYPE_FIELDS (t1);
+      tree f2 = TYPE_FIELDS (t2);
+      for (; f1 && f2; f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
+	if (f1 != f2 && (TREE_TYPE (f1) != TREE_TYPE (f2)
+			 || DECL_NAME (f1) != DECL_NAME (f2)
+			 || !tree_int_cst_equal (DECL_FIELD_BITPOS (f1),
+						 DECL_FIELD_BITPOS (f2))
+			 || !tree_int_cst_equal (DECL_FIELD_SIZE (f1),
+						 DECL_FIELD_SIZE (f2))))
+	  return 0;
+      return 1;
+    }
+
+  return 0;
+}
+
 /* Create a complex type whose components are COMPONENT_TYPE.  */
 
 tree
 build_complex_type (component_type)
      tree component_type;
 {
-  register tree t;
+  register tree type;
+  register tree rectype;
   int hashcode;
 
   /* Make a node of the sort we want.  */
-  t = make_node (COMPLEX_TYPE);
-
-  TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
-  set_type_quals (t, TYPE_QUALS (component_type));
+  type = make_node (COMPLEX_TYPE);
+  rectype = make_node (RECORD_TYPE);
+  TYPE_FIELDS (rectype)
+    = chainon (build_decl (FIELD_DECL, get_identifier ("real"),
+			   TYPE_MAIN_VARIANT (component_type)),
+	       build_decl (FIELD_DECL, get_identifier ("imag"),
+			   TYPE_MAIN_VARIANT (component_type)));
+  layout_type (rectype);
+  TREE_TYPE (type) = rectype;
+  set_type_quals (type, TYPE_QUALS (component_type));
+  layout_type (type);
+  TYPE_MODE (rectype) = TYPE_MODE (type);
 
   /* If we already have such a type, use the old one and free this one.  */
   hashcode = TYPE_HASH (component_type);
-  t = type_hash_canon (hashcode, t);
+  type = type_hash_canon (hashcode, type);
 
-  if (TYPE_SIZE (t) == 0)
-    layout_type (t);
-
   /* If we are writing Dwarf2 output we need to create a name,
      since complex is a fundamental type.  */
-  if (write_symbols == DWARF2_DEBUG && ! TYPE_NAME (t))
+  if (write_symbols == DWARF2_DEBUG && ! TYPE_NAME (type))
     {
       char *name;
       if (component_type == char_type_node)
@@ -4480,10 +4517,10 @@ build_complex_type (component_type)
 	name = (char *)0;
 
       if (name)
-	TYPE_NAME (t) = get_identifier (name);
+	TYPE_NAME (type) = get_identifier (name);
     }
 
-  return t;
+  return type;
 }
 
 /* Return OP, stripped of any conversions to wider types as much as is safe.
@@ -5284,21 +5321,10 @@ build_common_tree_nodes_2 (short_double)
   TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
   layout_type (long_double_type_node);
 
-  complex_integer_type_node = make_node (COMPLEX_TYPE);
-  TREE_TYPE (complex_integer_type_node) = integer_type_node;
-  layout_type (complex_integer_type_node);
-
-  complex_float_type_node = make_node (COMPLEX_TYPE);
-  TREE_TYPE (complex_float_type_node) = float_type_node;
-  layout_type (complex_float_type_node);
-
-  complex_double_type_node = make_node (COMPLEX_TYPE);
-  TREE_TYPE (complex_double_type_node) = double_type_node;
-  layout_type (complex_double_type_node);
-
-  complex_long_double_type_node = make_node (COMPLEX_TYPE);
-  TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
-  layout_type (complex_long_double_type_node);
+  complex_integer_type_node = build_complex_type (integer_type_node);
+  complex_float_type_node = build_complex_type (float_type_node);
+  complex_double_type_node = build_complex_type (double_type_node);
+  complex_long_double_type_node = build_complex_type (long_double_type_node);
 
 #ifdef BUILD_VA_LIST_TYPE
   BUILD_VA_LIST_TYPE(va_list_type_node);
Index: tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.h,v
retrieving revision 1.95
diff -u -p -r1.95 tree.h
--- tree.h	1999/09/30 13:40:40	1.95
+++ tree.h	1999/10/03 03:27:11
@@ -917,6 +917,9 @@ struct tree_block
    compact a way as possible.  */
 #define TYPE_PACKED(NODE) (TYPE_CHECK (NODE)->type.packed_flag)
 
+/* Component type of a complex type */
+#define TYPE_COMPLEX_SUBTYPE(NODE) (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (NODE))))
+
 struct tree_type
 {
   char common[sizeof (struct tree_common)];
Index: config/sh/sh.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/sh/sh.c,v
retrieving revision 1.35
diff -u -p -r1.35 sh.c
--- sh.c	1999/09/14 23:29:48	1.35
+++ sh.c	1999/10/03 03:27:23
@@ -4122,7 +4122,7 @@ sh_va_arg (valist, type)
 	{
 	  pass_as_float = ((TREE_CODE (type) == REAL_TYPE && size <= 8)
 			   || (TREE_CODE (type) == COMPLEX_TYPE
-			       && TREE_CODE (TREE_TYPE (type)) == REAL_TYPE
+			       && TREE_CODE (TYPE_COMPLEX_SUBTYPE (type)) == REAL_TYPE
 			       && size <= 16));
 	}
       else
Index: cp/method.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/method.c,v
retrieving revision 1.120
diff -u -p -r1.120 method.c
--- method.c	1999/10/01 04:34:24	1.120
+++ method.c	1999/10/03 03:27:35
@@ -1465,7 +1465,7 @@ process_overload_item (parmtype, extra_G
 
     case COMPLEX_TYPE:
       OB_PUTC ('J');
-      build_mangled_name_for_type (TREE_TYPE (parmtype));
+      build_mangled_name_for_type (TYPE_COMPLEX_SUBTYPE (parmtype));
       break;
 
     case VOID_TYPE:
Index: cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.219
diff -u -p -r1.219 typeck.c
--- typeck.c	1999/09/30 06:15:53	1.219
+++ typeck.c	1999/10/03 03:27:54
@@ -555,13 +555,13 @@ common_type (t1, t2)
      required type.  */
   if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
     {
-      tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
-      tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+      tree subtype1 = code1 == COMPLEX_TYPE ? TYPE_COMPLEX_SUBTYPE (t1) : t1;
+      tree subtype2 = code2 == COMPLEX_TYPE ? TYPE_COMPLEX_SUBTYPE (t2) : t2;
       tree subtype = common_type (subtype1, subtype2);
 
-      if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+      if (code1 == COMPLEX_TYPE && TYPE_COMPLEX_SUBTYPE (t1) == subtype)
 	return build_type_attribute_variant (t1, attributes);
-      else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+      else if (code2 == COMPLEX_TYPE && TYPE_COMPLEX_SUBTYPE (t2) == subtype)
 	return build_type_attribute_variant (t2, attributes);
       else
 	return build_type_attribute_variant (build_complex_type (subtype),
@@ -1076,7 +1076,7 @@ comptypes (t1, t2, strict)
       return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
 
     case COMPLEX_TYPE:
-      return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+      return same_type_p (TYPE_COMPLEX_SUBTYPE (t1), TYPE_COMPLEX_SUBTYPE (t2));
 
     default:
       break;
@@ -4440,7 +4440,7 @@ build_unary_op (code, xarg, noconvert)
       if (TREE_CODE (arg) == COMPLEX_CST)
 	return TREE_REALPART (arg);
       else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-	return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+	return fold (build1 (REALPART_EXPR, TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg)), arg));
       else
 	return arg;
 
@@ -4448,7 +4448,7 @@ build_unary_op (code, xarg, noconvert)
       if (TREE_CODE (arg) == COMPLEX_CST)
 	return TREE_IMAGPART (arg);
       else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-	return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+	return fold (build1 (IMAGPART_EXPR, TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg)), arg));
       else
 	return cp_convert (TREE_TYPE (arg), integer_zero_node);
       
Index: f/com.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/f/com.c,v
retrieving revision 1.68
diff -u -p -r1.68 com.c
--- com.c	1999/09/24 10:07:01	1.68
+++ com.c	1999/10/03 03:28:28
@@ -1,5 +1,5 @@
 /* com.c -- Implementation File (module.c template V1.0)
-   Copyright (C) 1995-1998 Free Software Foundation, Inc.
+   Copyright (C) 1995-1999 Free Software Foundation, Inc.
    Contributed by James Craig Burley.
 
 This file is part of GNU Fortran.
@@ -1220,7 +1220,8 @@ ffecom_convert_narrow_ (type, expr)
   if (code == COMPLEX_TYPE)
     {
       assert (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE);
-      assert (TYPE_PRECISION (TREE_TYPE (type)) <= TYPE_PRECISION (TREE_TYPE (TREE_TYPE (e))));
+      assert (TYPE_PRECISION (TYPE_COMPLEX_SUBTYPE (type))
+	      <= TYPE_PRECISION (TYPE_COMPLEX_SUBTYPE (TREE_TYPE (e))));
       return fold (convert_to_complex (type, e));
     }
   if (code == RECORD_TYPE)
@@ -1293,7 +1294,8 @@ ffecom_convert_widen_ (type, expr)
   if (code == COMPLEX_TYPE)
     {
       assert (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE);
-      assert (TYPE_PRECISION (TREE_TYPE (type)) >= TYPE_PRECISION (TREE_TYPE (TREE_TYPE (e))));
+      assert (TYPE_PRECISION (TYPE_COMPLEX_SUBTYPE (type))
+	      >= TYPE_PRECISION (TYPE_COMPLEX_SUBTYPE (TREE_TYPE (e))));
       return fold (convert_to_complex (type, e));
     }
   if (code == RECORD_TYPE)
@@ -1323,26 +1325,27 @@ ffecom_convert_widen_ (type, expr)
 static tree
 ffecom_make_complex_type_ (tree subtype)
 {
-  tree type;
-  tree realfield;
-  tree imagfield;
-
+  tree rec_type;
+  tree real_field;
+  tree imag_field;
+
+  rec_type = make_node (RECORD_TYPE);
+  real_field = ffecom_decl_field (rec_type, NULL_TREE, "r", subtype);
+  imag_field = ffecom_decl_field (rec_type, real_field, "i", subtype);
+  TYPE_FIELDS (rec_type) = real_field;
+  layout_type (rec_type);
+  
   if (ffe_is_emulate_complex ())
-    {
-      type = make_node (RECORD_TYPE);
-      realfield = ffecom_decl_field (type, NULL_TREE, "r", subtype);
-      imagfield = ffecom_decl_field (type, realfield, "i", subtype);
-      TYPE_FIELDS (type) = realfield;
-      layout_type (type);
-    }
+    return rec_type;
   else
     {
-      type = make_node (COMPLEX_TYPE);
-      TREE_TYPE (type) = subtype;
-      layout_type (type);
+      tree complex_type = make_node (COMPLEX_TYPE);
+      TREE_TYPE (rec_type) = subtype;
+      TREE_TYPE (complex_type) = rec_type;
+      layout_type (complex_type);
+      TYPE_MODE (rec_type) = TYPE_MODE (complex_type);
+      return complex_type;
     }
-
-  return type;
 }
 #endif
 
@@ -2610,10 +2613,13 @@ ffecom_debug_kludge_ (tree aggr, const c
 	  break;
 
 	case ARRAY_TYPE:
-	case COMPLEX_TYPE:
 	  type_id = TREE_TYPE (type_id);
 	  break;
 
+	case COMPLEX_TYPE:
+	  type_id = TYPE_COMPLEX_SUBTYPE (type_id);
+	  break;
+
 	default:
 	  assert ("no IDENTIFIER_NODE for type!" == NULL);
 	  type_id = error_mark_node;
@@ -3755,8 +3761,8 @@ ffecom_expr_ (ffebld expr, tree dest_tre
 
 	    if (TREE_CODE (TREE_TYPE (arg1)) == COMPLEX_TYPE)
 	      {
-		real_type = TREE_TYPE (TREE_TYPE (arg1));
-		assert (real_type == TREE_TYPE (TREE_TYPE (arg2)));
+		real_type = TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg1));
+		assert (real_type == TYPE_COMPLEX_SUBTYPE (TREE_TYPE (arg2)));
 	      }
 	    else
 	      {
@@ -4044,7 +4050,7 @@ ffecom_expr_intrinsic_ (ffebld expr, tre
     case FFEINTRIN_impDIMAG:
     case FFEINTRIN_impIMAGPART:
       if (TREE_CODE (arg1_type) == COMPLEX_TYPE)
-	arg1_type = TREE_TYPE (arg1_type);
+	arg1_type = TYPE_COMPLEX_SUBTYPE (arg1_type);
       else
 	arg1_type = TREE_TYPE (TYPE_FIELDS (arg1_type));
 
@@ -4497,7 +4503,7 @@ ffecom_expr_intrinsic_ (ffebld expr, tre
 
     case FFEINTRIN_impREALPART:
       if (TREE_CODE (arg1_type) == COMPLEX_TYPE)
-	arg1_type = TREE_TYPE (arg1_type);
+	arg1_type = TYPE_COMPLEX_SUBTYPE (arg1_type);
       else
 	arg1_type = TREE_TYPE (TYPE_FIELDS (arg1_type));
 
@@ -9353,7 +9359,7 @@ ffecom_tree_divide_ (tree tree_type, tre
       {
 	ffecomGfrt ix;
 
-	if (TREE_TYPE (tree_type)
+	if (TYPE_COMPLEX_SUBTYPE (tree_type)
 	    == ffecom_tree_type [FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1])
 	  ix = FFECOM_gfrtDIV_CC;	/* Overlapping result okay. */
 	else
@@ -15661,10 +15667,10 @@ truthvalue_conversion (expr)
 	      ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
 	     integer_type_node,
 	     truthvalue_conversion (ffecom_1 (REALPART_EXPR,
-					      TREE_TYPE (TREE_TYPE (expr)),
+					      TYPE_COMPLEX_SUBTYPE (TREE_TYPE (expr)),
 					      expr)),
 	     truthvalue_conversion (ffecom_1 (IMAGPART_EXPR,
-					      TREE_TYPE (TREE_TYPE (expr)),
+					      TYPE_COMPLEX_SUBTYPE (TREE_TYPE (expr)),
 					      expr))));
 
   return ffecom_2 (NE_EXPR, integer_type_node,


More information about the Gcc-patches mailing list