This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: mips64-linux n32/n64 long doubles


On Jan 27, 2003, Eric Christopher <echristo@redhat.com> wrote:

>> mainline to 3.3 added).  Ok to install if it bootstraps and regtests
>> on irix?
>> 

> Yup. Looks good. Thanks.

Here's what I'm checking in in the 3.3 branch and in mainline,
respectively.  Since the last round, I added prototypes for the
functions defined in gcc/config/mips/_tilib.c, to silence warnings,
and added an #include "defaults.h" for mainline, necessary for a
definition of BITS_PER_UNIT.

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* config/mips/mips.h (UNITS_PER_HWFPVALUE): Renamed from...
	(UNITS_PER_FPVALUE): Defined as the width of a long double, or
	zero if no hardware floating point.
	(LONG_DUBLE_TYPE_SIZE): Set to 128 on N32 and N64.
	(MAX_FIXED_MODE_SIZE): Define to LONG_DOUBLE_TYPE_SIZE.
	(LIBGCC2_LONG_DOUBLE_TYPE_SIZE): Define.
	(BIGGEST_ALIGNMENT): Same as LONG_DOUBLE_TYPE_SIZE.
	(FUNCTION_VALUE_REGNO_P): Set for FP_RETURN+2 on N32 and N64.
	* config/mips/iris6.h (MIPS_TFMODE_FORMAT): Define.
	* config/mips/mips.c (override_options): Use it.
	(mips_arg_info): Pass TFmode values in even FP registers on N32
	and N64.
	(mips_setup_incoming_varargs): Use UNITS_PER_HWFPVALUE.
	(mips_va_start): Adjust alignment of ARG_POINTER_REGNUM.
	(mips_va_arg): Use UNITS_PER_HWFPVALUE.  Impose additional
	even-register-like alignment to 128-bit arguments.
	(save_restore_insns): Use UNITS_PER_HWFPVALUE.
	(mips_function_value): Likewise.  Return TFmode in $f0 and $f2
	on N32 or N64.
	* config/mips/_tilib.c (__negti2, __ashlti3, __lshrti3): New.
	* config/mips/t-iris6 (LIB2FUNCS_EXTRA): Add _tilib.c.
	(TPBIT): Set to tp-bit.c.
	(tp-bit.c): Create out of fp-bit.c.

