Return-Path: owner-egcs@cygnus.com Sun
Received: from cygnus.com (runyon.cygnus.com [205.180.230.5]) by hurl.cygnus.com with ESMTP (8.7.1/8.7.1) id RAA11988 for <law@hurl.cygnus.com>; Sun, 5 Oct 1997 17:27:27 -0600 (MDT)
Received: (from majordom@localhost)
	by runyon.cygnus.com (8.8.7-cygnus/8.8.7) id QAA27817;
	Sun, 5 Oct 1997 16:16:45 -0700 (PDT)
Received: from YALPH1.physics.yale.edu (hepvms1.physics.yale.edu [198.125.138.1])
	by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id QAA27802;
	Sun, 5 Oct 1997 16:16:38 -0700 (PDT)
Received: from hepunix2.physics.yale.edu by hepmail.physics.yale.edu
 (PMDF V5.1-8 #17719)
 with ESMTP id <01IOGJ0WO510CFQE02@hepmail.physics.yale.edu>; Sun,
 5 Oct 1997 19:20:08 EDT
Received: from hepunix1.physics.yale.edu by hepunix.physics.yale.edu
 (PMDF V5.1-5 #17721) with SMTP id <0EHLPVM0N00788@hepunix.physics.yale.edu>;
 Sun, 05 Oct 1997 19:14:13 -0400 (EDT)
Date: Sun, 05 Oct 1997 19:14:09 -0400 (EDT)
From: Weiwen Liu <liu@hepvms.physics.yale.edu>
Subject: Re: complex support on alpha
In-reply-to: <199710020532.WAA16123@dot.cygnus.com>
X-Sender: liu@hepunix1.physics.yale.edu
To: rth@cygnus.com
Cc: egcs@cygnus.com
Message-id: <Pine.OSF.3.96.971005190110.31383A-100000@hepunix1.physics.yale.edu>
MIME-version: 1.0
Content-type: TEXT/PLAIN; charset=US-ASCII
Sender: owner-egcs@cygnus.com
Precedence: bulk

On Wed, 1 Oct 1997, Richard Henderson wrote:

> Well, it is enough to compile those examples properly, but it is
> not completely correct.  The problem is that complex numbers should
> be treated as two distinct arguments on Alpha, which affects padding
> of the arguments passed on the stack.
> 

Here is a patch for it.  It should be applied against egcs-970929.
Beside fixing complex-5.c in the testsuite, egcs with this patch generates
the same result from 'make check-gcc' as without it.

On an alpha-dec-osf4.0, this patch correctly compiles the following test
program with F=char, short, int, long, float, double:
#ifndef F
#define F float
#endif

typedef __complex__ F FC;

FC f1(int odd, FC a, FC b, FC c)
{
  return a + b + c;
}

FC f2a(F a, F b, F c, F d, F e, F f, F g, F h)
{
  return (a + c + e + g) + 1i * (b + d + f + h);
}

FC f2b(FC a, FC b, FC c, FC d)
{
  return a + b + c + d;
}

int main()
{
    FC a, b, c, d, e;
    a = 1 + 2i;
    b = 3+4i;
    c = 5+6i;
    d = 7+8i;

    e = f1(1,a,b,c);
    if (e != 9+12i)
        abort ();
    e=f2b(a,b,c,d);
    if (e != 16+20i)
        abort ();
    e=f2a(1,2,3,4,5,6,7,8);
    if (e != 16+20i)
        abort ();
    return 0;
}

This patch has only been tested on alpha-dec-osf4.0, because I have no
access to other machines.  To support compless on other machines, the
machine-dependent tm.h has to be modified similarly to what is done for
alpha.h here.

Weiwen

Sun Oct  5 19:00:00  Weiwen Liu  <liu@hepunix.phycis.yale.edu>

	 * c-tree.h: Define complex_long_integer_type_node
	 to support __complex__ long.
	 * c-decl.c (init_decl_processing): Initialize 
	 complex_long_integer_type_node.
	 * c-lex.c (yylex): Enable __complex__ long.

	 * expr.h:  Define COMPLEX_WORD_MODE and GET_COMPLEX_MODE_SIZE.
	 * emit-rtl.c (gen_lowpart_common, gen_highpart,
	 operand_subword): Use them.
	 * expr.c (move_block_to_reg, emit_push_insn): Use them.

	 * emit-rtl.c (operand_subword): Deal with a complex mode.

	 * regs.h: Correctly calculate REG_SIZE for a complex mode.

	 * config/alpha/alpha.h: Correctly deal with a complex mode in 
	 HARD_REGNO_NREGS, FUNCTION_VALUE, ALPHA_ARG_SIZE.

*** gcc/c-decl.c.orig	Sat Sep 27 14:16:06 1997
--- gcc/c-decl.c	Wed Oct  1 16:19:39 1997
*************** tree double_type_node;
*** 135,140 ****
--- 135,141 ----
  tree long_double_type_node;
  
  tree complex_integer_type_node;
+ tree complex_long_integer_type_node;
  tree complex_float_type_node;
  tree complex_double_type_node;
  tree complex_long_double_type_node;
*************** init_decl_processing ()
*** 2989,2994 ****
--- 2990,3001 ----
  			complex_integer_type_node));
    TREE_TYPE (complex_integer_type_node) = integer_type_node;
    layout_type (complex_integer_type_node);
