public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Patch for COMPLEX support (part 2)
@ 1998-02-10  3:34 Weiwen Liu
  0 siblings, 0 replies; 2+ messages in thread
From: Weiwen Liu @ 1998-02-10  3:34 UTC (permalink / raw)
  To: egcs

Wed Jan  7 17:30:00 1998  Weiwen Liu <liu@hepunix.physics.yale.edu>

	 * machmode.h: define COMPLEX_MODE_P, COMPLEX_SUBMODE.

	 * regs.h (REG_SIZE): Consider complex modes.

	 * calls.c (arg_data): Add partial_real and partial_imag to
	 record the number of registers used for real/imaginary part.

	 * combine.c (expand_field_assignment): Exclude SUBREG of a
         COMPLEX.

	 * explow.c (hard_function_value): Promote COMPLEX return
	 value if required.

	 * calls.c (expand_call): Deal with arguments of complex modes.
	   (store_one_arg): Likewise.
	 * emit-rtl.c (gen_lowpart_common): Likewise.
	 (gen_highpart): Likewise.
	 * expr.c (store_expr): Likewise.
	 (expand_expr): Likewise.
	 * function.c (aggregate_value_p): Likewise.
	 (assign_parms): Likewise.
	 (locate_and_pad_parm): Likewise.
	 (expand_function_start): Likewise.
	 * integrate.c (expand_inline_function): Likewise.
	 * reload.c (find_reloads): Likewise.
	 * stmt.c (expand_value_return): Likewise.

--- gcc/calls.c.orig	Wed Dec 24 16:39:40 1997
+++ gcc/calls.c	Wed Jan  7 10:57:01 1998
@@ -71,6 +71,10 @@ struct arg_data
   /* Number of registers to use.  0 means put the whole arg in registers.
      Also 0 if not passed in registers.  */
   int partial;
+  /* Number of registers to use for real part. */
+  int partial_real;
+  /* Number of registers to use for imaginary part. */
+  int partial_imag;
   /* Non-zero if argument must be passed on stack.
      Note that some arguments may be passed on the stack
      even though pass_on_stack is zero, just because FUNCTION_ARG says so.
@@ -1012,7 +1016,9 @@ expand_call (exp, target, ignore)
       tree type = TREE_TYPE (TREE_VALUE (p));
       int unsignedp;
       enum machine_mode mode;
-
+      enum machine_mode submode;
+      tree subtype;
+      
       args[i].tree_value = TREE_VALUE (p);
 
       /* Replace erroneous argument with constant zero.  */
@@ -1044,8 +1050,13 @@ expand_call (exp, target, ignore)
 	   && contains_placeholder_p (TYPE_SIZE (type)))
 	  || TREE_ADDRESSABLE (type)
 #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
-	  || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type),
-					     type, argpos < n_named_args)
+	  || FUNCTION_ARG_PASS_BY_REFERENCE
+	     (args_so_far,
+	      (! COMPLEX_MODE_P (TYPE_MODE (type)))?
+	      TYPE_MODE (type) : COMPLEX_SUBMODE (TYPE_MODE (type)),
+	      (! COMPLEX_MODE_P (TYPE_MODE (type)))?
+	      type : type_for_mode (COMPLEX_SUBMODE (TYPE_MODE (type)), 0),
+	      argpos < n_named_args)
 #endif
 	  )
 	{
@@ -1053,8 +1064,14 @@ expand_call (exp, target, ignore)
              references instead of making a copy.  */
 	  if (current_function_is_thunk
 #ifdef FUNCTION_ARG_CALLEE_COPIES
-	      || (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type),
-					     type, argpos < n_named_args)
+	      || (FUNCTION_ARG_CALLEE_COPIES
+		  (args_so_far,
+		   COMPLEX_MODE_P (TYPE_MODE (type))?
+		   COMPLEX_SUBMODE (TYPE_MODE (type)) : TYPE_MODE (type),
+		   COMPLEX_MODE_P (TYPE_MODE (type))?
+		   type_for_mode (COMPLEX_SUBMODE (TYPE_MODE (type)), 0)
+		   : type,
+		   argpos < n_named_args)
 		  /* If it's in a register, we must make a copy of it too.  */
 		  /* ??? Is this a sufficient test?  Is there a better one? */
 		  && !(TREE_CODE (args[i].tree_value) == VAR_DECL
@@ -1117,21 +1134,81 @@ expand_call (exp, target, ignore)
 
       mode = TYPE_MODE (type);
       unsignedp = TREE_UNSIGNED (type);
-
+      if (COMPLEX_MODE_P (mode))
+	{
+	  submode = COMPLEX_SUBMODE (mode);
+	  subtype = type_for_mode (submode, unsignedp);
+	}
+      
 #ifdef PROMOTE_FUNCTION_ARGS
-      mode = promote_mode (type, mode, &unsignedp, 1);
+      if (! COMPLEX_MODE_P (mode))
+	{
+	  mode = promote_mode (type, mode, &unsignedp, 1);
+	}
+      else
+	{
+	  submode = promote_mode (subtype, submode, &unsignedp, 1);
+	  subtype = type_for_mode (submode, unsignedp);
+	  mode = mode_for_size (2 * GET_MODE_SIZE (submode) * BITS_PER_UNIT,
+				GET_MODE_CLASS (mode), 0);
+	}
 #endif
 
       args[i].unsignedp = unsignedp;
       args[i].mode = mode;
-      args[i].reg = FUNCTION_ARG (args_so_far, mode, type,
-				  argpos < n_named_args);
+      if (! COMPLEX_MODE_P (mode))
+	{
+	  args[i].reg = FUNCTION_ARG (args_so_far, mode, type,
+				      argpos < n_named_args);
 #ifdef FUNCTION_ARG_PARTIAL_NREGS
-      if (args[i].reg)
-	args[i].partial
-	  = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,
-					argpos < n_named_args);
+	  if (args[i].reg)
+	    args[i].partial
+	      = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,
+					    argpos < n_named_args);
 #endif
+      /* Increment ARGS_SO_FAR, which has info about which arg-registers
+	 have been used, etc.  */
+	  FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,
+				argpos < n_named_args);
+	}
+      else
+	{
+	  rtx realpart;
+	  rtx imagpart;
+	  
+	  realpart = FUNCTION_ARG (args_so_far, submode, subtype,
+				   argpos < n_named_args);
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+	  args[i].partial_real = 0;
+	  if (realpart)
+	    {
+	      args[i].partial_real
+		= FUNCTION_ARG_PARTIAL_NREGS (args_so_far, submode, subtype,
+					      argpos < n_named_args);
+	      args[i].partial = args[i].partial_real;
+	    }
+#endif
+	  FUNCTION_ARG_ADVANCE (args_so_far, submode,
+				type, argpos < n_named_args);
+	  imagpart = FUNCTION_ARG (args_so_far, submode, subtype,
+				   argpos < n_named_args);
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+	  args[i].partial_imag = 0;
+	  if (imagpart)
+	    {
+	      args[i].partial_imag
+		= FUNCTION_ARG_PARTIAL_NREGS (args_so_far, submode, subtype,
+					      argpos < n_named_args);
+	      args[i].partial = args[i].partial_imag;
+	    }
+#endif
+	  FUNCTION_ARG_ADVANCE (args_so_far, submode,
+				type, argpos < n_named_args);
+	  if (realpart != 0)
+	    args[i].reg = gen_rtx (CONCAT, mode, realpart, imagpart);
+	  else
+	    args[i].reg = 0;
+	}
 
       args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);
 
@@ -1158,19 +1235,45 @@ expand_call (exp, target, ignore)
 
       /* Compute the stack-size of this argument.  */
       if (args[i].reg == 0 || args[i].partial != 0
+	  /* Allocate stack for a complex argument if its real part is
+	     passed in register and its imaginary part is not. */
+	  || (COMPLEX_MODE_P (mode) && XEXP (args[i].reg, 1) == 0)
 #ifdef REG_PARM_STACK_SPACE
 	  || reg_parm_stack_space > 0
 #endif
 	  || args[i].pass_on_stack)
-	locate_and_pad_parm (mode, type,
+	{
+	  enum machine_mode passed_mode = mode;
+	  tree passed_type = type;
+	  rtx reg = args[i].reg;
+	  
+	  if (COMPLEX_MODE_P (mode) && args[i].reg != 0
+#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+	    && REG_PARM_STACK_SPACE (fndecl) == 0
+#endif
+	    )
+	    {
+	      /* If we do not need to allocate stack space for
+		 arguments passing in register, and the real part
+		 of a complex argument is passing in register,
+		 we only allocate stack space for the imaginary part. */
+	      if (XEXP (args[i].reg, 0) != 0 && args[i].partial_real == 0)
+		{
+		  passed_mode = submode;
+		  passed_type = subtype;
+		  reg = XEXP (args[i].reg, 1);
+		}
+	    }
+	  locate_and_pad_parm (passed_mode, passed_type,
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
-			     1,
+			       1,
 #else
-			     args[i].reg != 0,
+			       reg != 0,
 #endif
-			     fndecl, &args_size, &args[i].offset,
-			     &args[i].size);
-
+			       fndecl, &args_size, &args[i].offset,
+			       &args[i].size);
+	}
+      
 #ifndef ARGS_GROW_DOWNWARD
       args[i].slot_offset = args_size;
 #endif
@@ -1203,12 +1306,6 @@ expand_call (exp, target, ignore)
 	  SUB_PARM_SIZE (args[i].slot_offset, args_size.var);
 	}
 #endif
-
-      /* Increment ARGS_SO_FAR, which has info about which arg-registers
-	 have been used, etc.  */
-
-      FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,
-			    argpos < n_named_args);
     }
 
 #ifdef FINAL_REG_PARM_STACK_SPACE
@@ -1375,10 +1472,33 @@ expand_call (exp, target, ignore)
 	  = protect_from_queue (args[i].initial_value, 0);
 
 	if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode)
-	  args[i].value
-	    = convert_modes (args[i].mode, 
-			     TYPE_MODE (TREE_TYPE (args[i].tree_value)),
-			     args[i].value, args[i].unsignedp);
+	  {
+	    if (! COMPLEX_MODE_P (args[i].mode))
+	      args[i].value
+		= convert_modes (args[i].mode, 
+				 TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+				 args[i].value, args[i].unsignedp);
+	    else
+	      {
+		enum machine_mode submode_orig
+		  = COMPLEX_SUBMODE (TYPE_MODE
+				       (TREE_TYPE (args[i].tree_value)));
+		enum machine_mode submode_final
+		  = COMPLEX_SUBMODE (args[i].mode);
+		rtx realpart;
+		rtx imagpart;
+		realpart = convert_modes (submode_final, submode_orig,
+					  gen_realpart (submode_orig,
+							args[i].value),
+					  args[i].unsignedp);
+		imagpart = convert_modes (submode_final, submode_orig,
+					  gen_imagpart (submode_orig,
+							args[i].value),
+					  args[i].unsignedp);
+		args[i].value = gen_rtx (CONCAT, args[i].mode,
+					 realpart, imagpart);
+	      }
+	  }
       }
 
   /* Now we are about to start emitting insns that can be deleted
@@ -1665,10 +1785,33 @@ expand_call (exp, target, ignore)
 	   do it now.  */
 
 	if (args[i].mode != TYPE_MODE (TREE_TYPE (args[i].tree_value)))
