public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* complex support on alpha
@ 1997-10-01 21:03 Weiwen Liu
  1997-10-01 22:34 ` Richard Henderson
  1997-10-02 20:35 ` Jim Wilson
  0 siblings, 2 replies; 9+ messages in thread
From: Weiwen Liu @ 1997-10-01 21:03 UTC (permalink / raw)
  To: egcs

Hi,

egcs on alpha-dec-osf4.0 fails to generate correct code for
gcc.c-torture/execute/complex-5.c 
in the testsuite, because gcc does not calculate correctly the number of
registers needed for 'float __complex__'.  Instead of 2 registers, gcc
says only one register is needed. 

egcs generates rtl's for complex-5.c:
(insn 4 2 6 (set (mem:SF (reg:DI 65))
        (reg:SF 48 $f16)) -1 (nil)
    (nil))

(insn 6 4 8 (set (mem:SF (plus:DI (reg:DI 65)
                (const_int 4)))
        (reg:SF 48 $f16)) -1 (nil)
    (nil))
===> register $f16 is used to pass both real and imagine part, and the
===> real part is lost in function f in complex-5.c 
(insn 8 6 10 (set (mem:SF (plus:DI (reg:DI 65)
                (const_int 8)))
        (reg:SF 49 $f17)) -1 (nil)
    (nil))

(insn 10 8 11 (set (mem:SF (plus:DI (reg:DI 65)
                (const_int 12)))
        (reg:SF 49 $f17)) -1 (nil)
    (nil))


The following patch  will calculate number of registers for
complex arguments correctly and compile complex-5.c correctly.

With this patch, egcs generates correct code for the following
program:

/*
long int __complex__ t5 (long int __complex__ a, long int __complex__ b)
{
    return a + b;
}
*/

float __complex__ t1 (float __complex__ a, float __complex__ b)
{
    return a + b;
}

double __complex__ t2 (double __complex__ a, double __complex__ b)
{
    return a + b;
}

short __complex__ t3 (short __complex__ a, short __complex__ b)
{
    return a + b;
}

int __complex__ t4 (int __complex__ a, int __complex__ b)
{
    return a + b;
}

float __complex__ a1 = 1. + 2.i;
float __complex__ b1 = 3. + 4.i;
float __complex__ c1 = 4. + 6.i;

double __complex__ a2 = 1.L + 2.Li;
double __complex__ b2 = 3.L + 4.Li;
double __complex__ c2 = 4.L + 6.Li;

short __complex__ a3 = 1 + 2i;
short __complex__ b3 = 3 + 4i;
short __complex__ c3 = 4 + 6i;

int __complex__ a4 = 1 + 2i;
int __complex__ b4 = 3 + 4i;
int __complex__ c4 = 4 + 6i;

/*
long int __complex__ a5 = 1L + 2Li;
long int __complex__ b5 = 3L + 4Li;
long int __complex__ c5 = 4L + 6Li;
*/

int main()
{
    if (t1(a1, b1) != c1)
        abort ();
    if (t2(a2, b2) != c2)
        abort ();
    if (t3(a3, b3) != c3)
        abort ();
    if (t4(a4, b4) != c4)
        abort ();
/*
    if (t5(a5, b5) != c5)
        abort ();
*/
    return 0;
}

Note that "long int __complex__" parts are commented out because gcc
does not accept it even though gcc.info says it supports.  I have a
patch to enable "long int __complex__" support.  If you need this
patch, let me know.

Weiwen

Wed Oct  2  23:30:00  Weiwen Liu <liu@hepunix.physics.yale.edu>

	 * regs.h: Correctly calculates number of registers needed.
	 * emit-rtl.c (gen_lowpart_common, gen_highpart): Ditto.
	 * config/alpha/alpha.h: Ditto.

	 * config/alpha/alpha.h: Use $f0 and $f1 for complex float.

*** gcc/regs.h.orig	Tue Sep 30 01:07:59 1997
--- gcc/regs.h	Wed Oct  1 00:20:26 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/emit-rtl.c.orig	Mon Sep 22 13:41:24 1997
--- gcc/emit-rtl.c	Tue Sep 30 23:09:20 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,647 ----
  	     / UNITS_PER_WORD)))
      return 0;
  
!   if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) >0)
!     word = ((GET_MODE_UNIT_SIZE (GET_MODE (x)) + (UNITS_PER_WORD - 1))
!             / UNITS_PER_WORD)
!         * (GET_MODE_SIZE (GET_MODE (x))
!            / GET_MODE_UNIT_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
--- 1016,1028 ----
        int word = 0;
  
        if (! WORDS_BIG_ENDIAN
! 	  && GET_MODE_SIZE (GET_MODE (x)) > 0)
!         word = ((GET_MODE_UNIT_SIZE (GET_MODE (x)) + (UNITS_PER_WORD - 1))
!                 / UNITS_PER_WORD)
!             * (GET_MODE_SIZE (GET_MODE (x))
!                / GET_MODE_UNIT_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
*** gcc/config/alpha/alpha.h.orig	Thu Sep 25 10:21:11 1997
--- gcc/config/alpha/alpha.h	Wed Oct  1 12:33:43 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,525 ----
     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))))