+ 
+   complex_long_integer_type_node = make_node (COMPLEX_TYPE);
+   pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long int"),
+ 			complex_long_integer_type_node));
+   TREE_TYPE (complex_long_integer_type_node) = long_integer_type_node;
+   layout_type (complex_long_integer_type_node);
  
    complex_float_type_node = make_node (COMPLEX_TYPE);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
*** gcc/c-lex.c.orig	Fri Aug 15 01:32:53 1997
--- gcc/c-lex.c	Wed Oct  1 16:19:39 1997
*************** yylex ()
*** 1769,1774 ****
--- 1769,1780 ----
  		    = build_complex (NULL_TREE, integer_zero_node,
  				     convert (integer_type_node,
  					      yylval.ttype));
+ 		else if (TYPE_PRECISION (type)
+ 		    <= TYPE_PRECISION (long_integer_type_node))
+ 		  yylval.ttype
+ 		    = build_complex (NULL_TREE, integer_zero_node,
+ 				     convert (long_integer_type_node,
+ 					      yylval.ttype));
  		else
  		  error ("complex integer constant is too wide for `complex int'");
  	      }
*** gcc/c-tree.h.orig	Mon Aug 11 11:57:03 1997
--- gcc/c-tree.h	Wed Oct  1 16:19:40 1997
*************** extern tree long_long_integer_type_node;
*** 219,224 ****
--- 219,225 ----
  extern tree long_long_unsigned_type_node;
  extern tree long_unsigned_type_node;
  extern tree complex_integer_type_node;
+ extern tree complex_long_integer_type_node;
  extern tree complex_float_type_node;
  extern tree complex_double_type_node;
  extern tree complex_long_double_type_node;
*** gcc/emit-rtl.c.orig	Mon Sep 22 13:41:24 1997
--- gcc/emit-rtl.c	Sun Oct  5 17:48:05 1997
*************** gen_lowpart_common (mode, x)
*** 635,644 ****
  	     / 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 ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
        && (GET_MODE_CLASS (mode) == MODE_INT
--- 635,644 ----
  	     / UNITS_PER_WORD)))
      return 0;
  