-	  args[i].value
-	    = convert_modes (args[i].mode,
-			     TYPE_MODE (TREE_TYPE (args[i].tree_value)),
-			     args[i].value, args[i].unsignedp);
+	  {
+	    if (! COMPLEX_MODE_P (args[i].mode))
+	      args[i].value
+		= convert_modes (args[i].mode, 
+				 TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+				 args[i].value, args[i].unsignedp);
+	    else
+	      {
+		enum machine_mode submode_orig
+		  = COMPLEX_SUBMODE (TYPE_MODE
+				       (TREE_TYPE (args[i].tree_value)));
+		enum machine_mode submode_final
+		  = COMPLEX_SUBMODE (args[i].mode);
+		rtx realpart;
+		rtx imagpart;
+		realpart = convert_modes (submode_final, submode_orig,
+					  gen_realpart (submode_orig,
+							args[i].value),
+					  args[i].unsignedp);
+		imagpart = convert_modes (submode_final, submode_orig,
+					  gen_imagpart (submode_orig,
+							args[i].value),
+					  args[i].unsignedp);
+		args[i].value = gen_rtx (CONCAT, args[i].mode,
+					 realpart, imagpart);
+	      }
+	  }
 
 	/* If the value is expensive, and we are inside an appropriately 
 	   short loop, put the value into a pseudo and then put the pseudo
@@ -1758,7 +1901,12 @@ expand_call (exp, target, ignore)
      but we do preallocate space here if they want that.  */
 
   for (i = 0; i < num_actuals; i++)
-    if (args[i].reg == 0 || args[i].pass_on_stack)
+    if (args[i].reg == 0 || args[i].pass_on_stack
+	/* Deal with the imaginary part of a complex argument
+	   that is passed in stack. */
+	|| (COMPLEX_MODE_P (args[i].mode)
+	    && args[i].reg != 0 && args[i].partial == 0
+	    && XEXP (args[i].reg, 1) == 0))
       store_one_arg (&args[i], argblock, may_be_alloca,
 		     args_size.var != 0, fndecl, reg_parm_stack_space);
 
@@ -1919,8 +2067,22 @@ expand_call (exp, target, ignore)
 	     load the register(s) from memory.  */
 
 	  else if (nregs == -1)
-	    emit_move_insn (reg, args[i].value);
-
+	    {
+	      if (GET_CODE (reg) != CONCAT)
+		emit_move_insn (reg, args[i].value);
+	      else
+		{
+		  enum machine_mode submode
+		    = COMPLEX_SUBMODE (args[i].value->mode);
+		  if (XEXP (reg, 0))
+		    emit_move_insn (XEXP (reg, 0),
+				    gen_realpart (submode, args[i].value));
+		  if (XEXP (reg, 1))
+		    emit_move_insn (XEXP (reg, 1),
+				    gen_imagpart (submode, args[i].value));
+		}
+	    }
+	  
 	  /* If we have pre-computed the values to put in the registers in
 	     the case of non-aligned structures, copy them in now.  */
 
@@ -1939,9 +2101,31 @@ expand_call (exp, target, ignore)
 	  if (GET_CODE (reg) == PARALLEL)
 	    use_group_regs (&call_fusage, reg);
 	  else if (nregs == -1)
-	    use_reg (&call_fusage, reg);
+	    {
+	      if (GET_CODE (reg) != CONCAT)
+		use_reg (&call_fusage, reg);
+	      else
+		{
+		  if (XEXP (reg, 0))
+		    use_reg (&call_fusage, XEXP (reg, 0));
+		  if (XEXP (reg, 1))
+		    use_reg (&call_fusage, XEXP (reg, 1));
+		}
+	    }
 	  else
-	    use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);
+	    {
+	      if (GET_CODE (reg) != CONCAT)
+		use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);
+	      else
+		{
+		  if (args[i].partial_real)
+		    use_regs (&call_fusage, REGNO (XEXP (reg, 0)),
+			      args[i].partial_real);
+		  else
+		    use_regs (&call_fusage, REGNO (XEXP (reg, 1)),
+			      args[i].partial_imag);
+		}
+	    }
 	}
     }
 
@@ -2193,6 +2377,41 @@ expand_call (exp, target, ignore)
       SUBREG_PROMOTED_VAR_P (target) = 1;
       SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp;
     }
+  else if (GET_CODE (target) == CONCAT
+	   && GET_CODE (XEXP (target, 0)) == REG
+	   && TYPE_MODE (TREE_TYPE (exp)) != BLKmode
+	   && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
+    {
+      tree type = TREE_TYPE (exp);
+      int unsignedp = TREE_UNSIGNED (type);
+      enum machine_mode submode_orig = COMPLEX_SUBMODE (TYPE_MODE (type));
+      enum machine_mode submode_final;
+      enum machine_mode promoted_mode;
+      rtx realpart;
+      rtx imagpart;
+      
+      submode_final = promote_mode (type_for_mode (submode_orig, unsignedp),
+				     submode_orig, &unsignedp, 1);
+      promoted_mode = mode_for_size (2 * GET_MODE_SIZE (submode_final)
+				     * BITS_PER_UNIT,
+				     GET_MODE_CLASS (GET_MODE (target)), 0);
+      
+      /* If we don't promote as expected, something is wrong.  */
+      if (GET_MODE (target) != promoted_mode )
+	abort ();
+
+      realpart = gen_rtx (SUBREG, submode_orig,
+			  gen_realpart (submode_final, target), 0);
+      SUBREG_PROMOTED_VAR_P (realpart) = 1;
+      SUBREG_PROMOTED_UNSIGNED_P (realpart) = unsignedp;
+
+      imagpart = gen_rtx (SUBREG, submode_orig,
+			  gen_imagpart (submode_final, target), 0);
+      SUBREG_PROMOTED_VAR_P (imagpart) = 1;
+      SUBREG_PROMOTED_UNSIGNED_P (imagpart) = unsignedp;
+
+      target = gen_rtx (CONCAT, TYPE_MODE (type), realpart, imagpart);
+    }
 #endif
 
   /* If size of args is variable or this was a constructor call for a stack
@@ -3512,8 +3737,13 @@ store_one_arg (arg, argblock, may_be_all
   /* If this isn't going to be placed on both the stack and in registers,
      set up the register and number of words.  */
   if (! arg->pass_on_stack)
-    reg = arg->reg, partial = arg->partial;
-
+    {
+      reg = arg->reg, partial = arg->partial;
+      if (reg && COMPLEX_MODE_P (reg->mode) && partial == 0)
+	/* Deal with the imaginary part passing in stack. */
+	reg = 0;
+    }
+  
   if (reg != 0 && partial == 0)
     /* Being passed entirely in a register.  We shouldn't be called in
        this case.   */
@@ -3560,8 +3790,31 @@ store_one_arg (arg, argblock, may_be_all
 	 doesn't agree, convert the mode.  */
 
       if (arg->mode != TYPE_MODE (TREE_TYPE (pval)))
-	arg->value = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)),
-				    arg->value, arg->unsignedp);
+	{
+	  if (! COMPLEX_MODE_P (arg->mode))
+	    arg->value
+	      = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)),
+			       arg->value, arg->unsignedp);
+	  else
+	    {
+	      enum machine_mode submode_orig
+		= COMPLEX_SUBMODE (TYPE_MODE (TREE_TYPE (pval)));
+	      enum machine_mode submode_final
+		= COMPLEX_SUBMODE (arg->mode);
+	      rtx realpart;
+	      rtx imagpart;
+	      realpart = convert_modes (submode_final, submode_orig,
+					gen_realpart (submode_orig,
+						      arg->value),
+					arg->unsignedp);
+	      imagpart = convert_modes (submode_final, submode_orig,
+					gen_imagpart (submode_orig,
+						      arg->value),
+					arg->unsignedp);
+	      arg->value = gen_rtx (CONCAT, arg->mode,
+				    realpart, imagpart);
+	    }
+	}
 
 #ifdef ACCUMULATE_OUTGOING_ARGS
       if (arg->pass_on_stack)
@@ -3593,6 +3846,11 @@ store_one_arg (arg, argblock, may_be_all
   else if (arg->mode != BLKmode)
     {
       register int size;
+      enum machine_mode mode
+	= (!COMPLEX_MODE_P (arg->mode)) ?
+	arg->mode : COMPLEX_SUBMODE (arg->mode);
+      tree type = (!COMPLEX_MODE_P (arg->mode))?
+	TREE_TYPE (pval) : TREE_TYPE (TREE_TYPE (pval));
 
       /* Argument is a scalar, not entirely passed in registers.
 	 (If part is passed in registers, arg->partial says how much
@@ -3604,7 +3862,7 @@ store_one_arg (arg, argblock, may_be_all
 	 Note that in C the default argument promotions
 	 will prevent such mismatches.  */
 
-      size = GET_MODE_SIZE (arg->mode);
+      size = GET_MODE_SIZE (mode);
       /* Compute how much space the push instruction will push.
 	 On many machines, pushing a byte will advance the stack
 	 pointer by a halfword.  */
@@ -3615,16 +3873,57 @@ store_one_arg (arg, argblock, may_be_all
 
       /* Compute how much space the argument should get:
 	 round up to a multiple of the alignment for arguments.  */
-      if (none != FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)))
+      if (none != FUNCTION_ARG_PADDING (mode, type))
 	used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
 		 / (PARM_BOUNDARY / BITS_PER_UNIT))
 		* (PARM_BOUNDARY / BITS_PER_UNIT));
 
       /* This isn't already where we want it on the stack, so put it there.
 	 This can either be done with push or copy insns.  */