! /*  ((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
*************** 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
--- 895,909 ----
  #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
--- 961,970 ----
  
  #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


The result from "make check-gcc" with this patch is

		=== gcc Summary ===

# of expected passes		4879
# of unexpected failures	8
# of expected failures		4
# of unsupported tests		7

FAIL: gcc.c-torture/compile/961203-1.c,  -O0  
FAIL: gcc.c-torture/compile/961203-1.c,  -O1  
FAIL: gcc.c-torture/compile/961203-1.c,  -O2  
FAIL: gcc.c-torture/compile/961203-1.c,  -O2 -fomit-frame-pointer -finline-functions  
FAIL: gcc.c-torture/execute/ieee/fp-cmp-1.c execution,  -O0 
FAIL: gcc.c-torture/execute/ieee/fp-cmp-1.c execution,  -O1 
FAIL: gcc.c-torture/execute/ieee/fp-cmp-1.c execution,  -O2 
FAIL: gcc.c-torture/execute/ieee/fp-cmp-1.c execution,  -O2 -fomit-frame-pointer -finline-functions 



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

* Re: complex support on alpha
  1997-10-01 21:03 complex support on alpha Weiwen Liu
@ 1997-10-01 22:34 ` Richard Henderson
  1997-10-02  9:22   ` Weiwen Liu
  1997-10-05 16:16   ` Weiwen Liu
  1997-10-02 20:35 ` Jim Wilson
  1 sibling, 2 replies; 9+ messages in thread
From: Richard Henderson @ 1997-10-01 22:34 UTC (permalink / raw)
  To: Weiwen Liu; +Cc: egcs

> The following patch  will calculate number of registers for
> complex arguments correctly and compile complex-5.c correctly.

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.

Have a look at the appended samples.  Note the lossage in the 
handling of C in f1.  And the code generated for f2a and f2b
should be identical wrt g+h/d.

It was a this point I got stuck myself.



r~



typedef __complex__ float FC;

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

FC f2a(float a, float b, float c, float d, float e, float f, float g, float h)
{
  return (a + c + e + g) + 1.0fi * (b + d + f + h);
}

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

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

* Re: complex support on alpha
  1997-10-01 22:34 ` Richard Henderson
@ 1997-10-02  9:22   ` Weiwen Liu
  1997-10-02 10:46     ` Richard Henderson
  1997-10-05 16:16   ` Weiwen Liu
  1 sibling, 1 reply; 9+ messages in thread
From: Weiwen Liu @ 1997-10-02  9:22 UTC (permalink / raw)
  To: rth; +Cc: egcs

On Wed, 1 Oct 1997, Richard Henderson wrote:

> > The following patch  will calculate number of registers for
> > complex arguments correctly and compile complex-5.c correctly.
> 
> 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.
> 
> Have a look at the appended samples.  Note the lossage in the 
> handling of C in f1.  And the code generated for f2a and f2b
> should be identical wrt g+h/d.
> 
> It was a this point I got stuck myself.
> 
> 
> 
> r~
> 
> 
> 
> typedef __complex__ float FC;
> 
> FC f1(int odd, FC a, FC b, FC c)
> {
>   return a + b + c;
> }
> 
> FC f2a(float a, float b, float c, float d, float e, float f, float g, float h)
> {
>   return (a + c + e + g) + 1.0fi * (b + d + f + h);
> }
> 
> FC f2b(FC a, FC b, FC c, FC d)
> {
>   return a + b + c + d;
> }
> 

I am working on this.

I have a question concerning f1:
How do we pass C of f1?  Both real and imagine part on stack, or real on
register and imagine on stack?

Weiwen


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

* Re: complex support on alpha
  1997-10-02  9:22   ` Weiwen Liu
@ 1997-10-02 10:46     ` Richard Henderson
  0 siblings, 0 replies; 9+ messages in thread
From: Richard Henderson @ 1997-10-02 10:46 UTC (permalink / raw)
  To: Weiwen Liu; +Cc: egcs

On Thu, Oct 02, 1997 at 12:21:37PM -0400, Weiwen Liu wrote:
>
> > FC f1(int odd, FC a, FC b, FC c)
> > {
> >   return a + b + c;
> > }
> 
> I have a question concerning f1:
> How do we pass C of f1?  Both real and imagine part on stack, or real on
> register and imagine on stack?

As if the two parts were separate operands -- real in $f21, imaginary
on stack in a 64-bit aligned field.


r~

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

* Re: complex support on alpha
  1997-10-01 21:03 complex support on alpha Weiwen Liu
  1997-10-01 22:34 ` Richard Henderson
@ 1997-10-02 20:35 ` Jim Wilson
  1997-10-04 14:33   ` Kamil Iskra
  1 sibling, 1 reply; 9+ messages in thread
From: Jim Wilson @ 1997-10-02 20:35 UTC (permalink / raw)
  To: Weiwen Liu; +Cc: egcs

	egcs on alpha-dec-osf4.0 fails to generate correct code for
	gcc.c-torture/execute/complex-5.c 
	in the testsuite, because gcc does not calculate correctly the number of
	registers needed for 'float __complex__'.  Instead of 2 registers, gcc
	says only one register is needed. 

It has been broken ever since the initial implementation.  There is a general
problem that __complex__ X fails if X is half the word size or smaller.
For instance, __complex__ short will fail on any 32 bit machine in the same
way that __complex__ float fails on the alpha.  It would be nice to see this
fixed.

Hopefully it can be fixed in a way that doesn't require changes to
every target.  If the alpha.h file requires fixes to make __complex__ float
work, then that implies that every tm.h file needs fixes to fix the general
__complex__ problem.

Jim

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

* Re: complex support on alpha
  1997-10-02 20:35 ` Jim Wilson
@ 1997-10-04 14:33   ` Kamil Iskra
  1997-10-04 18:29     ` Richard Henderson
  0 siblings, 1 reply; 9+ messages in thread
From: Kamil Iskra @ 1997-10-04 14:33 UTC (permalink / raw)
  To: Jim Wilson; +Cc: egcs

On Thu, 2 Oct 1997, Jim Wilson wrote:

> It has been broken ever since the initial implementation.  There is a general
> problem that __complex__ X fails if X is half the word size or smaller.
> For instance, __complex__ short will fail on any 32 bit machine in the same
> way that __complex__ float fails on the alpha.  It would be nice to see this
> fixed.

Could you please explain how things are *supposed* to work?

Richard Henderson says that on Alpha the real and imaginary parts should
be passed as two completely separate arguments. Is this how it should work
on any other target?

For example, see what I get on m68k-amigaos, for __complex__ char:

#include <stdio.h>

void f(__complex__ char cc)
{
	printf("cc: (%d, %d)\n", __real__ cc, __imag__ cc);
}

int main(void)
{
	__complex__ char cc;
	__real__ cc=1;
	__imag__ cc=2;
	f(cc);
}

#NO_APP
gcc2_compiled.:
___gnu_compiled_c:
.text
LC0:
	.ascii "cc: (%d, %d)\12\0"
	.even
.globl _f
_f:
	link a5,#0
	moveb a5@(11),d0 ;# 26 movqi+1/1
	extw d0 ;# 7 extendqihi2
	movew d0,a0 ;# 8 extendhisi2/2
	movel a0,sp@- ;# 10 movsi+1/1
	moveb a5@(10),d0 ;# 28 movqi+1/1
	extw d0 ;# 11 extendqihi2
	movew d0,a0 ;# 12 extendhisi2/2
	movel a0,sp@- ;# 14 movsi+1/1
	pea LC0 ;# 16 movsi+1/1
	jbsr _printf ;# 18 call_value+1
	lea sp@(12),sp ;# 19 *addsi3_internal/2
L5:
	unlk a5
	rts
	.even
.globl _main
_main:
	link a5,#-4
	jbsr ___main ;# 6 call+1
	moveb #1,a5@(-2) ;# 10 movqi+1/3
	moveb #2,a5@(-1) ;# 12 movqi+1/3
	subql #2,sp ;# 14 movqi+1/3
	moveb a5@(-1),sp@(1)
	subql #2,sp ;# 15 movqi+1/3
	moveb a5@(-2),sp@(1)
	subql #2,sp ;# 16 *addsi3_internal/2
	jbsr _f ;# 18 call+1
	addql #4,sp ;# 19 *addsi3_internal/2
	moveq #0,d0 ;# 23 movsi_const0
	jra L6 ;# 25 jump
	.even
L6:
	unlk a5
	rts

In f(), the stack is referenced as if there was a single, two-byte
__complex__ char variable on it. However, that's not the way main() 
arranges things: it puts a padding inbetween (insns 14 and 15), since the
m68k stack has to be 16-bit aligned. "Who" is right - main() or f()?

Actually, there's yet another problem, with a completely bogus insn 16.
The compiler pushes 6 bytes, but pops only 4 (insn 19). That's because
PARM_BOUNDARY is 32, and in calls.c:store_one_arg the compiler decides
that it will need to adjust stack for 2 bytes, but it doesn't yet know
that this won't be needed since it's not going to push one 2-byte object,
but two 1-byte ones, with PUSH_ROUNDING alignment for each of them.

Not surprisingly, the above code works fine if char is changed to short.

And one more thing. If I change the "cc" definition in main() to:

	register __complex__ char cc __asm__("d2");

I get the following main():

_main:
	link a5,#0
	movel d2,sp@-
	jbsr ___main ;# 6 call+1
	moveq #1,d2 ;# 10 movqi+1/1
	moveq #2,d2 ;# 12 movqi+1/1
	subql #2,sp ;# 14 movqi+1/3
	moveb d2,sp@(1)
	subql #2,sp ;# 15 movqi+1/3
	moveb d2,sp@(1)
	subql #2,sp ;# 16 *addsi3_internal/2
	jbsr _f ;# 18 call+1
	addql #4,sp ;# 19 *addsi3_internal/2
	moveq #0,d0 ;# 24 movsi_const0
	jra L6 ;# 26 jump
	.even
L6:
	movel a5@(-4),d2
	unlk a5
	rts

The compiler is clearly unaware that it needs to apply more logic for
stores/loads or real and imaginary parts when they are in the same
register. How is such a case supposed to work? Should two separate
registers be allocated (d2 and d3 in this case), or should more
sophisticated store/load code be generated?

/ Kamil Iskra - AMIGA 1200, 68030 50MHz, HDD 1.6 GB, 18 MB RAM \
| iskra@student.uci.agh.edu.pl  kiskra@ernie.icslab.agh.edu.pl |
| http://student.uci.agh.edu.pl/~iskra                         |
\ PGP public key available via Finger or WWW                   /


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

* Re: complex support on alpha
  1997-10-04 14:33   ` Kamil Iskra
@ 1997-10-04 18:29     ` Richard Henderson
  0 siblings, 0 replies; 9+ messages in thread
From: Richard Henderson @ 1997-10-04 18:29 UTC (permalink / raw)
  To: Kamil Iskra; +Cc: Jim Wilson, egcs

On Sat, Oct 04, 1997 at 10:58:44PM +0200, Kamil Iskra wrote:
> Richard Henderson says that on Alpha the real and imaginary parts should
> be passed as two completely separate arguments. Is this how it should work
> on any other target?

Most ABI's don't mention compex values at all.  Probably the right
thing to do on systems that don't is to treat the tuple as a struct.

To some extent, that is what gcc looks like it is trying to do.  I
don't know that it gets it right all the time, though.


r~

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

* Re: complex support on alpha
  1997-10-01 22:34 ` Richard Henderson
  1997-10-02  9:22   ` Weiwen Liu
@ 1997-10-05 16:16   ` Weiwen Liu
  1997-10-05 18:28     ` Richard Henderson
  1 sibling, 1 reply; 9+ messages in thread
From: Weiwen Liu @ 1997-10-05 16:16 UTC (permalink / raw)
  To: rth; +Cc: egcs

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



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

* Re: complex support on alpha
  1997-10-05 16:16   ` Weiwen Liu
@ 1997-10-05 18:28     ` Richard Henderson
  0 siblings, 0 replies; 9+ messages in thread
From: Richard Henderson @ 1997-10-05 18:28 UTC (permalink / raw)
  To: Weiwen Liu; +Cc: rth, egcs

On Sun, Oct 05, 1997 at 07:14:09PM -0400, Weiwen Liu wrote:
> 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.
[...]
> On an alpha-dec-osf4.0, this patch correctly compiles the following test
> program with F=char, short, int, long, float, double:

No good.

(1) It is still treating complex float as an 8-byte struct not two 
    _separate_ float arguments.  I sent you f2a and f2b so that you
    could verify that their arguments wound up in the same place, but

    f2b:
	lds $f10,16($30)
	lds $f11,20($30)

    f2a:
	lds $f10,16($30)
	lds $f11,24($30)

(2) f1, the one with odd numbered arguments, is _completely_ wrong:

    f1:
	lda $30,-16($30)
	.prologue 0
	sts $f21,8($30)
	lds $f10,12($30)

Did we write to 12($30), which is below the vfp?  No.  Your program
happened to run because of this bit from main:

	sts $f3,-4($30)

which is a big no-no.   No writes may be made below $sp.  You take a
signal after that instruction and your data will be corrupted. 


r~

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

end of thread, other threads:[~1997-10-05 18:28 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1997-10-01 21:03 complex support on alpha Weiwen Liu
1997-10-01 22:34 ` Richard Henderson
1997-10-02  9:22   ` Weiwen Liu
1997-10-02 10:46     ` Richard Henderson
1997-10-05 16:16   ` Weiwen Liu
1997-10-05 18:28     ` Richard Henderson
1997-10-02 20:35 ` Jim Wilson
1997-10-04 14:33   ` Kamil Iskra
1997-10-04 18:29     ` Richard Henderson

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