!   if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) >0)
!     word = GET_COMPLEX_MODE_SIZE (GET_MODE (x))
!         - ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1))
!            / UNITS_PER_WORD);
  
    if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
        && (GET_MODE_CLASS (mode) == MODE_INT
*************** gen_highpart (mode, x)
*** 1013,1022 ****
        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);
  
        /*
         * ??? This fails miserably for complex values being passed in registers
--- 1013,1022 ----
        int word = 0;
  
        if (! WORDS_BIG_ENDIAN
! 	  && GET_MODE_SIZE (GET_MODE (x)) > 0)
!         word = GET_COMPLEX_MODE_SIZE (GET_MODE (x))
!             - ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1))
!                / UNITS_PER_WORD);
  
        /*
         * ??? This fails miserably for complex values being passed in registers
*************** operand_subword (op, i, validate_address
*** 1100,1105 ****
--- 1100,1107 ----
  
    /* If OP is narrower than a word or if we want a word outside OP, fail.  */
    if (mode != BLKmode
+       && (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+           && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
        && (GET_MODE_SIZE (mode) < UNITS_PER_WORD
  	  || (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode)))
      return 0;
*************** operand_subword (op, i, validate_address
*** 1127,1133 ****
  	       || op == arg_pointer_rtx
  #endif
  	       || op == stack_pointer_rtx)
! 	return gen_rtx (SUBREG, word_mode, op, i);
        else
  	return gen_rtx (REG, word_mode, REGNO (op) + i);
      }
--- 1129,1135 ----
  	       || op == arg_pointer_rtx
  #endif
  	       || op == stack_pointer_rtx)
! 	return gen_rtx (SUBREG, COMPLEX_WORD_MODE (mode), op, i);
        else
  	return gen_rtx (REG, word_mode, REGNO (op) + i);
      }