-      emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
-		      0, partial, reg, used - size,
-		      argblock, ARGS_SIZE_RTX (arg->offset));
+      if (! COMPLEX_MODE_P (arg->mode))
+	emit_push_insn (arg->value, arg->mode, type, NULL_RTX,
+			0, partial, reg, used - size,
+			argblock, ARGS_SIZE_RTX (arg->offset));
+      else
+	{
+	  struct args_size offset;
+	  offset.constant = arg->offset.constant;
+	  offset.var = arg->offset.var;
+	  if (arg->partial_real > 0
+	      || arg->reg == 0
+	      || XEXP (arg->reg, 0) == 0)
+	    emit_push_insn (gen_realpart (mode, arg->value),
+			    mode, type, NULL_RTX,
+			    0, arg->partial_real,
+			    reg ? XEXP (arg->reg, 0) : reg, used - size,
+			    argblock, ARGS_SIZE_RTX (offset));
+	  
+	  if (!(arg->reg
+#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+		&& REG_PARM_STACK_SPACE (fndecl) == 0
+#endif
+		&& XEXP (arg->reg, 0) != 0 && arg->partial_real == 0)
+#ifdef ARGS_GROW_DOWNWARD
+	      /* If the real part is passing in register, the imaginary
+		 part in stack only, and ARGS_GROW_DOWNWARD is defined,
+		 allocate the stack space for the imaginary part close to
+		 next argument. */
+	      && !(arg->reg
+		   && XEXP (arg->reg, 0) != 0 && arg->partial_real == 0
+		   && (XEXP (arg->reg, 1) == 0 || arg->partial_imag > 0))
+#endif
+	      )
+	      offset.constant += arg->size.constant / 2;
+
+	  if (arg->partial_imag > 0
+	      || arg->reg == 0
+	      || XEXP (arg->reg, 1) == 0)
+	    emit_push_insn (gen_imagpart (mode, arg->value),
+			    mode, type, NULL_RTX,
+			    0, arg->partial_imag,
+			    reg ? XEXP (arg->reg, 1) : reg, used - size,
+			    argblock, ARGS_SIZE_RTX (offset));
+	}
     }
   else
     {
@@ -3666,7 +3965,10 @@ store_one_arg (arg, argblock, may_be_all
      ??? Note that this can change arg->value from arg->stack to
      arg->stack_slot and it matters when they are not the same.
      It isn't totally clear that this is correct in all cases.  */
-  if (partial == 0)
+  if (partial == 0
+      /* Do not include the case where the real/imaginary part is
+	 not partially in register. */
+      && arg->reg == 0)
     arg->value = arg->stack_slot;
 
   /* Once we have pushed something, pops can't safely
--- gcc/combine.c.orig	Sat Dec 20 06:31:23 1997
+++ gcc/combine.c	Tue Jan  6 17:26:53 1998
@@ -5297,8 +5297,10 @@ expand_field_assignment (x)
 	}
 
       /* A SUBREG between two modes that occupy the same numbers of words
-	 can be done by moving the SUBREG to the source.  */
+	 can be done by moving the SUBREG to the source.
+         But a SUBREG of a COMPLEX should not be done. */
       else if (GET_CODE (SET_DEST (x)) == SUBREG
+               && ! COMPLEX_MODE_P (GET_MODE (SUBREG_REG (SET_DEST (x))))
 	       && (((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
 		     + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
 		   == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
--- gcc/emit-rtl.c.orig	Sat Dec 20 06:31:27 1997
+++ gcc/emit-rtl.c	Tue Jan  6 17:42:46 1998
@@ -499,8 +499,7 @@ gen_reg_rtx (mode)
   if (reload_in_progress || reload_completed)
     abort ();
 
-  if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-      || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
+  if (COMPLEX_MODE_P (mode))
     {
       /* For complex modes, don't make a single pseudo.
 	 Instead, make a CONCAT of two pseudos.
@@ -637,10 +636,16 @@ gen_lowpart_common (mode, x)
 	     / UNITS_PER_WORD)))
     return 0;
 
-  if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
-    word = ((GET_MODE_SIZE (GET_MODE (x))
-	     - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
-	    / UNITS_PER_WORD);
+  if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > 0)
+    {
+      if (!COMPLEX_MODE_P (GET_MODE (x)))
+	word = ((GET_MODE_SIZE (GET_MODE (x))
+		 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+		/ UNITS_PER_WORD);
+      else
+	word = 2 * HARD_REGNO_NREGS (REGNO (x), COMPLEX_SUBMODE (GET_MODE (x)))
+	  - HARD_REGNO_NREGS (REGNO (x), mode);
+    }
 
   if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
       && (GET_MODE_CLASS (mode) == MODE_INT
@@ -1017,10 +1022,17 @@ gen_highpart (mode, x)
       int word = 0;
 
       if (! WORDS_BIG_ENDIAN
-	  && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
-	word = ((GET_MODE_SIZE (GET_MODE (x))
-		 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
-		/ UNITS_PER_WORD);
+	  && GET_MODE_SIZE (GET_MODE (x)) > 0)
+	{
+	  if (!COMPLEX_MODE_P (GET_MODE (x)))
+	    word = ((GET_MODE_SIZE (GET_MODE (x))
+		     - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+		    / UNITS_PER_WORD);
+	  else
+	    word = 2 * HARD_REGNO_NREGS (REGNO (x),
+					 COMPLEX_SUBMODE (GET_MODE (x)))
+	      - HARD_REGNO_NREGS (REGNO (x), mode);
+	}
 
       /*
        * ??? This fails miserably for complex values being passed in registers
--- gcc/explow.c.orig	Sat Dec  6 12:19:52 1997
+++ gcc/explow.c	Wed Jan  7 16:34:26 1998
@@ -1322,7 +1322,29 @@ hard_function_value (valtype, func)
      tree valtype;
      tree func;
 {
-  rtx val = FUNCTION_VALUE (valtype, func);
+  rtx val;
+  enum machine_mode complex_mode = TYPE_MODE (valtype);
+  
+  if (COMPLEX_MODE_P (complex_mode))
+    {
+      enum machine_mode orig_word_mode = word_mode;
+      enum machine_mode submode = COMPLEX_SUBMODE (complex_mode);
+      int unsignedp = TREE_UNSIGNED (valtype);
+      word_mode = submode;
+      val = FUNCTION_VALUE (type_for_mode (submode, unsignedp), func);
+      word_mode = orig_word_mode;
+#ifdef PROMOTE_FUNCTION_RETURN
+      submode = promote_mode (type_for_mode (submode, unsignedp),
+			      submode, &unsignedp, 0);
+      complex_mode = mode_for_size (2 * GET_MODE_SIZE (submode)
+				    * BITS_PER_UNIT,
+				    GET_MODE_CLASS (complex_mode), 0);
+#endif
+      val = gen_rtx (REG, complex_mode, REGNO (val));
+    }
+  else
+    val = FUNCTION_VALUE (valtype, func);
+  
   if (GET_CODE (val) == REG
       && GET_MODE (val) == BLKmode)
     {
--- gcc/expr.c.orig	Fri Dec 19 11:41:58 1997
+++ gcc/expr.c	Wed Jan  7 16:53:23 1998
@@ -2262,12 +2262,8 @@ emit_move_insn_1 (x, y)
       emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (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))
+  else if (COMPLEX_MODE_P (mode)
+	   && BLKmode != (submode = COMPLEX_SUBMODE (mode))
 	   && (mov_optab->handlers[(int) submode].insn_code
 	       != CODE_FOR_nothing))
     {
@@ -3296,6 +3292,81 @@ store_expr (exp, target, want_value)
 		    SUBREG_PROMOTED_UNSIGNED_P (target));
       return want_value ? temp : NULL_RTX;
     }
+  else if (GET_CODE (target) == CONCAT
+	   && COMPLEX_MODE_P (GET_MODE (target))
+	   && GET_CODE (XEXP (target, 0)) == SUBREG
+	   && SUBREG_PROMOTED_VAR_P (XEXP (target, 0)))
+    /* Do the same as for the previous case. */
+    {
+      rtx realpart;
+      rtx imagpart;
+      if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (exp)))
+	  && TREE_TYPE (TREE_TYPE (TREE_TYPE (exp))) == 0)
+	{
+	  enum machine_mode mode;
+	  tree type;
+	  
+	  if (TREE_UNSIGNED (TREE_TYPE (exp))
+	      != SUBREG_PROMOTED_UNSIGNED_P (XEXP (target, 0)))
+	    exp
+	      = convert
+		(signed_or_unsigned_type (SUBREG_PROMOTED_UNSIGNED_P
+					  (XEXP (target, 0)),
+					  TREE_TYPE (exp)),
+		 exp);
+
+	  mode = GET_MODE (SUBREG_REG (XEXP (target, 0)));
+	  mode = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT * 2,
+				GET_MODE_CLASS (GET_MODE (target)),
+				0);
+	  
+	  exp = convert (type_for_mode (mode,
+					SUBREG_PROMOTED_UNSIGNED_P
+					(XEXP (target, 0))),
+					exp);
+	}
+	 
+      temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+
+      realpart = gen_realpart (COMPLEX_SUBMODE (GET_MODE (temp)), temp);
+      imagpart = gen_imagpart (COMPLEX_SUBMODE (GET_MODE (temp)), temp);
+      if (GET_CODE (realpart) == MEM && want_value
+	  && (MEM_VOLATILE_P (realpart)
+	      || reg_mentioned_p (SUBREG_REG (XEXP (target, 0)),
+				  XEXP (realpart, 0))))
+	realpart = copy_to_reg (realpart);
+      if (GET_CODE (imagpart) == MEM && want_value
+	  && (MEM_VOLATILE_P (imagpart)
+	      || reg_mentioned_p (SUBREG_REG (XEXP (target, 1)),
+				  XEXP (imagpart, 0))))
+	imagpart = copy_to_reg (imagpart);
+
+      if (CONSTANT_P (realpart) && GET_MODE (realpart) == VOIDmode)
+	realpart = convert_modes (GET_MODE (SUBREG_REG
+						  (XEXP (target, 0))),
+					COMPLEX_SUBMODE (TYPE_MODE
+							   (TREE_TYPE (exp))),
+					realpart,
+					SUBREG_PROMOTED_UNSIGNED_P
+					(XEXP (target, 0)));
+      if (CONSTANT_P (imagpart) && GET_MODE (imagpart) == VOIDmode)
+	imagpart = convert_modes (GET_MODE (SUBREG_REG
+						  (XEXP (target, 1))),
+					COMPLEX_SUBMODE (TYPE_MODE
+							   (TREE_TYPE (exp))),
+					imagpart,
+					SUBREG_PROMOTED_UNSIGNED_P
+					(XEXP (target, 1)));
+
+      convert_move (SUBREG_REG (XEXP (target, 0)), realpart,
+		    SUBREG_PROMOTED_UNSIGNED_P (XEXP (target, 0)));
+      convert_move (SUBREG_REG (XEXP (target, 1)), imagpart,
+		    SUBREG_PROMOTED_UNSIGNED_P (XEXP (target, 1)));
+      temp = gen_rtx (CONCAT, TYPE_MODE (TREE_TYPE (exp)),
+		      realpart, imagpart);
+      
+      return want_value ? temp : NULL_RTX;
+    }
   else
     {
       temp = expand_expr (exp, target, GET_MODE (target), 0);
@@ -4978,10 +5049,21 @@ expand_expr (exp, target, tmode, modifie
      and 2) otherwise cse could produce an insn the machine
      cannot support.  */
 
-  if (! cse_not_expected && mode != BLKmode && target
-      && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER))
-    target = subtarget;
+  if (! cse_not_expected && mode != BLKmode && target)
+    {
+      int flag = 1;
+      
+      if (GET_CODE (target) == REG && REGNO (target) > FIRST_PSEUDO_REGISTER)
+	flag = 0;
+      else if (GET_CODE (target) == CONCAT
+	       && GET_CODE (XEXP (target, 0)) == REG
+	       && REGNO (XEXP (target, 0)) > FIRST_PSEUDO_REGISTER)
+	flag = 0;
 
+      if (flag)
+	target = subtarget;
+    }
+  
   switch (code)
     {
     case LABEL_DECL:
@@ -5160,6 +5242,38 @@ expand_expr (exp, target, tmode, modifie
 	  return temp;
 	}
 
+      if (GET_CODE (DECL_RTL (exp)) == CONCAT
+	  && COMPLEX_MODE_P (GET_MODE (DECL_RTL (exp)))
+	  && GET_MODE (DECL_RTL (exp)) != mode)
+	{
+	  rtx realpart;
+	  rtx imagpart;
+	  enum machine_mode submode_orig = COMPLEX_SUBMODE (mode);
+	  enum machine_mode submode_final
+	    = promote_mode (type_for_mode (submode_orig,
+					   TREE_UNSIGNED (type)),
+			    submode_orig, &unsignedp, 0);
+	  enum machine_mode promoted_mode
+	    = mode_for_size (2 * GET_MODE_SIZE (submode_final)
+			     * BITS_PER_UNIT, GET_MODE_CLASS (mode), 0);
+	  /* Get the signedness used for this variable.  Ensure we get the
+	     same mode we got when the variable was declared.  */
+	  if (GET_MODE (DECL_RTL (exp)) != promoted_mode)
+	    abort ();
+
+	  realpart = gen_rtx (SUBREG, submode_orig,
+			      XEXP (DECL_RTL (exp), 0), 0);
+	  imagpart = gen_rtx (SUBREG, submode_orig,
+			      XEXP (DECL_RTL (exp), 1), 0);
+	  SUBREG_PROMOTED_VAR_P (realpart) = 1;
+	  SUBREG_PROMOTED_UNSIGNED_P (realpart) = unsignedp;
+	  SUBREG_PROMOTED_VAR_P (imagpart) = 1;
+	  SUBREG_PROMOTED_UNSIGNED_P (imagpart) = unsignedp;
+
+	  temp = gen_rtx (CONCAT, mode, realpart, imagpart);
+	  return temp;
+	}
+
       return DECL_RTL (exp);
 
     case INTEGER_CST:
@@ -5789,8 +5903,7 @@ expand_expr (exp, target, tmode, modifie
 	    || (modifier != EXPAND_CONST_ADDRESS
 		&& modifier != EXPAND_INITIALIZER
 		&& ((mode1 != BLKmode && ! direct_load[(int) mode1]
-		     && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
-		     && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
+		     && ! COMPLEX_MODE_P (mode))
 		    /* If the field isn't aligned enough to fetch as a memref,
 		       fetch it as a bit field.  */
 		    || (SLOW_UNALIGNED_ACCESS
@@ -6493,8 +6606,7 @@ expand_expr (exp, target, tmode, modifie
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
 
       /* Handle complex values specially.  */
-      if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
-	  || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+      if (COMPLEX_MODE_P (mode))
 	return expand_complex_abs (mode, op0, target, unsignedp);
 
       /* Unsigned abs is simply the operand.  Testing here means we don't
@@ -10396,8 +10508,7 @@ do_jump (exp, if_false_label, if_true_la
 
 	if (integer_zerop (TREE_OPERAND (exp, 1)))
 	  do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
-	else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
-		 || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
+	else if (COMPLEX_MODE_P (TYPE_MODE (inner_type)))
 	  do_jump
 	    (fold
 	     (build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp),
@@ -10430,8 +10541,7 @@ do_jump (exp, if_false_label, if_true_la
 
 	if (integer_zerop (TREE_OPERAND (exp, 1)))
 	  do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-	else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
-		 || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
+	else if (COMPLEX_MODE_P (TYPE_MODE (inner_type)))
 	  do_jump
 	    (fold
 	     (build (TRUTH_ORIF_EXPR, TREE_TYPE (exp),
--- gcc/function.c.orig	Mon Dec 15 02:04:57 1997
+++ gcc/function.c	Wed Jan  7 16:42:46 1998
@@ -3523,7 +3523,9 @@ aggregate_value_p (exp)
   else
     type = TREE_TYPE (exp);
 
-  if (RETURN_IN_MEMORY (type))
+  if (RETURN_IN_MEMORY (COMPLEX_MODE_P (TYPE_MODE (type))?
+			type_for_mode (COMPLEX_SUBMODE (TYPE_MODE (type)), 0)
+			: type))
     return 1;
   /* Types that are TREE_ADDRESSABLE must be constructed in memory,
      and thus can't be returned in registers.  */
@@ -3541,7 +3543,10 @@ aggregate_value_p (exp)
     return 0;
 
   regno = REGNO (reg);
-  nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
+  if (! COMPLEX_MODE_P (GET_MODE (reg)))
+    nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
+  else
+    nregs = 2*HARD_REGNO_NREGS (regno, COMPLEX_SUBMODE (TYPE_MODE (type)));
   for (i = 0; i < nregs; i++)
     if (! call_used_regs[regno + i])
       return 1;
@@ -3661,7 +3666,13 @@ assign_parms (fndecl, second_time)
       int did_conversion = 0;
       tree passed_type = DECL_ARG_TYPE (parm);
       tree nominal_type = TREE_TYPE (parm);
-
+      enum machine_mode submode;
+      tree subtype;
+      int nregs = 0;
+      int nregs_real = 0;
+      int nregs_imag = 0;
+      int in_regs;
+      
       /* Set LAST_NAMED if this is last named arg before some
 	 anonymous args.  We treat it as if it were anonymous too.  */
       int last_named = ((TREE_CHAIN (parm) == 0
@@ -3714,8 +3725,14 @@ assign_parms (fndecl, second_time)
 	   && contains_placeholder_p (TYPE_SIZE (passed_type)))
 	  || TREE_ADDRESSABLE (passed_type)
 #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
-	  || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
-					      passed_type, ! last_named)
+	  || FUNCTION_ARG_PASS_BY_REFERENCE
+	     (args_so_far,
+	      (! COMPLEX_MODE_P (passed_mode))?
+	      passed_mode : COMPLEX_SUBMODE (passed_mode),
+	      (! COMPLEX_MODE_P (passed_mode))?
+	      passed_type : type_for_mode (COMPLEX_SUBMODE (passed_mode),
+					   0),
+	      ! last_named)
 #endif
 	  )
 	{
@@ -3725,25 +3742,31 @@ assign_parms (fndecl, second_time)
 	}
 
       promoted_mode = passed_mode;
+      unsignedp = TREE_UNSIGNED (passed_type);
 
+      if (COMPLEX_MODE_P (promoted_mode))
+	{
+	  submode = COMPLEX_SUBMODE (promoted_mode);
+	  subtype = type_for_mode (submode, unsignedp);
+	}
+      
 #ifdef PROMOTE_FUNCTION_ARGS
       /* Compute the mode in which the arg is actually extended to.  */
-      promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
-#endif
-
-      /* Let machine desc say which reg (if any) the parm arrives in.
-	 0 means it arrives on the stack.  */
-#ifdef FUNCTION_INCOMING_ARG
-      entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
-					  passed_type, ! last_named);
-#else
-      entry_parm = FUNCTION_ARG (args_so_far, promoted_mode,
-				 passed_type, ! last_named);
+      if (! COMPLEX_MODE_P (promoted_mode))
+	{
+	  promoted_mode = promote_mode (passed_type, promoted_mode,
+					&unsignedp, 1);
+	}
+      else
+	{
+	  submode = promote_mode (subtype, submode, &unsignedp, 1);
+	  subtype = type_for_mode (submode, unsignedp);
+	  promoted_mode = mode_for_size (2 * GET_MODE_SIZE (submode)
+					 * BITS_PER_UNIT,
+					 GET_MODE_CLASS (promoted_mode), 0);
+	}
 #endif
 
-      if (entry_parm == 0)
-	promoted_mode = passed_mode;
-
 #ifdef SETUP_INCOMING_VARARGS
       /* If this is the last named parameter, do any required setup for
 	 varargs or stdargs.  We need to know about the case of this being an
@@ -3764,6 +3787,121 @@ assign_parms (fndecl, second_time)
 	}
 #endif
 
+      if (! COMPLEX_MODE_P (promoted_mode))
+	{
+	  /* Let machine desc say which reg (if any) the parm arrives in.
+	     0 means it arrives on the stack.  */
+#ifdef FUNCTION_INCOMING_ARG
+	  entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
+					      passed_type, ! last_named);
+#else
+	  entry_parm = FUNCTION_ARG (args_so_far, promoted_mode,
+				     passed_type, ! last_named);
+#endif
+
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+	  if (entry_parm)
+	    nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
+						passed_type, ! last_named);
+#endif
+
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+	  in_regs = 1;
+#else
+#ifdef FUNCTION_INCOMING_ARG
+	  in_regs = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
+					   passed_type,
+					   (! last_named
+					    || varargs_setup)) != 0;
+#else
+	  in_regs = FUNCTION_ARG (args_so_far, promoted_mode,
+				  passed_type,
+				  ! last_named || varargs_setup) != 0;
+#endif
+#endif
+
+	  /* Update info on where next arg arrives in registers.  */
+	  FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
+				passed_type, ! last_named);
+	}
+      else
+	{
+	  rtx realpart;
+	  rtx imagpart;
+	  int in_regs_real;
+	  int in_regs_imag;
+	  
+#ifdef FUNCTION_INCOMING_ARG
+	  realpart = FUNCTION_INCOMING_ARG (args_so_far, submode,
+					    subtype, ! last_named);
+#else
+	  realpart = FUNCTION_ARG (args_so_far, submode,
+				   subtype, ! last_named);
+#endif
+
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+	  if (realpart)
+	    nregs_real = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, submode,
+						     subtype, ! last_named);
+#endif
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+	  in_regs_real = 1;
+#else
+#ifdef FUNCTION_INCOMING_ARG
+	  in_regs_real = FUNCTION_INCOMING_ARG (args_so_far, submode, subtype,
+						(! last_named
+						 || varargs_setup)) != 0;
+#else
+	  in_regs_real = FUNCTION_ARG (args_so_far, submode, subtype,
+				       ! last_named || varargs_setup) != 0;
+#endif
+#endif
+
+	  FUNCTION_ARG_ADVANCE (args_so_far, submode,
+				subtype, !last_named);
+#ifdef FUNCTION_INCOMING_ARG
+	  imagpart = FUNCTION_INCOMING_ARG (args_so_far, submode,
+					    subtype, ! last_named);
+#else
+	  imagpart = FUNCTION_ARG (args_so_far, submode,
+				   subtype, ! last_named);
+#endif
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+	  if (imagpart)
+	    nregs_imag = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, submode,
+						     subtype, ! last_named);
+#endif
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+	  in_regs_imag = 1;
+#else
+#ifdef FUNCTION_INCOMING_ARG
+	  in_regs_imag = FUNCTION_INCOMING_ARG (args_so_far, submode, subtype,
+						(! last_named
+						 || varargs_setup)) != 0;
+#else
+	  in_regs_imag = FUNCTION_ARG (args_so_far, submode, subtype,
+				       ! last_named || varargs_setup) != 0;
+#endif
+#endif
+
+	  FUNCTION_ARG_ADVANCE (args_so_far, submode,
+				subtype, !last_named);
+	  if (realpart == 0 && imagpart == 0)
+	    in_regs = in_regs_real;
+	  else if (imagpart)
+	    in_regs = in_regs_imag;
+	  else if (realpart)
+	    in_regs = in_regs_real;
+	  
+	  if (realpart != 0)
+	    entry_parm = gen_rtx (CONCAT, promoted_mode, realpart, imagpart);
+	  else
+	    entry_parm = 0;
+	}
+      
+      if (entry_parm == 0)
+	promoted_mode = passed_mode;
+
       /* Determine parm's home in the stack,
 	 in case it arrives in the stack or we should pretend it did.
 
@@ -3777,40 +3915,114 @@ assign_parms (fndecl, second_time)
 	 In this case, we call FUNCTION_ARG with NAMED set to 1 instead of
 	 0 as it was the previous time.  */
 