Index: gcc/config/mips/_tilib.c
===================================================================
RCS file: gcc/config/mips/_tilib.c
diff -N gcc/config/mips/_tilib.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/config/mips/_tilib.c 27 Jan 2003 23:27:20 -0000
@@ -0,0 +1,161 @@
+/* A few TImode functions needed for TFmode emulated arithmetic.
+   Copyright 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+
+#include "tconfig.h"
+#include "tsystem.h"
+
+#ifndef LIBGCC2_WORDS_BIG_ENDIAN
+#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
+#endif
+
+#if _MIPS_SIM == 2 /* N32 */ || _MIPS_SIM == 3 /* 64 */
+
+typedef int TItype __attribute__ ((mode (TI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef int SItype __attribute__ ((mode (SI)));
+
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+
+typedef union
+{
+  struct TIstruct {
+#if LIBGCC2_WORDS_BIG_ENDIAN
+    DItype high, low;
+#else
+    DItype low, high;
+#endif
+  } s;
+  TItype ll;
+} TIunion;
+
+TItype __negti2 (TItype);
+TItype __ashlti3 (TItype, int);
+#if 0
+TItype __ashrti3 (TItype, int);
+#endif
+TItype __lshrti3 (TItype, int);
+
+TItype
+__negti2 (TItype u)
+{
+  TIunion w;
+  TIunion uu;
+
+  uu.ll = u;
+
+  w.s.low = -uu.s.low;
+  w.s.high = -uu.s.high - ((UDItype) w.s.low > 0);
+
+  return w.ll;
+}
+
+TItype
+__ashlti3 (TItype u, int b)
+{
+  TIunion w;
+  int bm;
+  TIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (DItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      w.s.low = 0;
+      w.s.high = (UDItype) uu.s.low << -bm;
+    }
+  else
+    {
+      UDItype carries = (UDItype) uu.s.low >> bm;
+
+      w.s.low = (UDItype) uu.s.low << b;
+      w.s.high = ((UDItype) uu.s.high << b) | carries;
+    }
+
+  return w.ll;
+}
+
+#if 0
+TItype
+__ashrti3 (TItype u, int b)
+{
+  TIunion w;
+  int bm;
+  TIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (DItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      /* w.s.high = 1..1 or 0..0 */
+      w.s.high = uu.s.high >> (sizeof (DItype) * BITS_PER_UNIT - 1);
+      w.s.low = uu.s.high >> -bm;
+    }
+  else
+    {
+      UDItype carries = (UDItype) uu.s.high << bm;
+
+      w.s.high = uu.s.high >> b;
+      w.s.low = ((UDItype) uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
+#endif
+
+TItype
+__lshrti3 (TItype u, int b)
+{
+  TIunion w;
+  int bm;
+  TIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (DItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      w.s.high = 0;
+      w.s.low = (UDItype) uu.s.high >> -bm;
+    }
+  else
+    {
+      UDItype carries = (UDItype) uu.s.high << bm;
+
+      w.s.high = (UDItype) uu.s.high >> b;
+      w.s.low = ((UDItype) uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
+
+#endif /* N32 or N64 */
Index: gcc/config/mips/iris6.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/iris6.h,v
retrieving revision 1.54
diff -u -p -r1.54 iris6.h
--- gcc/config/mips/iris6.h 29 Aug 2002 21:40:15 -0000 1.54
+++ gcc/config/mips/iris6.h 27 Jan 2003 23:27:20 -0000
@@ -1,5 +1,5 @@
 /* Definitions of target machine for GNU compiler.  Iris version 6.
-   Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002
+   Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
 
 This file is part of GNU CC.
@@ -509,3 +509,5 @@ do {									 \
 %{shared:-hidden_symbol __do_global_ctors,__do_global_ctors_1,__do_global_dtors} \
 -_SYSTYPE_SVR4 -woff 131 \
 %{mabi=32: -32}%{mabi=n32: -n32}%{mabi=64: -64}%{!mabi*: -n32}"
+
+#define MIPS_TFMODE_FORMAT ibm_extended_format
Index: gcc/config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.241
diff -u -p -r1.241 mips.c
--- gcc/config/mips/mips.c 12 Dec 2002 05:13:03 -0000 1.241
+++ gcc/config/mips/mips.c 27 Jan 2003 23:27:26 -0000
@@ -4321,9 +4321,11 @@ mips_arg_info (cum, mode, type, named, i
 	 is a double, but $f14 if it is a single.  Otherwise, on a
 	 32-bit double-float machine, each FP argument must start in a
 	 new register pair.  */
-      even_reg_p = ((mips_abi == ABI_O64 && mode == SFmode) || FP_INC > 1);
+      even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_HWFPVALUE
+		    || (mips_abi == ABI_O64 && mode == SFmode)
+		    || FP_INC > 1);
     }
-  else if (!TARGET_64BIT)
+  else if (!TARGET_64BIT || LONG_DOUBLE_TYPE_SIZE == 128)
     {
       if (GET_MODE_CLASS (mode) == MODE_INT
 	  || GET_MODE_CLASS (mode) == MODE_FLOAT)
@@ -4635,7 +4637,7 @@ mips_setup_incoming_varargs (cum, mode, 
 	      rtx ptr = plus_constant (virtual_incoming_args_rtx, off);
 	      emit_move_insn (gen_rtx_MEM (mode, ptr),
 			      gen_rtx_REG (mode, FP_ARG_FIRST + i));
-	      off += UNITS_PER_FPVALUE;
+	      off += UNITS_PER_HWFPVALUE;
 	    }
 	}
     }
@@ -4712,6 +4714,15 @@ mips_va_start (valist, nextarg)
 {
   const CUMULATIVE_ARGS *cum = &current_function_args_info;
 
+  /* ARG_POINTER_REGNUM is initialized to STACK_POINTER_BOUNDARY, but
+     since the stack is aligned for a pair of argument-passing slots,
+     and the beginning of a variable argument list may be an odd slot,
+     we have to decrease its alignment.  */
+  if (cfun && cfun->emit->regno_pointer_align)
+    while (((current_function_pretend_args_size * BITS_PER_UNIT)
+	    & (REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) - 1)) != 0)
+      REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) /= 2;
+
   if (mips_abi == ABI_EABI)
     {
       int gpr_save_area_size;
@@ -4909,9 +4920,9 @@ mips_va_arg (valist, type)
 	      off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
 
 	      /* When floating-point registers are saved to the stack,
-		 each one will take up UNITS_PER_FPVALUE bytes, regardless
+		 each one will take up UNITS_PER_HWFPVALUE bytes, regardless
 		 of the float's precision.  */
-	      rsize = UNITS_PER_FPVALUE;
+	      rsize = UNITS_PER_HWFPVALUE;
 	    }
 	  else
 	    {
@@ -4930,7 +4941,7 @@ mips_va_arg (valist, type)
 	     bytes (= PARM_BOUNDARY bits).  RSIZE can sometimes be smaller
 	     than that, such as in the combination -mgp64 -msingle-float
 	     -fshort-double.  Doubles passed in registers will then take
-	     up UNITS_PER_FPVALUE bytes, but those passed on the stack
+	     up UNITS_PER_HWFPVALUE bytes, but those passed on the stack
 	     take up UNITS_PER_WORD bytes.  */
 	  osize = MAX (rsize, UNITS_PER_WORD);
 
@@ -5007,7 +5018,10 @@ mips_va_arg (valist, type)
 	 that alignments <= UNITS_PER_WORD are preserved by the va_arg
 	 increment mechanism.  */
 
-      if (TARGET_64BIT)
+      if ((mips_abi == ABI_N32 || mips_abi == ABI_64)
+	  && TYPE_ALIGN (type) > 64)
+	align = 16;
+      else if (TARGET_64BIT)
 	align = 8;
       else if (TYPE_ALIGN (type) > 32)
 	align = 8;
@@ -5365,6 +5379,10 @@ override_options ()
   else
     mips16 = 0;
 
+#ifdef MIPS_TFMODE_FORMAT
+  real_format_for_mode[TFmode - QFmode] = &MIPS_TFMODE_FORMAT;
+#endif
+  
   mips_print_operand_punct['?'] = 1;
   mips_print_operand_punct['#'] = 1;
   mips_print_operand_punct['&'] = 1;
@@ -7085,7 +7103,7 @@ save_restore_insns (store_p, large_reg, 
       /* Pick which pointer to use as a base register.  */
       fp_offset = cfun->machine->frame.fp_sp_offset;
       end_offset = fp_offset - (cfun->machine->frame.fp_reg_size
-				- UNITS_PER_FPVALUE);
+				- UNITS_PER_HWFPVALUE);
 
       if (fp_offset < 0 || end_offset < 0)
 	internal_error
@@ -7140,7 +7158,7 @@ save_restore_insns (store_p, large_reg, 
 	    else
 	      emit_move_insn (reg_rtx, mem_rtx);
 
-	    fp_offset -= UNITS_PER_FPVALUE;
+	    fp_offset -= UNITS_PER_HWFPVALUE;
 	  }
     }
 }
@@ -8271,11 +8289,26 @@ mips_function_value (valtype, func, mode
     }
   mclass = GET_MODE_CLASS (mode);
 
-  if (mclass == MODE_FLOAT && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE)
+  if (mclass == MODE_FLOAT && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
     reg = FP_RETURN;
 
+  else if (mclass == MODE_FLOAT && mode == TFmode)
+    /* long doubles are really split between f0 and f2, not f1.  Eek.
+       Use DImode for each component, since GCC wants integer modes
+       for subregs.  */
+    return gen_rtx_PARALLEL
+      (VOIDmode,
+       gen_rtvec (2,
+		  gen_rtx_EXPR_LIST (VOIDmode,
+				     gen_rtx_REG (DImode, FP_RETURN),
+				     GEN_INT (0)),
+		  gen_rtx_EXPR_LIST (VOIDmode,
+				     gen_rtx_REG (DImode, FP_RETURN + 2),
+				     GEN_INT (GET_MODE_SIZE (mode) / 2))));
+       
+
   else if (mclass == MODE_COMPLEX_FLOAT
-	   && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE * 2)
+	   && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)
     {
       enum machine_mode cmode = GET_MODE_INNER (mode);
 
Index: gcc/config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.227.4.2
diff -u -p -r1.227.4.2 mips.h
--- gcc/config/mips/mips.h 17 Jan 2003 04:58:53 -0000 1.227.4.2
+++ gcc/config/mips/mips.h 27 Jan 2003 23:27:30 -0000
@@ -1487,8 +1487,14 @@ do {							\
    the next available register.  */
 #define FP_INC (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT ? 1 : 2)
 
-/* The largest size of value that can be held in floating-point registers.  */
-#define UNITS_PER_FPVALUE (TARGET_SOFT_FLOAT ? 0 : FP_INC * UNITS_PER_FPREG)
+/* The largest size of value that can be held in floating-point
+   registers and moved with a single instruction.  */
+#define UNITS_PER_HWFPVALUE (TARGET_SOFT_FLOAT ? 0 : FP_INC * UNITS_PER_FPREG)
+
+/* The largest size of value that can be held in floating-point
+   registers.  */
+#define UNITS_PER_FPVALUE \
+  (TARGET_SOFT_FLOAT ? 0 : (LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT))
 
 /* The number of bytes in a double.  */
 #define UNITS_PER_DOUBLE (TYPE_PRECISION (double_type_node) / BITS_PER_UNIT)
@@ -1535,7 +1541,21 @@ do {							\
 /* A C expression for the size in bits of the type `long double' on
    the target machine.  If you don't define this, the default is two
    words.  */
-#define LONG_DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE \
+  (mips_abi == ABI_N32 || mips_abi == ABI_64 ? 128 : 64)
+
+/* long double is not a fixed mode, but the idea is that, if we
+   support long double, we also want a 128-bit integer type.  */
+#define MAX_FIXED_MODE_SIZE LONG_DOUBLE_TYPE_SIZE
+
+#ifdef IN_LIBGCC2
+#if  (defined _ABIN32 && _MIPS_SIM == _ABIN32) \
+  || (defined _ABI64 && _MIPS_SIM == _ABI64)
+#  define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128
+# else
+#  define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64
+# endif
+#endif
 
 /* Width in bits of a pointer.
    See also the macro `Pmode' defined below.  */
@@ -1562,7 +1582,7 @@ do {							\
 #define STRUCTURE_SIZE_BOUNDARY 8
 
 /* There is no point aligning anything to a rounder boundary than this.  */
-#define BIGGEST_ALIGNMENT 64
+#define BIGGEST_ALIGNMENT LONG_DOUBLE_TYPE_SIZE
 
 /* Set this nonzero if move instructions will actually fail to work
    when given unaligned data.  */
@@ -2624,7 +2644,9 @@ extern enum reg_class mips_char_to_class
    On the MIPS, R2 R3 and F0 F2 are the only register thus used.
    Currently, R2 and F0 are only implemented  here (C has no complex type)  */
 
-#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN)
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN \
+  || (LONG_DOUBLE_TYPE_SIZE == 128 && FP_RETURN != GP_RETURN \
+      && (N) == FP_RETURN + 2))
 
 /* 1 if N is a possible register number for function argument passing.
    We have no FP argument registers when soft-float.  When FP registers
Index: gcc/config/mips/t-iris6
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/t-iris6,v
retrieving revision 1.16
diff -u -p -r1.16 t-iris6
--- gcc/config/mips/t-iris6 12 Nov 2002 11:15:48 -0000 1.16
+++ gcc/config/mips/t-iris6 27 Jan 2003 23:27:30 -0000
@@ -18,3 +18,16 @@ CRTSTUFF_T_CFLAGS=-g1
 # This is only needed in the static libgcc as a band-aid until gcc correctly
 # implements the N32/N64 ABI structure passing conventions
 LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/mips/irix6-libc-compat.c
+
+LIB2FUNCS_EXTRA = $(srcdir)/config/mips/_tilib.c
+
+TPBIT = tp-bit.c
+
+tp-bit.c: $(srcdir)/config/fp-bit.c
+	echo '#ifdef __MIPSEL__' > tp-bit.c
+	echo '# define FLOAT_BIT_ORDER_MISMATCH' >> tp-bit.c
+	echo '#endif' >> tp-bit.c
+	echo '#if __LDBL_MANT_DIG__ == 106' >> tp-bit.c
+	echo '# define TFLOAT' >> tp-bit.c
+	cat $(srcdir)/config/fp-bit.c >> tp-bit.c
+	echo '#endif' >> tp-bit.c
Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* config/mips/mips.h (UNITS_PER_HWFPVALUE): Renamed from...
	(UNITS_PER_FPVALUE): Defined as the width of a long double, or
	zero if no hardware floating point.
	(LONG_DUBLE_TYPE_SIZE): Set to 128 on N32 and N64.
	(MAX_FIXED_MODE_SIZE): Define to LONG_DOUBLE_TYPE_SIZE.
	(LIBGCC2_LONG_DOUBLE_TYPE_SIZE): Define.
	(BIGGEST_ALIGNMENT): Same as LONG_DOUBLE_TYPE_SIZE.
	(FUNCTION_VALUE_REGNO_P): Set for FP_RETURN+2 on N32 and N64.
	* config/mips/mips.c (mips_arg_info): Pass TFmode values in
	even FP registers on N32 and N64.
	(mips_setup_incoming_varargs): Use UNITS_PER_HWFPVALUE.
	(mips_va_start): Adjust alignment of ARG_POINTER_REGNUM.
	(mips_va_arg): Use UNITS_PER_HWFPVALUE.  Impose additional
	even-register-like alignment to 128-bit arguments.
	(save_restore_insns): Use UNITS_PER_HWFPVALUE.
	(mips_function_value): Likewise.  Return TFmode in $f0 and $f2
	on N32 or N64.
	* config/mips/_tilib.c (__negti2, __ashlti3, __lshrti3): New.
	* config/mips/t-iris6 (LIB2FUNCS_EXTRA): Add _tilib.c.
	(TPBIT): Set to tp-bit.c.
	(tp-bit.c): Create out of fp-bit.c.

Index: gcc/config/mips/_tilib.c
===================================================================
RCS file: gcc/config/mips/_tilib.c
diff -N gcc/config/mips/_tilib.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/config/mips/_tilib.c 28 Jan 2003 02:12:21 -0000
@@ -0,0 +1,162 @@
+/* A few TImode functions needed for TFmode emulated arithmetic.
+   Copyright 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "defaults.h"
+
+#ifndef LIBGCC2_WORDS_BIG_ENDIAN
+#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
+#endif
+
+#if _MIPS_SIM == 2 /* N32 */ || _MIPS_SIM == 3 /* 64 */
+
+typedef int TItype __attribute__ ((mode (TI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef int SItype __attribute__ ((mode (SI)));
+
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+
+typedef union
+{
+  struct TIstruct {
+#if LIBGCC2_WORDS_BIG_ENDIAN
+    DItype high, low;
+#else
+    DItype low, high;
+#endif
+  } s;
+  TItype ll;
+} TIunion;
+
+TItype __negti2 (TItype);
+TItype __ashlti3 (TItype, int);
+#if 0
+TItype __ashrti3 (TItype, int);
+#endif
+TItype __lshrti3 (TItype, int);
+
+TItype
+__negti2 (TItype u)
+{
+  TIunion w;
+  TIunion uu;
+
+  uu.ll = u;
+
+  w.s.low = -uu.s.low;
+  w.s.high = -uu.s.high - ((UDItype) w.s.low > 0);
+
+  return w.ll;
+}
+
+TItype
+__ashlti3 (TItype u, int b)
+{
+  TIunion w;
+  int bm;
+  TIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (DItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      w.s.low = 0;
+      w.s.high = (UDItype) uu.s.low << -bm;
+    }
+  else
+    {
+      UDItype carries = (UDItype) uu.s.low >> bm;
+
+      w.s.low = (UDItype) uu.s.low << b;
+      w.s.high = ((UDItype) uu.s.high << b) | carries;
+    }
+
+  return w.ll;
+}
+
+#if 0
+TItype
+__ashrti3 (TItype u, int b)
+{
+  TIunion w;
+  int bm;
+  TIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (DItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      /* w.s.high = 1..1 or 0..0 */
+      w.s.high = uu.s.high >> (sizeof (DItype) * BITS_PER_UNIT - 1);
+      w.s.low = uu.s.high >> -bm;
+    }
+  else
+    {
+      UDItype carries = (UDItype) uu.s.high << bm;
+
+      w.s.high = uu.s.high >> b;
+      w.s.low = ((UDItype) uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
+#endif
+
+TItype
+__lshrti3 (TItype u, int b)
+{
+  TIunion w;
+  int bm;
+  TIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (DItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      w.s.high = 0;
+      w.s.low = (UDItype) uu.s.high >> -bm;
+    }
+  else
+    {
+      UDItype carries = (UDItype) uu.s.high << bm;
+
+      w.s.high = (UDItype) uu.s.high >> b;
+      w.s.low = ((UDItype) uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
+
+#endif /* N32 or N64 */
Index: gcc/config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.247
diff -u -p -r1.247 mips.c
--- gcc/config/mips/mips.c 19 Jan 2003 13:04:24 -0000 1.247
+++ gcc/config/mips/mips.c 28 Jan 2003 02:12:27 -0000
@@ -4315,9 +4315,11 @@ mips_arg_info (cum, mode, type, named, i
 	 is a double, but $f14 if it is a single.  Otherwise, on a
 	 32-bit double-float machine, each FP argument must start in a
 	 new register pair.  */
-      even_reg_p = ((mips_abi == ABI_O64 && mode == SFmode) || FP_INC > 1);
+      even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_HWFPVALUE
+		    || (mips_abi == ABI_O64 && mode == SFmode)
+		    || FP_INC > 1);
     }
-  else if (!TARGET_64BIT)
+  else if (!TARGET_64BIT || LONG_DOUBLE_TYPE_SIZE == 128)
     {
       if (GET_MODE_CLASS (mode) == MODE_INT
 	  || GET_MODE_CLASS (mode) == MODE_FLOAT)
@@ -4629,7 +4631,7 @@ mips_setup_incoming_varargs (cum, mode, 
 	      rtx ptr = plus_constant (virtual_incoming_args_rtx, off);
 	      emit_move_insn (gen_rtx_MEM (mode, ptr),
 			      gen_rtx_REG (mode, FP_ARG_FIRST + i));
-	      off += UNITS_PER_FPVALUE;
+	      off += UNITS_PER_HWFPVALUE;
 	    }
 	}
     }
@@ -4706,6 +4708,15 @@ mips_va_start (valist, nextarg)
 {
   const CUMULATIVE_ARGS *cum = &current_function_args_info;
 
+  /* ARG_POINTER_REGNUM is initialized to STACK_POINTER_BOUNDARY, but
+     since the stack is aligned for a pair of argument-passing slots,
+     and the beginning of a variable argument list may be an odd slot,
+     we have to decrease its alignment.  */
+  if (cfun && cfun->emit->regno_pointer_align)
+    while (((current_function_pretend_args_size * BITS_PER_UNIT)
+	    & (REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) - 1)) != 0)
+      REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) /= 2;
+
   if (mips_abi == ABI_EABI)
     {
       int gpr_save_area_size;
@@ -4903,9 +4914,9 @@ mips_va_arg (valist, type)
 	      off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
 
 	      /* When floating-point registers are saved to the stack,
-		 each one will take up UNITS_PER_FPVALUE bytes, regardless
+		 each one will take up UNITS_PER_HWFPVALUE bytes, regardless
 		 of the float's precision.  */
-	      rsize = UNITS_PER_FPVALUE;
+	      rsize = UNITS_PER_HWFPVALUE;
 	    }
 	  else
 	    {
@@ -4924,7 +4935,7 @@ mips_va_arg (valist, type)
 	     bytes (= PARM_BOUNDARY bits).  RSIZE can sometimes be smaller
 	     than that, such as in the combination -mgp64 -msingle-float
 	     -fshort-double.  Doubles passed in registers will then take
-	     up UNITS_PER_FPVALUE bytes, but those passed on the stack
+	     up UNITS_PER_HWFPVALUE bytes, but those passed on the stack
 	     take up UNITS_PER_WORD bytes.  */
 	  osize = MAX (rsize, UNITS_PER_WORD);
 
@@ -4998,7 +5009,10 @@ mips_va_arg (valist, type)
 	 that alignments <= UNITS_PER_WORD are preserved by the va_arg
 	 increment mechanism.  */
 
-      if (TARGET_64BIT)
+      if ((mips_abi == ABI_N32 || mips_abi == ABI_64)
+	  && TYPE_ALIGN (type) > 64)
+	align = 16;
+      else if (TARGET_64BIT)
 	align = 8;
       else if (TYPE_ALIGN (type) > 32)
 	align = 8;
@@ -7080,7 +7094,7 @@ save_restore_insns (store_p, large_reg, 
       /* Pick which pointer to use as a base register.  */
       fp_offset = cfun->machine->frame.fp_sp_offset;
       end_offset = fp_offset - (cfun->machine->frame.fp_reg_size
-				- UNITS_PER_FPVALUE);
+				- UNITS_PER_HWFPVALUE);
 
       if (fp_offset < 0 || end_offset < 0)
 	internal_error
@@ -7133,7 +7147,7 @@ save_restore_insns (store_p, large_reg, 
 	    else
 	      emit_move_insn (reg_rtx, mem_rtx);
 
-	    fp_offset -= UNITS_PER_FPVALUE;
+	    fp_offset -= UNITS_PER_HWFPVALUE;
 	  }
     }
 }
@@ -8264,11 +8278,26 @@ mips_function_value (valtype, func, mode
     }
   mclass = GET_MODE_CLASS (mode);
 
-  if (mclass == MODE_FLOAT && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE)
+  if (mclass == MODE_FLOAT && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
     reg = FP_RETURN;
 
+  else if (mclass == MODE_FLOAT && mode == TFmode)
+    /* long doubles are really split between f0 and f2, not f1.  Eek.
+       Use DImode for each component, since GCC wants integer modes
+       for subregs.  */
+    return gen_rtx_PARALLEL
+      (VOIDmode,
+       gen_rtvec (2,
+		  gen_rtx_EXPR_LIST (VOIDmode,
+				     gen_rtx_REG (DImode, FP_RETURN),
+				     GEN_INT (0)),
+		  gen_rtx_EXPR_LIST (VOIDmode,
+				     gen_rtx_REG (DImode, FP_RETURN + 2),
+				     GEN_INT (GET_MODE_SIZE (mode) / 2))));
+       
+
   else if (mclass == MODE_COMPLEX_FLOAT
-	   && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE * 2)
+	   && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)
     {
       enum machine_mode cmode = GET_MODE_INNER (mode);
 
Index: gcc/config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.234
diff -u -p -r1.234 mips.h
--- gcc/config/mips/mips.h 19 Jan 2003 13:04:24 -0000 1.234
+++ gcc/config/mips/mips.h 28 Jan 2003 02:12:31 -0000
@@ -1517,8 +1517,14 @@ do {							\
    the next available register.  */
 #define FP_INC (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT ? 1 : 2)
 
-/* The largest size of value that can be held in floating-point registers.  */
-#define UNITS_PER_FPVALUE (TARGET_SOFT_FLOAT ? 0 : FP_INC * UNITS_PER_FPREG)
+/* The largest size of value that can be held in floating-point
+   registers and moved with a single instruction.  */
+#define UNITS_PER_HWFPVALUE (TARGET_SOFT_FLOAT ? 0 : FP_INC * UNITS_PER_FPREG)
+
+/* The largest size of value that can be held in floating-point
+   registers.  */
+#define UNITS_PER_FPVALUE \
+  (TARGET_SOFT_FLOAT ? 0 : (LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT))
 
 /* The number of bytes in a double.  */
 #define UNITS_PER_DOUBLE (TYPE_PRECISION (double_type_node) / BITS_PER_UNIT)
@@ -1565,7 +1571,21 @@ do {							\
 /* A C expression for the size in bits of the type `long double' on
    the target machine.  If you don't define this, the default is two
    words.  */
-#define LONG_DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE \
+  (mips_abi == ABI_N32 || mips_abi == ABI_64 ? 128 : 64)
+
+/* long double is not a fixed mode, but the idea is that, if we
+   support long double, we also want a 128-bit integer type.  */
+#define MAX_FIXED_MODE_SIZE LONG_DOUBLE_TYPE_SIZE
+
+#ifdef IN_LIBGCC2
+#if  (defined _ABIN32 && _MIPS_SIM == _ABIN32) \
+  || (defined _ABI64 && _MIPS_SIM == _ABI64)
+#  define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128
+# else
+#  define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64
+# endif
+#endif
 
 /* Width in bits of a pointer.
    See also the macro `Pmode' defined below.  */
@@ -1592,7 +1612,7 @@ do {							\
 #define STRUCTURE_SIZE_BOUNDARY 8
 
 /* There is no point aligning anything to a rounder boundary than this.  */
-#define BIGGEST_ALIGNMENT 64
+#define BIGGEST_ALIGNMENT LONG_DOUBLE_TYPE_SIZE
 
 /* Set this nonzero if move instructions will actually fail to work
    when given unaligned data.  */
@@ -2654,7 +2674,9 @@ extern enum reg_class mips_char_to_class
    On the MIPS, R2 R3 and F0 F2 are the only register thus used.
    Currently, R2 and F0 are only implemented  here (C has no complex type)  */
 
-#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN)
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN \
+  || (LONG_DOUBLE_TYPE_SIZE == 128 && FP_RETURN != GP_RETURN \
+      && (N) == FP_RETURN + 2))
 
 /* 1 if N is a possible register number for function argument passing.
    We have no FP argument registers when soft-float.  When FP registers
Index: gcc/config/mips/t-iris6
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/t-iris6,v
retrieving revision 1.16
diff -u -p -r1.16 t-iris6
--- gcc/config/mips/t-iris6 12 Nov 2002 11:15:48 -0000 1.16
+++ gcc/config/mips/t-iris6 28 Jan 2003 02:12:31 -0000
@@ -18,3 +18,16 @@ CRTSTUFF_T_CFLAGS=-g1
 # This is only needed in the static libgcc as a band-aid until gcc correctly
 # implements the N32/N64 ABI structure passing conventions
 LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/mips/irix6-libc-compat.c
+
+LIB2FUNCS_EXTRA = $(srcdir)/config/mips/_tilib.c
+
+TPBIT = tp-bit.c
+
+tp-bit.c: $(srcdir)/config/fp-bit.c
+	echo '#ifdef __MIPSEL__' > tp-bit.c
+	echo '# define FLOAT_BIT_ORDER_MISMATCH' >> tp-bit.c
+	echo '#endif' >> tp-bit.c
+	echo '#if __LDBL_MANT_DIG__ == 106' >> tp-bit.c
+	echo '# define TFLOAT' >> tp-bit.c
+	cat $(srcdir)/config/fp-bit.c >> tp-bit.c
+	echo '#endif' >> tp-bit.c
-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist                Professional serial bug killer

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]