*************** operand_subword (op, i, validate_address
*** 1135,1141 ****
      return gen_rtx (SUBREG, word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
    else if (GET_CODE (op) == CONCAT)
      {
!       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,
--- 1137,1144 ----
      return gen_rtx (SUBREG, word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
    else if (GET_CODE (op) == CONCAT)
      {
!       int partwords = (GET_MODE_UNIT_SIZE (GET_MODE (op))
!                        + (UNITS_PER_WORD - 1))/ UNITS_PER_WORD;
        if (i < partwords)
  	return operand_subword (XEXP (op, 0), i, validate_address, mode);
        return operand_subword (XEXP (op, 1), i - partwords,
*************** operand_subword (op, i, validate_address
*** 1145,1151 ****
    /* Form a new MEM at the requested address.  */
    if (GET_CODE (op) == MEM)
      {
!       rtx addr = plus_constant (XEXP (op, 0), i * UNITS_PER_WORD);
        rtx new;
  
        if (validate_address)
--- 1148,1158 ----
    /* Form a new MEM at the requested address.  */
    if (GET_CODE (op) == MEM)
      {
!       rtx addr = plus_constant (
!           XEXP (op, 0),
!           (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
!            || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)?
!           i*GET_MODE_UNIT_SIZE (mode): i * UNITS_PER_WORD);
        rtx new;
  
        if (validate_address)
*************** operand_subword (op, i, validate_address
*** 1159,1165 ****
  	    addr = memory_address (word_mode, addr);
  	}
  
!       new = gen_rtx (MEM, word_mode, addr);
  
        MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op);
        MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op);
--- 1166,1172 ----
  	    addr = memory_address (word_mode, addr);
  	}
  
!       new = gen_rtx (MEM, COMPLEX_WORD_MODE (mode), addr);
  
        MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op);
        MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op);
*** gcc/expr.c.orig	Sat Oct  4 03:12:35 1997
--- gcc/expr.c	Sun Oct  5 18:21:18 1997
*************** move_block_to_reg (regno, x, nregs, mode
*** 1701,1707 ****
  #endif
  
    for (i = 0; i < nregs; i++)
!     emit_move_insn (gen_rtx (REG, word_mode, regno + i),
  		    operand_subword_force (x, i, mode));
  }
  
--- 1701,1707 ----
  #endif
  
    for (i = 0; i < nregs; i++)
!     emit_move_insn (gen_rtx (REG, COMPLEX_WORD_MODE (mode), regno + i),
  		    operand_subword_force (x, i, mode));
  }
  
*************** move_block_from_reg (regno, x, nregs, si
*** 1724,1729 ****
--- 1724,1731 ----
    /* If SIZE is that of a mode no bigger than a word, just use that
       mode's store operation.  */
    if (size <= UNITS_PER_WORD
+       && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_INT
+       && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_FLOAT
        && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
      {
        emit_move_insn (change_address (x, mode, NULL),
*************** move_block_from_reg (regno, x, nregs, si
*** 1769,1780 ****
  
    for (i = 0; i < nregs; i++)
      {
!       rtx tem = operand_subword (x, i, 1, BLKmode);
  
        if (tem == 0)
  	abort ();
  
!       emit_move_insn (tem, gen_rtx (REG, word_mode, regno + i));
      }
  }
  
--- 1771,1786 ----
  
    for (i = 0; i < nregs; i++)
      {
!       rtx tem = operand_subword
!           (x, i, 1, (GET_MODE_CLASS(GET_MODE (x)) == MODE_COMPLEX_INT
!                      || GET_MODE_CLASS(GET_MODE (x)) == MODE_COMPLEX_FLOAT)?
!            GET_MODE(x):BLKmode);
  
        if (tem == 0)
  	abort ();
  
!       emit_move_insn (tem, gen_rtx (REG, COMPLEX_WORD_MODE (GET_MODE (x)),
!                                     regno + i));
      }
  }
  
*************** emit_push_insn (x, mode, type, size, ali
*** 2687,2693 ****
      {
        /* Scalar partly in registers.  */
  
!       int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
        int i;
        int not_stack;
        /* # words of start of argument
--- 2693,2699 ----
      {
        /* Scalar partly in registers.  */
  
!       int size = GET_COMPLEX_MODE_SIZE (mode);
        int i;
        int not_stack;
        /* # words of start of argument
*************** emit_push_insn (x, mode, type, size, ali
*** 2696,2701 ****
--- 2702,2716 ----
        int args_offset = INTVAL (args_so_far);
        int skip;
  
+       /* For a complex argument passing partially in a register,
+          save the image part in stack immedially following the space
+          used for save the part passig in register (see function
+          assign_parms in function.c).  */
+       if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
+           || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+           if (GET_MODE_UNIT_SIZE (mode) < UNITS_PER_WORD)
+               args_offset += GET_MODE_UNIT_SIZE (mode) - UNITS_PER_WORD;
+       
        /* Push padding now if padding above and stack grows down,
  	 or if padding below and stack grows up.
  	 But if space already allocated, this has already been done.  */
*************** emit_push_insn (x, mode, type, size, ali
*** 2742,2748 ****
  #endif
  	if (i >= not_stack + offset)
  	  emit_push_insn (operand_subword_force (x, i, mode),
! 			  word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
  			  0, args_addr,
  			  GEN_INT (args_offset + ((i - not_stack + skip)
  						  * UNITS_PER_WORD)));
--- 2757,2764 ----
  #endif
  	if (i >= not_stack + offset)
  	  emit_push_insn (operand_subword_force (x, i, mode),
!                           COMPLEX_WORD_MODE (mode),
!                           NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
  			  0, args_addr,
  			  GEN_INT (args_offset + ((i - not_stack + skip)
  						  * UNITS_PER_WORD)));
*** gcc/expr.h.orig	Sat Oct  4 23:46:34 1997
--- gcc/expr.h	Sun Oct  5 18:21:14 1997
*************** extern void bc_adjust_stack			PROTO ((in
*** 952,954 ****
--- 952,970 ----
  extern void bc_load_localaddr			PROTO ((rtx));
  extern void do_jump_by_parts_greater_rtx	PROTO ((enum machine_mode, int,
  							rtx, rtx, rtx, rtx));
+ 
+ /* Determine the mode for the imagine and real part of a complex MODE.
+    For a non-complex MODE, use WORD_MODE.*/
+ #define COMPLEX_WORD_MODE(MODE) \
+ (((GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT \
+   || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
+  && GET_MODE_UNIT_SIZE (MODE) < UNITS_PER_WORD)? \
+ mode_for_size (GET_MODE_UNIT_SIZE(MODE)*BITS_PER_UNIT, \
+                (GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT)? \
+                MODE_INT:MODE_FLOAT, \
+                0):word_mode)
+ 
+ /* Calculate number of bytes needed for a complex MODE */
+ #define GET_COMPLEX_MODE_SIZE(MODE) \
+ (((GET_MODE_UNIT_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) \
+  * (GET_MODE_SIZE (MODE)) / GET_MODE_UNIT_SIZE (MODE))
*** gcc/regs.h.orig	Mon Aug 11 11:57:12 1997
--- gcc/regs.h	Wed Oct  1 16:19:31 1997
*************** Boston, MA 02111-1307, USA.  */
*** 27,33 ****
     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)
  
  /* Maximum register number used in this function, plus one.  */
  
--- 27,36 ----
     valid way to get this value.  You cannot get it from the regno.  */
  
  #define REG_SIZE(R) \
!   (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)))))
  
  /* Maximum register number used in this function, plus one.  */
  
*** gcc/config/alpha/alpha.h.orig	Wed Oct  1 16:16:31 1997
--- gcc/config/alpha/alpha.h	Fri Oct  3 11:41:58 1997
*************** extern void override_options ();
*** 515,521 ****
     but can be less for certain modes in special long registers.  */
  
  #define HARD_REGNO_NREGS(REGNO, MODE)   \
!   ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
  
  /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
     On Alpha, the integer registers can hold any mode.  The floating-point
--- 515,524 ----
     but can be less for certain modes in special long registers.  */
  
  #define HARD_REGNO_NREGS(REGNO, MODE)   \
!   (GET_MODE_SIZE (MODE) == 0?					\
!    0:(((GET_MODE_UNIT_SIZE (MODE) + (UNITS_PER_WORD - 1))	\
!       / UNITS_PER_WORD) * (GET_MODE_SIZE (MODE)			\
!       / GET_MODE_UNIT_SIZE (MODE))))
  
  /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
     On Alpha, the integer registers can hold any mode.  The floating-point
*************** enum reg_class { NO_REGS, GENERAL_REGS, 
*** 891,901 ****
  #define FUNCTION_VALUE(VALTYPE, FUNC)	\
    gen_rtx (REG,							\
  	   (INTEGRAL_MODE_P (TYPE_MODE (VALTYPE))		\
  	    && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) 	\
  	   ? word_mode : TYPE_MODE (VALTYPE),			\
  	   ((TARGET_FPREGS					\
  	     && (TREE_CODE (VALTYPE) == REAL_TYPE		\
! 		 || TREE_CODE (VALTYPE) == COMPLEX_TYPE))	\
  	    ? 32 : 0))
  
  /* Define how to find the value returned by a library function
--- 894,908 ----
  #define FUNCTION_VALUE(VALTYPE, FUNC)	\
    gen_rtx (REG,							\
  	   (INTEGRAL_MODE_P (TYPE_MODE (VALTYPE))		\
+             && (GET_MODE_CLASS(TYPE_MODE (VALTYPE))		\
+                 != MODE_COMPLEX_INT)				\
  	    && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) 	\
  	   ? word_mode : TYPE_MODE (VALTYPE),			\
  	   ((TARGET_FPREGS					\
  	     && (TREE_CODE (VALTYPE) == REAL_TYPE		\
! 		 || TREE_CODE (VALTYPE) == COMPLEX_TYPE)	\
!              && (GET_MODE_CLASS(TYPE_MODE (VALTYPE))		\
!                  != MODE_COMPLEX_INT))				\
  	    ? 32 : 0))
  
  /* Define how to find the value returned by a library function
*************** enum reg_class { NO_REGS, GENERAL_REGS, 
*** 953,959 ****
  
  #define ALPHA_ARG_SIZE(MODE, TYPE, NAMED)				\
  ((MODE) != BLKmode							\
!  ? (GET_MODE_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD 	\
   : (int_size_in_bytes (TYPE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
  
  /* Update the data in CUM to advance over an argument
--- 960,969 ----
  
  #define ALPHA_ARG_SIZE(MODE, TYPE, NAMED)				\
  ((MODE) != BLKmode							\
!  ? (GET_MODE_SIZE (MODE) > 0?						\
!     (GET_MODE_UNIT_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD	\
!     * GET_MODE_SIZE (MODE) / GET_MODE_UNIT_SIZE (MODE)			\
!     : 0)								\
   : (int_size_in_bytes (TYPE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
  
  /* Update the data in CUM to advance over an argument