-      locate_and_pad_parm (promoted_mode, passed_type,
-#ifdef STACK_PARMS_IN_REG_PARM_AREA
-			   1,
-#else
-#ifdef FUNCTION_INCOMING_ARG
-			   FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
-						  passed_type,
-						  (! last_named
-						   || varargs_setup)) != 0,
-#else
-			   FUNCTION_ARG (args_so_far, promoted_mode,
-					 passed_type,
-					 ! last_named || varargs_setup) != 0,
-#endif
+      {
+	enum machine_mode pad_mode = promoted_mode;
+	tree pad_type = passed_type;
+	
+	if (COMPLEX_MODE_P (promoted_mode) && entry_parm != 0
+#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+	    && REG_PARM_STACK_SPACE (fndecl) == 0
 #endif
-			   fndecl, &stack_args_size, &stack_offset, &arg_size);
-
-      if (! second_time)
-	{
-	  rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
+	    )
+	  {
+	    /* If we do not need to allocate stack space for
+	       arguments passing in register, and the real part
+	       of a complex argument is passing in register,
+	       we only allocate stack space for the imaginary part. */
+	    if (XEXP (entry_parm, 0) != 0 && nregs_real == 0
+		&& (XEXP (entry_parm, 1) == 0 || nregs_imag > 0))
+	      {
+		pad_mode = COMPLEX_SUBMODE (passed_mode);
+		pad_type = type_for_mode (pad_mode, unsignedp);
+	      }
+	  }
+	locate_and_pad_parm (pad_mode, pad_type, in_regs,
+			     fndecl, &stack_args_size, &stack_offset,
+			     &arg_size);
+      
+	if (! second_time)
+	  {
+	    rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
 
-	  if (offset_rtx == const0_rtx)
-	    stack_parm = gen_rtx (MEM, promoted_mode, internal_arg_pointer);
-	  else
-	    stack_parm = gen_rtx (MEM, promoted_mode,
-				  gen_rtx (PLUS, Pmode,
-					   internal_arg_pointer, offset_rtx));
+	    if (! COMPLEX_MODE_P (promoted_mode))
+	      {
+		if (offset_rtx == const0_rtx)
+		  stack_parm = gen_rtx (MEM, promoted_mode,
+					internal_arg_pointer);
+		else
+		  stack_parm = gen_rtx (MEM, promoted_mode,
+					gen_rtx (PLUS, Pmode,
+						 internal_arg_pointer,
+						 offset_rtx));
+
+		/* If this is a memory ref that contains aggregate components,
+		   mark it as such for cse and loop optimize.  Likewise if it
+		   is readonly.  */
+		MEM_IN_STRUCT_P (stack_parm) = aggregate;
+		RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
+	      }
+	    else
+	      {
+		rtx realpart;
+		rtx imagpart;
+		int imag_offset;
+		enum machine_mode stack_mode = promoted_mode;
+		enum machine_mode sub_stack_mode;
+	      
+		if (entry_parm
+		    && XEXP (entry_parm, 0) != 0 && nregs_real == 0)
+		    stack_mode = passed_mode;
+		sub_stack_mode = COMPLEX_SUBMODE (stack_mode);
+
+		if (offset_rtx == const0_rtx)
+		  realpart = gen_rtx (MEM, sub_stack_mode,
+				      internal_arg_pointer);
+		else
+		  realpart = gen_rtx (MEM, sub_stack_mode,
+				      gen_rtx (PLUS, Pmode,
+					       internal_arg_pointer,
+					       offset_rtx));
+		MEM_IN_STRUCT_P (realpart) = aggregate;
+		RTX_UNCHANGING_P (realpart) = TREE_READONLY (parm);
 
-	  /* If this is a memory ref that contains aggregate components,
-	     mark it as such for cse and loop optimize.  Likewise if it
-	     is readonly.  */
-	  MEM_IN_STRUCT_P (stack_parm) = aggregate;
-	  RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
-	}
+		if (COMPLEX_MODE_P (pad_mode))
+		  {
+		    imag_offset = arg_size.constant / 2;
+		    stack_offset.constant += imag_offset;
+		    
+		    offset_rtx = ARGS_SIZE_RTX (stack_offset);
+		    imagpart = gen_rtx (MEM, sub_stack_mode,
+					gen_rtx (PLUS, Pmode,
+						 internal_arg_pointer,
+						 offset_rtx));
+		    MEM_IN_STRUCT_P (imagpart) = aggregate;
+		    RTX_UNCHANGING_P (imagpart) = TREE_READONLY (parm);
+		  }
+		else
+		  imagpart = 0;
+#ifdef ARGS_GROW_DOWNWARD
+		/* If the real part is passing in register, the imaginary
+		   part in stack only, and ARGS_GROW_DOWNWARD is defined,
+		   allocate the stack space for the imaginary part close to
+		   next argument. */
+	    if (COMPLEX_MODE_P (promoted_mode) && entry_parm != 0
+		&& XEXP (entry_parm, 0) != 0 && nregs_real == 0
+		&& (XEXP (entry_parm, 1) == 0 || nregs_imag > 0))
+	      {
+		rtx tmp = realpart;
+		realpart = imagpart;
+		imagpart = tmp;
+	      }
+#endif
+		if (COMPLEX_MODE_P (pad_mode))
+		  stack_parm = gen_rtx (CONCAT, stack_mode,
+					realpart, imagpart);
+		else
+		  stack_parm = gen_rtx (CONCAT, stack_mode,
+					imagpart, realpart);
+	      }
+	  }
+      }
 
       /* If this parameter was passed both in registers and in the stack,
 	 use the copy on the stack.  */
@@ -3826,15 +4038,49 @@ assign_parms (fndecl, second_time)
 	 we could put it together in a pseudoreg directly,
 	 but for now that's not worth bothering with.  */
 
-      if (entry_parm)
+      if (entry_parm != 0 && GET_CODE (entry_parm) == CONCAT
+	  && COMPLEX_MODE_P (GET_MODE (entry_parm)))
 	{
-	  int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
-						  passed_type, ! last_named);
+	  if (nregs_real > 0 || nregs_imag > 0
+	      || (XEXP (entry_parm, 0) && XEXP (entry_parm, 1) == 0))
+	    {
+	      if (nregs_real > 0 || nregs_imag > 0)
+		{
+		  current_function_pretend_args_size
+		    = ((((nregs_real + nregs_imag) * UNITS_PER_WORD)
+			+ (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
+		       / (PARM_BOUNDARY / BITS_PER_UNIT)
+		       * (PARM_BOUNDARY / BITS_PER_UNIT));
+		}
+	      if (! second_time)
+		{
+		  if (nregs_real > 0)
+		    move_block_from_reg (REGNO (XEXP (entry_parm, 0)),
+					 validize_mem (XEXP (stack_parm, 0)),
+					 nregs_real,
+					 int_size_in_bytes (DECL_ARG_TYPE
+							    (parm))/2);
+		  else if (nregs_imag > 0)
+		    move_block_from_reg (REGNO (XEXP (entry_parm, 1)),
+					 validize_mem (XEXP (stack_parm, 1)),
+					 nregs_imag,
+					 int_size_in_bytes (DECL_ARG_TYPE
+							    (parm))/2);
+		}
 
+	      if (XEXP (entry_parm, 0) && nregs_real == 0)
+		XEXP (entry_parm, 1) = stack_parm ? XEXP (stack_parm, 1) : 0;
+	      else
+		entry_parm = stack_parm;
+	    }
+	}
+      else if (entry_parm)
+	{
 	  if (nregs > 0)
 	    {
 	      current_function_pretend_args_size
-		= (((nregs * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
+		= (((nregs * UNITS_PER_WORD)
+		    + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
 		   / (PARM_BOUNDARY / BITS_PER_UNIT)
 		   * (PARM_BOUNDARY / BITS_PER_UNIT));
 
@@ -3869,6 +4115,8 @@ assign_parms (fndecl, second_time)
 	 to indicate there is no preallocated stack slot for the parm.  */
 
       if (entry_parm == stack_parm
+	  || (COMPLEX_MODE_P (promoted_mode) && entry_parm && stack_parm
+	      && XEXP (entry_parm, 1) == XEXP (stack_parm, 1))
 #if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
 	  /* On some machines, even if a parm value arrives in a register
 	     there is still an (uninitialized) stack slot allocated for it.
@@ -3891,11 +4139,6 @@ assign_parms (fndecl, second_time)
 	/* No stack slot was pushed for this parm.  */
 	stack_parm = 0;
 
-      /* Update info on where next arg arrives in registers.  */
-
-      FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
-			    passed_type, ! last_named);
-
       /* If this is our second time through, we are done with this parm.  */
       if (second_time)
 	continue;
@@ -3970,6 +4213,16 @@ assign_parms (fndecl, second_time)
 
       if (GET_CODE (entry_parm) == REG && !(hide_last_arg && last_named))
 	  emit_insn (gen_rtx (USE, GET_MODE (entry_parm), entry_parm));
+      else if (GET_CODE (entry_parm) == CONCAT
+	       && !(hide_last_arg && last_named))
+	{
+	  if (GET_CODE (XEXP (entry_parm, 0)) == REG)
+	    emit_insn (gen_rtx (USE, GET_MODE (XEXP (entry_parm, 0)),
+				XEXP (entry_parm, 0)));
+	  if (GET_CODE (XEXP (entry_parm, 1)) == REG)
+	    emit_insn (gen_rtx (USE, GET_MODE (XEXP (entry_parm, 1)),
+				XEXP (entry_parm, 1)));
+	}
 #endif
 
       /* ENTRY_PARM is an RTX for the parameter as it arrives,
@@ -4056,12 +4309,38 @@ assign_parms (fndecl, second_time)
 
 	  unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
 
-	  promoted_nominal_mode
-	    = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
-
-	  parmreg = gen_reg_rtx (promoted_nominal_mode);
-	  mark_user_reg (parmreg);
-
+	  if (! COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (parm))))
+	    {
+	      promoted_nominal_mode
+		= promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
+	      
+	      parmreg = gen_reg_rtx (promoted_nominal_mode);
+	      mark_user_reg (parmreg);
+	    }
+	  else
+	    {
+	      enum machine_mode submode_nominal
+		= COMPLEX_SUBMODE (nominal_mode);
+	      rtx realpart;
+	      rtx imagpart;
+	      
+	      submode_nominal
+		= promote_mode (type_for_mode (submode_nominal, unsignedp),
+				submode_nominal, &unsignedp, 0);
+	      promoted_nominal_mode
+		= mode_for_size (2 * GET_MODE_SIZE (submode_nominal)
+				 * BITS_PER_UNIT,
+				GET_MODE_CLASS (nominal_mode), 0);
+	      
+	      realpart = gen_reg_rtx (submode_nominal);
+	      imagpart = gen_reg_rtx (submode_nominal);
+
+	      parmreg = gen_rtx (CONCAT, promoted_nominal_mode,
+				 realpart, imagpart);
+	      mark_user_reg (realpart);
+	      mark_user_reg (imagpart);
+	    }
+	    
 	  /* If this was an item that we received a pointer to, set DECL_RTL
 	     appropriately.  */
 	  if (passed_pointer)
@@ -4075,7 +4354,10 @@ assign_parms (fndecl, second_time)
 
 	  /* Copy the value into the register.  */
 	  if (nominal_mode != passed_mode
-	      || promoted_nominal_mode != promoted_mode)
+	      || promoted_nominal_mode != promoted_mode
+	      || (COMPLEX_MODE_P (passed_mode)
+		  && GET_MODE (XEXP (entry_parm, 0))
+		  != GET_MODE (XEXP (entry_parm, 1))))
 	    {
 	      /* ENTRY_PARM has been converted to PROMOTED_MODE, its
 		 mode, by the caller.  We now have to convert it to 
@@ -4096,22 +4378,60 @@ assign_parms (fndecl, second_time)
 		 a pseudo reg here, and save the conversion until after all
 		 parameters have been moved.  */
 
-	      rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
+	      if (! COMPLEX_MODE_P (GET_MODE (entry_parm)))
+		{
+		  rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
 
-	      emit_move_insn (tempreg, validize_mem (entry_parm));
+		  emit_move_insn (tempreg, validize_mem (entry_parm));
 
-	      push_to_sequence (conversion_insns);
-	      tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
+		  push_to_sequence (conversion_insns);
+		  tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
 
-	      expand_assignment (parm,
-				 make_tree (nominal_type, tempreg), 0, 0);
-	      conversion_insns = get_insns ();
-	      did_conversion = 1;
-	      end_sequence ();
+		  expand_assignment (parm,
+				     make_tree (nominal_type, tempreg), 0, 0);
+		  conversion_insns = get_insns ();
+		  did_conversion = 1;
+		  end_sequence ();
+		}
+	      else
+		{
+		  rtx realpart = gen_reg_rtx (GET_MODE (XEXP (entry_parm, 0)));
+		  rtx imagpart = gen_reg_rtx (GET_MODE (XEXP (entry_parm, 1)));
+		  enum machine_mode submode_nominal
+		    = COMPLEX_SUBMODE (nominal_mode);
+		  rtx tempreg;
+		  
+		  emit_move_insn (realpart,
+				  validize_mem (XEXP (entry_parm, 0)));
+		  emit_move_insn (imagpart,
+				  validize_mem (XEXP (entry_parm, 1)));
+
+		  push_to_sequence (conversion_insns);
+		  realpart = convert_to_mode (submode_nominal, realpart, unsignedp);
+		  imagpart = convert_to_mode (submode_nominal, imagpart, unsignedp);
+		  tempreg = gen_rtx (CONCAT, nominal_mode,
+				     realpart, imagpart);
+		  
+		  expand_assignment (parm,
+				     make_tree (nominal_type, tempreg), 0, 0);
+		  conversion_insns = get_insns ();
+		  did_conversion = 1;
+		  end_sequence ();
+		}
 	    }
 	  else
-	    emit_move_insn (parmreg, validize_mem (entry_parm));
-
+	    {
+	      if (! COMPLEX_MODE_P (GET_MODE (entry_parm)))
+		emit_move_insn (parmreg, validize_mem (entry_parm));
+	      else
+		{
+		  emit_move_insn (XEXP (parmreg, 0),
+				  validize_mem (XEXP (entry_parm, 0)));
+		  emit_move_insn (XEXP (parmreg, 1),
+				  validize_mem (XEXP (entry_parm, 1)));
+		}
+	    }
+	  
 	  /* If we were passed a pointer but the actual value
 	     can safely live in a register, put it in one.  */
 	  if (passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode
@@ -4145,10 +4465,16 @@ assign_parms (fndecl, second_time)
 	     modified, don't do the copy.  */
 
 	  else if (passed_pointer
-		   && FUNCTION_ARG_CALLEE_COPIES (args_so_far,
-						  TYPE_MODE (DECL_ARG_TYPE (parm)),
-						  DECL_ARG_TYPE (parm),
-						  ! last_named)
+		   && FUNCTION_ARG_CALLEE_COPIES
+		   (args_so_far,
+		    (! COMPLEX_MODE_P (TYPE_MODE (DECL_ARG_TYPE (parm))))?
+		    TYPE_MODE (DECL_ARG_TYPE (parm))
+		    : COMPLEX_SUBMODE (TYPE_MODE (DECL_ARG_TYPE (parm))),
+		    (! COMPLEX_MODE_P (TYPE_MODE (DECL_ARG_TYPE (parm))))?
+		    DECL_ARG_TYPE (parm)
+		    : type_for_mode (COMPLEX_SUBMODE (TYPE_MODE (DECL_ARG_TYPE (parm))),
+				     0),
+		    ! last_named)
 		   && ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
 	    {
 	      rtx copy;
@@ -4219,15 +4545,13 @@ assign_parms (fndecl, second_time)
 	    {
 	      enum machine_mode submode = GET_MODE (XEXP (parmreg, 0));
 
-	      regnor = REGNO (gen_realpart (submode, parmreg));
-	      regnoi = REGNO (gen_imagpart (submode, parmreg));
+	      regnor = REGNO (XEXP (parmreg, 0));
+	      regnoi = REGNO (XEXP (parmreg, 1));
 
 	      if (stack_parm != 0)
 		{
-		  parm_reg_stack_loc[regnor]
-		    = gen_realpart (submode, stack_parm);
-		  parm_reg_stack_loc[regnoi]
-		    = gen_imagpart (submode, stack_parm);
+		  parm_reg_stack_loc[regnor] = XEXP (stack_parm, 0);
+		  parm_reg_stack_loc[regnoi] = XEXP (stack_parm, 1);
 		}
 	      else
 		{
@@ -4294,53 +4618,157 @@ assign_parms (fndecl, second_time)
 	  /* Value must be stored in the stack slot STACK_PARM
 	     during function execution.  */
 
-	  if (promoted_mode != nominal_mode)
+	  if (! COMPLEX_MODE_P (promoted_mode))
 	    {
-	      /* Conversion is required.   */
-	      rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
-
-	      emit_move_insn (tempreg, validize_mem (entry_parm));
+	      if (promoted_mode != nominal_mode)
+		{
+		  /* Conversion is required.   */
+		  rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
+		  
+		  emit_move_insn (tempreg, validize_mem (entry_parm));
+		  
+		  push_to_sequence (conversion_insns);
+		  entry_parm
+		    = convert_to_mode (nominal_mode, tempreg,
+				       TREE_UNSIGNED (TREE_TYPE (parm)));
+		  if (stack_parm)
+		    {
+		      /* ??? This may need a big-endian conversion on sparc64.  */
+		      stack_parm = change_address (stack_parm, nominal_mode,
+						   NULL_RTX);
+		    }
+		  conversion_insns = get_insns ();
+		  did_conversion = 1;
+		  end_sequence ();
+		}
+	    }
+	  else
+	    {
+	      enum machine_mode submode_nominal
+		= COMPLEX_SUBMODE (nominal_mode);
+	      rtx realpart;
+	      rtx imagpart;
+	      int unsignedp1 = TREE_UNSIGNED (TREE_TYPE (parm));
 
-	      push_to_sequence (conversion_insns);
-	      entry_parm = convert_to_mode (nominal_mode, tempreg,
-					    TREE_UNSIGNED (TREE_TYPE (parm)));
-	      if (stack_parm)
+	      if (GET_MODE (XEXP (entry_parm, 0)) != submode_nominal)
 		{
-		  /* ??? This may need a big-endian conversion on sparc64.  */
-		  stack_parm = change_address (stack_parm, nominal_mode,
-					       NULL_RTX);
+		  realpart = gen_reg_rtx (submode);
+		  emit_move_insn (realpart,
+				  validize_mem (XEXP (entry_parm, 0)));
+		  push_to_sequence (conversion_insns);
+		  realpart = convert_to_mode (submode_nominal, realpart,
+					      unsignedp1);
+		  conversion_insns = get_insns ();
+		  did_conversion = 1;
+		  end_sequence ();
 		}
-	      conversion_insns = get_insns ();
-	      did_conversion = 1;
-	      end_sequence ();
+	      else
+		realpart = XEXP (entry_parm, 0);
+	      
+	      if (GET_MODE (XEXP (entry_parm, 1)) != submode_nominal)
+		{
+		  imagpart = gen_reg_rtx (submode);
+		  emit_move_insn (imagpart,
+				  validize_mem (XEXP (entry_parm, 1)));
+		  push_to_sequence (conversion_insns);
+		  imagpart = convert_to_mode (submode_nominal, imagpart,
+					      unsignedp1);
+		  conversion_insns = get_insns ();
+		  did_conversion = 1;
+		  end_sequence ();
+		}
+	      else
+		imagpart = XEXP (entry_parm, 1);
+
+	      if (GET_MODE (XEXP (entry_parm, 0)) != submode_nominal
+		  || GET_MODE (XEXP (entry_parm, 1)) != submode_nominal)
+		entry_parm = gen_rtx (CONCAT, nominal_mode,
+				      realpart, imagpart);
 	    }
 
 	  if (entry_parm != stack_parm)
 	    {
-	      if (stack_parm == 0)
+	      enum machine_mode entry_mode = GET_MODE (entry_parm);
+		  
+	      if (! COMPLEX_MODE_P (entry_mode))
 		{
-		  stack_parm
-		    = assign_stack_local (GET_MODE (entry_parm),
-					  GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
-		  /* If this is a memory ref that contains aggregate components,
-		     mark it as such for cse and loop optimize.  */
-		  MEM_IN_STRUCT_P (stack_parm) = aggregate;
+		  if (stack_parm == 0)
+		    {
+		      stack_parm
+			= assign_stack_local (GET_MODE (entry_parm),
+					      GET_MODE_SIZE (GET_MODE
+							     (entry_parm)), 0);
+		      /* If this is a memory ref that contains aggregate components,
+			 mark it as such for cse and loop optimize.  */
+		      MEM_IN_STRUCT_P (stack_parm) = aggregate;
+		    }
+		}
+	      else
+		{
+		  rtx realpart;
+		  rtx imagpart;
+		  enum machine_mode submode
+		    = COMPLEX_SUBMODE (entry_mode);
+
+		  if (stack_parm == 0 || XEXP (stack_parm, 0) == 0)
+		    {
+		      realpart
+			= assign_stack_local (submode,
+					      GET_MODE_SIZE (submode), 0);
+		      MEM_IN_STRUCT_P (realpart) = aggregate;
+		    }
+		  if (stack_parm == 0 || XEXP (stack_parm, 1) == 0)
+		    {
+		      imagpart
+			= assign_stack_local (submode,
+					      GET_MODE_SIZE (submode), 0);
+		      MEM_IN_STRUCT_P (imagpart) = aggregate;
+		    }
+		  if (stack_parm == 0)
+		    stack_parm = gen_rtx (CONCAT, entry_mode,
+					  realpart, imagpart);
+		  else if (XEXP (stack_parm, 0) == 0)
+		    XEXP (stack_parm, 0) = realpart;
+		  else if (XEXP (stack_parm, 1) == 0)
+		    XEXP (stack_parm, 1) = imagpart;
 		}
-
 	      if (promoted_mode != nominal_mode)
 		{
 		  push_to_sequence (conversion_insns);
-		  emit_move_insn (validize_mem (stack_parm),
-				  validize_mem (entry_parm));
+		  if (! COMPLEX_MODE_P (entry_mode))
+		    {
+		      emit_move_insn (validize_mem (stack_parm),
+				      validize_mem (entry_parm));
+		    }
+		  else
+		    {
+		      emit_move_insn (validize_mem (XEXP (stack_parm, 0)),
+				      validize_mem (XEXP (entry_parm, 0)));
+		      emit_move_insn (validize_mem (XEXP (stack_parm, 1)),
+				      validize_mem (XEXP (entry_parm, 1)));
+		    }
+		  
 		  conversion_insns = get_insns ();
 		  end_sequence ();
 		}
 	      else
-		emit_move_insn (validize_mem (stack_parm),
-				validize_mem (entry_parm));
+		{
+		  if (! COMPLEX_MODE_P (entry_mode))
+		    {
+		      emit_move_insn (validize_mem (stack_parm),
+				      validize_mem (entry_parm));
+		    }
+		  else
+		    {
+		      emit_move_insn (validize_mem (XEXP (stack_parm, 0)),
+				      validize_mem (XEXP (entry_parm, 0)));
+		      emit_move_insn (validize_mem (XEXP (stack_parm, 1)),
+				      validize_mem (XEXP (entry_parm, 1)));
+		    }
+		}
 	    }
-	  if (flag_check_memory_usage)
-	    {
+  	  if (flag_check_memory_usage)
+  	    {
 	      push_to_sequence (conversion_insns);
 	      emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
 				 XEXP (stack_parm, 0), ptr_mode,
@@ -4511,12 +4939,32 @@ locate_and_pad_parm (passed_mode, type, 
      struct args_size *offset_ptr;
      struct args_size *arg_size_ptr;
 {
-  tree sizetree
-    = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
-  enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
-  int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
-  int boundary_in_bytes = boundary / BITS_PER_UNIT;
+  tree sizetree;
+  enum direction where_pad;
+  enum machine_mode mode;
+  int boundary;
+  int boundary_in_bytes;
   int reg_parm_stack_space = 0;
+  int i;
+  
+  if (! COMPLEX_MODE_P (passed_mode))
+    {
+      sizetree = type ? size_in_bytes (type)
+	: size_int (GET_MODE_SIZE (passed_mode));
+      where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
+      boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
+      mode = passed_mode;
+    }
+  else
+    {
+      tree subtype;
+      mode = COMPLEX_SUBMODE (passed_mode);
+      subtype = type_for_mode (mode, 0);
+      sizetree = size_int (GET_MODE_SIZE (mode));
+      where_pad = FUNCTION_ARG_PADDING (mode, subtype);
+      boundary = FUNCTION_ARG_BOUNDARY (mode, subtype);
+    }
+  boundary_in_bytes = boundary / BITS_PER_UNIT;
 
 #ifdef REG_PARM_STACK_SPACE
   /* If we have found a stack parm before we reach the end of the
@@ -4562,7 +5010,13 @@ locate_and_pad_parm (passed_mode, type, 
       && (TREE_CODE (sizetree) != INTEGER_CST
 	  || ((TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)))
     sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
-  SUB_PARM_SIZE (*offset_ptr, sizetree);
+  if (COMPLEX_MODE_P (passed_mode))
+    {
+      SUB_PARM_SIZE (*offset_ptr, sizetree);
+      SUB_PARM_SIZE (*offset_ptr, sizetree);
+    }
+  else
+    SUB_PARM_SIZE (*offset_ptr, sizetree);
   if (where_pad != downward)
     pad_to_arg_alignment (offset_ptr, boundary);
   if (initial_offset_ptr->var)
@@ -4593,14 +5047,20 @@ locate_and_pad_parm (passed_mode, type, 
     /* However, BLKmode args passed in regs have their padding done elsewhere.
        The stack slot must be able to hold the entire register.  */
       && !(in_regs && passed_mode == BLKmode))
-    pad_below (offset_ptr, passed_mode, sizetree);
+    pad_below (offset_ptr, mode, sizetree);
 
   if (where_pad != none
       && (TREE_CODE (sizetree) != INTEGER_CST
 	  || ((TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)))
     sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
 
-  ADD_PARM_SIZE (*arg_size_ptr, sizetree);
+  if (COMPLEX_MODE_P (passed_mode))
+    {
+      ADD_PARM_SIZE (*arg_size_ptr, sizetree);
+      ADD_PARM_SIZE (*arg_size_ptr, sizetree);
+    }
+  else
+    ADD_PARM_SIZE (*arg_size_ptr, sizetree);    
 #endif /* ARGS_GROW_DOWNWARD */
 }
 
@@ -5586,10 +6046,61 @@ expand_function_start (subr, parms_have_
       tree type = TREE_TYPE (DECL_RESULT (subr));
       int unsignedp = TREE_UNSIGNED (type);
 
-      mode = promote_mode (type, mode, &unsignedp, 1);
+      if (! COMPLEX_MODE_P (mode))
+	{
+	  mode = promote_mode (type, mode, &unsignedp, 1);
+	}
+      else
+	{
+	  enum machine_mode submode = COMPLEX_SUBMODE (mode);
+	  submode = promote_mode (type_for_mode (submode,
+						 TREE_UNSIGNED (type)),
+				  submode, &unsignedp, 1);
+	  mode = mode_for_size (2 * GET_MODE_SIZE (submode) * BITS_PER_UNIT,
+				GET_MODE_CLASS (mode), 0);
+	}
 #endif
 
       DECL_RTL (DECL_RESULT (subr)) = gen_reg_rtx (mode);
+    }
+  else if (COMPLEX_MODE_P (DECL_MODE (DECL_RESULT (subr))))
+    /* To return a complex value, using two registers. */
+    {
+      enum machine_mode mode = DECL_MODE (DECL_RESULT (subr));
+      enum machine_mode submode = COMPLEX_SUBMODE (mode);
+      rtx realpart;
+      int unsignedp = TREE_UNSIGNED (TREE_TYPE (DECL_RESULT (subr)));
+      tree parttree = type_for_mode (submode, unsignedp);
+      
+#ifdef FUNCTION_OUTGOING_VALUE
+      realpart = FUNCTION_OUTGOING_VALUE (parttree, subr);
+#else
+      realpart = FUNCTION_VALUE (parttree, subr);
+#endif
+
+      if (GET_CODE (realpart) == REG)
+	{
+#ifdef PROMOTE_FUNCTION_RETURN
+	  submode = promote_mode (type_for_mode (submode, unsignedp),
+				  submode, &unsignedp, 1);
+	  mode = mode_for_size (2 * GET_MODE_SIZE (submode)
+				* BITS_PER_UNIT,
+				GET_MODE_CLASS (mode), 0);
+#endif
+	  DECL_RTL (DECL_RESULT (subr))
+	    = gen_rtx (REG, mode, REGNO (realpart));
+	}
+      else
+	abort ();
+      
+      /* Mark this reg as the function's return value.  */
+      if (GET_CODE (DECL_RTL (DECL_RESULT (subr))) == REG)
+	{
+	  REG_FUNCTION_VALUE_P (DECL_RTL (DECL_RESULT (subr))) = 1;
+	  /* Needed because we may need to move this to memory
+	     in case it's a named return value whose address is taken.  */
+	  DECL_REGISTER (DECL_RESULT (subr)) = 1;
+	}
     }
   else
     /* Scalar, returned in a register.  */
--- gcc/integrate.c.orig	Thu Dec 18 17:42:35 1997
+++ gcc/integrate.c	Wed Jan  7 16:45:26 1998
@@ -1382,11 +1382,32 @@ expand_inline_function (fndecl, parms, t
 	  if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg)))
 	    /* The mode if LOC and ARG can differ if LOC was a variable
 	       that had its mode promoted via PROMOTED_MODE.  */
-	    arg_vals[i] = convert_modes (GET_MODE (loc),
-					 TYPE_MODE (TREE_TYPE (arg)),
-					 expand_expr (arg, NULL_RTX, mode,
-						      EXPAND_SUM),
-					 TREE_UNSIGNED (TREE_TYPE (formal)));
+	    {
+	      if (! COMPLEX_MODE_P (GET_MODE (loc)))
+		arg_vals[i]
+		  = convert_modes (GET_MODE (loc),
+				   TYPE_MODE (TREE_TYPE (arg)),
+				   expand_expr (arg, NULL_RTX, mode,
+						EXPAND_SUM),
+				   TREE_UNSIGNED (TREE_TYPE (formal)));
+	      else
+		{
+		  rtx temp = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
+		  enum machine_mode mode_orig
+		    = COMPLEX_SUBMODE (TYPE_MODE (TREE_TYPE (arg)));
+		  enum machine_mode mode_final
+		    = COMPLEX_SUBMODE (GET_MODE (loc));
+		  rtx realpart = gen_realpart (mode_orig, temp);
+		  rtx imagpart = gen_imagpart (mode_orig, temp);
+
+		  realpart = convert_modes (mode_final, mode_orig, realpart,
+					    TREE_UNSIGNED (TREE_TYPE (formal)));
+		  imagpart = convert_modes (mode_final, mode_orig, imagpart,
+					    TREE_UNSIGNED (TREE_TYPE (formal)));
+		  arg_vals[i] = gen_rtx (CONCAT, GET_MODE (loc),
+					 realpart, imagpart);
+		}
+	    }
 	  else
 	    arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
 	}
@@ -1750,7 +1771,8 @@ expand_inline_function (fndecl, parms, t
       /* If function's value was promoted before return,
 	 avoid machine mode mismatch when we substitute INLINE_TARGET.
 	 But TARGET is what we will return to the caller.  */
-      if (arriving_mode != departing_mode)
+      if (arriving_mode != departing_mode
+	  && ! COMPLEX_MODE_P (arriving_mode))
 	{
 	  /* Avoid creating a paradoxical subreg wider than
 	     BITS_PER_WORD, since that is illegal.  */
@@ -1765,6 +1787,41 @@ expand_inline_function (fndecl, parms, t
 	    }
 	  else
 	    reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0);
+	}
+      else if (arriving_mode != departing_mode)
+	{
+	  /* Deal with complex return. */
+	  enum machine_mode submode = COMPLEX_SUBMODE (departing_mode);
+	  enum machine_mode promoted_submode
+	    = COMPLEX_SUBMODE (arriving_mode);
+	  rtx realpart;
+	  rtx imagpart;
+	  
+	  /* Avoid creating a paradoxical subreg wider than
+	     BITS_PER_WORD, since that is illegal.  */
+	  if (GET_MODE_BITSIZE (promoted_submode) > BITS_PER_WORD)
+	    {
+	      if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (submode),
+					  GET_MODE_BITSIZE (promoted_submode)))
+		/* Maybe could be handled by using convert_move () ?  */
+		abort ();
+	      reg_to_map = gen_reg_rtx (arriving_mode);
+	      realpart = gen_lowpart (submode,
+				      gen_realpart (promoted_submode,
+						    reg_to_map));
+	      imagpart = gen_lowpart (submode,
+				      gen_imagpart (promoted_submode,
+						    reg_to_map));
+	      target = gen_rtx (CONCAT, departing_mode, realpart, imagpart);
+	    }
+	  else
+	    {
+	      realpart = gen_rtx (SUBREG, promoted_submode,
+				  gen_realpart (submode, target), 0);
+	      imagpart = gen_rtx (SUBREG, promoted_submode,
+				  gen_imagpart (submode, target), 0);
+	      reg_to_map = gen_rtx (CONCAT, arriving_mode, realpart, imagpart);
+	    }
 	}
       else
 	reg_to_map = target;
--- gcc/machmode.h.orig	Mon Aug 11 11:57:11 1997
+++ gcc/machmode.h	Wed Jan  7 11:48:11 1998
@@ -164,6 +164,17 @@ extern enum mode_class mode_class[];
   (GET_MODE_CLASS (MODE) == MODE_FLOAT	\
    || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)
 
+/* Nonzero if MODE is a complex mode.  */
+#define COMPLEX_MODE_P(MODE)			\
+  (GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT	\
+   || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)
+
+/* Determine the mode for the imaginary and real part of a complex MODE. */
+#define COMPLEX_SUBMODE(MODE) \
+mode_for_size (GET_MODE_UNIT_SIZE(MODE)*BITS_PER_UNIT, \
+		(GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT)? \
+		MODE_INT:MODE_FLOAT, 0)
+
 /* Get the size in bytes of an object of mode MODE.  */
 
 extern int mode_size[];
--- gcc/recog.c.orig	Sat Dec  6 12:21:30 1997
+++ gcc/recog.c	Tue Jan  6 17:27:00 1998
@@ -898,8 +898,7 @@ register_operand (op, mode)
 				REGNO (SUBREG_REG (op)))
 	  && (GET_MODE_SIZE (mode)
 	      != GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
-	  && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_INT
-	  && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_FLOAT)
+	  && ! COMPLEX_MODE_P (GET_MODE (SUBREG_REG (op))))
 	return 0;
 #endif
 
--- gcc/regs.h.orig	Sun Nov  2 03:40:47 1997
+++ gcc/regs.h	Tue Jan  6 17:27:01 1998
@@ -27,7 +27,10 @@ Boston, MA 02111-1307, USA.  */
    valid way to get this value.  You cannot get it from the regno.  */
 
 #define REG_SIZE(R) \
-  ((mode_size[(int) GET_MODE (R)] + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+  (GET_MODE_SIZE (GET_MODE (R)) == 0?					\
+   0:(((GET_MODE_UNIT_SIZE (GET_MODE (R)) + (UNITS_PER_WORD - 1))	\
+      / UNITS_PER_WORD) * (GET_MODE_SIZE (GET_MODE (R))			\
+      / GET_MODE_UNIT_SIZE (GET_MODE (R)))))
 
 #ifndef SMALL_REGISTER_CLASSES
 #define SMALL_REGISTER_CLASSES 0
--- gcc/reload.c.orig	Mon Dec 15 12:55:27 1997
+++ gcc/reload.c	Tue Jan  6 23:30:05 1998
@@ -2370,6 +2370,21 @@ find_reloads (insn, replace, ind_levels,
 	  && REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
 				 REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
 	return;
+      if (GET_CODE (SET_DEST (body)) == SUBREG
+	  && GET_CODE (SUBREG_REG (SET_DEST (body))) == REG
+	  && COMPLEX_MODE_P (GET_MODE (SUBREG_REG (SET_DEST (body)))))
+	{
+	  rtx complex_dest = SUBREG_REG (SET_DEST (body));
+	  int regno = REGNO (complex_dest) + SUBREG_WORD (SET_DEST (body));
+	  
+	  if (regno < FIRST_PSEUDO_REGISTER
+	      && GET_CODE (SET_SRC (body)) == REG
+	      && REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
+	      && REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
+				     REGNO_REG_CLASS (regno)) == 2)
+	    return;
+	}
+      
     case PARALLEL:
     case ASM_OPERANDS:
       reload_n_operands = noperands = asm_noperands (body);
@@ -2768,6 +2783,7 @@ find_reloads (insn, replace, ind_levels,
 		     or which would handle that mode in the wrong number of
 		     registers for subregging to work.  */
 		  || (GET_CODE (operand) == REG
+		      && !COMPLEX_MODE_P (GET_MODE (operand))
 		      && REGNO (operand) < FIRST_PSEUDO_REGISTER
 		      && ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
 			   && (GET_MODE_SIZE (GET_MODE (operand))
--- gcc/stmt.c.orig	Fri Dec 19 11:41:53 1997
+++ gcc/stmt.c	Wed Jan  7 16:47:02 1998
@@ -2620,19 +2620,59 @@ expand_value_return (val)
 #ifdef PROMOTE_FUNCTION_RETURN
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
       int unsignedp = TREE_UNSIGNED (type);
-      enum machine_mode mode
-	= promote_mode (type, DECL_MODE (DECL_RESULT (current_function_decl)),
-			&unsignedp, 1);
+      enum machine_mode mode_orig
+	= DECL_MODE (DECL_RESULT (current_function_decl));
+      enum machine_mode mode;
+      enum machine_mode submode;
+      enum machine_mode promoted_submode;
 
+      if (! COMPLEX_MODE_P (mode_orig))
+	{
+	  mode = promote_mode (type, mode_orig, &unsignedp, 1);
+	}
+      else
+	{
+	  submode = COMPLEX_SUBMODE (mode_orig);
+	  promoted_submode
+	    = promote_mode (type_for_mode (submode, unsignedp),
+			    submode, &unsignedp, 1);
+	  mode = mode_for_size (2 * GET_MODE_SIZE (promoted_submode)
+				* BITS_PER_UNIT,
+				GET_MODE_CLASS (mode_orig), 0);
+	}
+      
       if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
-	convert_move (return_reg, val, unsignedp);
+	{
+	  if (! COMPLEX_MODE_P (mode))
+	    convert_move (return_reg, val, unsignedp);
+	  else
+	    {
+	      convert_move (gen_realpart (promoted_submode, return_reg),
+			    gen_realpart (submode, val), unsignedp);
+	      convert_move (gen_imagpart (promoted_submode, return_reg),
+			    gen_imagpart (submode, val), unsignedp);
+	    }
+	}   
       else
 #endif
 	emit_move_insn (return_reg, val);
     }
   if (GET_CODE (return_reg) == REG
       && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
-    emit_insn (gen_rtx (USE, VOIDmode, return_reg));
+    {
+      if (! COMPLEX_MODE_P (GET_MODE (return_reg)))
+	emit_insn (gen_rtx (USE, VOIDmode, return_reg));
+      else
+	{
+	  enum machine_mode submode = COMPLEX_SUBMODE (GET_MODE (return_reg));
+	  int n = 2 * HARD_REGNO_NREGS (REGNO (return_reg), submode);
+	  int k;
+
+	  for (k = 0; k < n; k ++)
+	    emit_insn (gen_rtx (USE, VOIDmode,
+			      gen_rtx (REG, submode, REGNO (return_reg) + k)));
+	}
+    }
   /* Handle calls that return values in multiple non-contiguous locations.
      The Irix 6 ABI has examples of this.  */
   else if (GET_CODE (return_reg) == PARALLEL)



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

* Patch for COMPLEX support (part 2)
@ 1998-01-08  6:05 Weiwen Liu
  0 siblings, 0 replies; 2+ messages in thread
From: Weiwen Liu @ 1998-01-08  6:05 UTC (permalink / raw)
  To: egcs

I sent part 2 of this patch yesterday, but it never shows up.

Is there a limit on the length of a message enforced on egcs mailing list?

I am sending part 2 now after it is gzipped.

Wed Jan  7 17:30:00 1998  Weiwen Liu <liu@hepunix.physics.yale.edu>

	 * machmode.h: define COMPLEX_MODE_P, COMPLEX_SUBMODE.

	 * regs.h (REG_SIZE): Consider complex modes.

	 * calls.c (arg_data): Add partial_real and partial_imag to
	 record the number of registers used for real/imaginary part.

	 * combine.c (expand_field_assignment): Exclude SUBREG of a
         COMPLEX.

	 * explow.c (hard_function_value): Promote COMPLEX return
	 value if required.

	 * calls.c (expand_call): Deal with arguments of complex modes.
	   (store_one_arg): Likewise.
	 * emit-rtl.c (gen_lowpart_common): Likewise.
	 (gen_highpart): Likewise.
	 * expr.c (store_expr): Likewise.
	 (expand_expr): Likewise.
	 * function.c (aggregate_value_p): Likewise.
	 (assign_parms): Likewise.
	 (locate_and_pad_parm): Likewise.
	 (expand_function_start): Likewise.
	 * integrate.c (expand_inline_function): Likewise.
	 * reload.c (find_reloads): Likewise.
	 * stmt.c (expand_value_return): Likewise.

begin 600 patch2.gz
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
CE#4\_A*AN)_QTX0DTVJ^IPI*#F.52-MY]O\`0>7"5^L2`0`<
`
end



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

end of thread, other threads:[~1998-02-10  3:34 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1998-02-10  3:34 Patch for COMPLEX support (part 2) Weiwen Liu
  -- strict thread matches above, loose matches on Subject: below --
1998-01-08  6:05 Weiwen Liu

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).