OSDN Git Service

Add support for MIPS EABI
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 16 Oct 1996 02:33:42 +0000 (02:33 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 16 Oct 1996 02:33:42 +0000 (02:33 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@12967 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/mips/abi64.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/ginclude/va-mips.h

index 9e1a4b9..df6eec6 100644 (file)
@@ -26,11 +26,14 @@ Boston, MA 02111-1307, USA.  */
   { "abi=", &mips_abi_string   },
 
 #undef STACK_BOUNDARY
-#define STACK_BOUNDARY (mips_abi == ABI_32 ? 64 : 128)
+#define STACK_BOUNDARY \
+  ((mips_abi == ABI_32 || mips_abi == ABI_EABI) ? 64 : 128)
 
 #undef MIPS_STACK_ALIGN
-#define MIPS_STACK_ALIGN(LOC) \
-  (mips_abi == ABI_32 ? ((LOC)+7) & ~7 : ((LOC)+15) & ~15)
+#define MIPS_STACK_ALIGN(LOC)                                  \
+  ((mips_abi == ABI_32 || mips_abi == ABI_EABI)                        \
+   ? ((LOC) + 7) & ~7                                          \
+   : ((LOC) + 15) & ~15)
 
 #undef GP_ARG_LAST
 #define GP_ARG_LAST  (mips_abi == ABI_32 ? GP_REG_FIRST + 7 : GP_REG_FIRST + 11)
@@ -78,13 +81,16 @@ Boston, MA 02111-1307, USA.  */
        ? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST                \
          && int_size_in_bytes (TYPE) < (PARM_BOUNDARY / BITS_PER_UNIT))\
        : (GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY                      \
-         && (mips_abi == ABI_32 || GET_MODE_CLASS (MODE) == MODE_INT)))\
+         && (mips_abi == ABI_32 || mips_abi == ABI_EABI                \
+             || GET_MODE_CLASS (MODE) == MODE_INT)))                   \
       ? downward : upward))
 
 #undef RETURN_IN_MEMORY
-#define RETURN_IN_MEMORY(TYPE) \
+#define RETURN_IN_MEMORY(TYPE)                                         \
   (mips_abi == ABI_32                                                  \
-   ? TYPE_MODE (TYPE) == BLKmode : int_size_in_bytes (TYPE) > 16)
+   ? TYPE_MODE (TYPE) == BLKmode                                       \
+   : (int_size_in_bytes (TYPE)                                         \
+      > (mips_abi == ABI_EABI ? 2 * UNITS_PER_WORD : 16)))
 
 extern struct rtx_def *mips_function_value ();
 #undef FUNCTION_VALUE
@@ -95,29 +101,78 @@ extern struct rtx_def *mips_function_value ();
    For stdarg, we do not need to save the current argument, because it
    is a real argument.  */
 #define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL)      \
-{ if (mips_abi != ABI_32                                               \
-      && ((CUM).arg_words                                              \
-         < (MAX_ARGS_IN_REGISTERS - ! current_function_varargs)))      \
+{ int mips_off = (! current_function_varargs) && (! (CUM).last_arg_fp);        \
+  int mips_fp_off = (! current_function_varargs) && ((CUM).last_arg_fp); \
+  if ((mips_abi != ABI_32                                              \
+       && (CUM).arg_words < MAX_ARGS_IN_REGISTERS - mips_off)          \
+      || (mips_abi == ABI_EABI                                         \
+         && ! TARGET_SOFT_FLOAT                                        \
+         && (CUM).fp_arg_words < MAX_ARGS_IN_REGISTERS - mips_fp_off)) \
     {                                                                  \
-      PRETEND_SIZE                                                     \
-       = (MAX_ARGS_IN_REGISTERS - (CUM).arg_words                      \
-          - ! current_function_varargs) * UNITS_PER_WORD;              \
+      int mips_save_gp_regs =                                          \
+        MAX_ARGS_IN_REGISTERS - (CUM).arg_words - mips_off;            \
+      int mips_save_fp_regs =                                          \
+        (mips_abi != ABI_EABI ? 0                                      \
+        : MAX_ARGS_IN_REGISTERS - (CUM).fp_arg_words - mips_fp_off);   \
+                                                                       \
+      if (mips_save_gp_regs < 0)                                       \
+       mips_save_gp_regs = 0;                                          \
+      if (mips_save_fp_regs < 0)                                       \
+       mips_save_fp_regs = 0;                                          \
+      PRETEND_SIZE = ((mips_save_gp_regs * UNITS_PER_WORD)             \
+                     + (mips_save_fp_regs * UNITS_PER_FPREG));         \
                                                                        \
       if (! (NO_RTL))                                                  \
        {                                                               \
-         rtx mem = gen_rtx (MEM, BLKmode, virtual_incoming_args_rtx);  \
-         /* va_arg is an array access in this case, which causes it to \
-            get MEM_IN_STRUCT_P set.  We must set it here so that the  \
-            insn scheduler won't assume that these stores can't        \
-            possibly overlap with the va_arg loads.  */                \
-         if (BYTES_BIG_ENDIAN)                                         \
-           MEM_IN_STRUCT_P (mem) = 1;                                  \
-         move_block_from_reg                                           \
-           ((CUM).arg_words + GP_ARG_FIRST + ! current_function_varargs, \
-            mem,                                                       \
-            (MAX_ARGS_IN_REGISTERS - (CUM).arg_words                   \
-             - ! current_function_varargs),                            \
-            PRETEND_SIZE);                                             \
+         if ((CUM).arg_words < MAX_ARGS_IN_REGISTERS - mips_off)       \
+           {                                                           \
+             rtx ptr, mem;                                             \
+             if (mips_abi != ABI_EABI)                                 \
+               ptr = virtual_incoming_args_rtx;                        \
+             else                                                      \
+               ptr = plus_constant (virtual_incoming_args_rtx,         \
+                                    - (mips_save_gp_regs               \
+                                       * UNITS_PER_WORD));             \
+             mem = gen_rtx (MEM, BLKmode, ptr);                        \
+             /* va_arg is an array access in this case, which causes   \
+                it to get MEM_IN_STRUCT_P set.  We must set it here    \
+                so that the insn scheduler won't assume that these     \
+                stores can't possibly overlap with the va_arg loads.  */ \
+             if (mips_abi != ABI_EABI && BYTES_BIG_ENDIAN)             \
+               MEM_IN_STRUCT_P (mem) = 1;                              \
+             move_block_from_reg                                       \
+               ((CUM).arg_words + GP_ARG_FIRST + mips_off,             \
+                mem,                                                   \
+                mips_save_gp_regs,                                     \
+                mips_save_gp_regs * UNITS_PER_WORD);                   \
+           }                                                           \
+         if (mips_abi == ABI_EABI                                      \
+             && ! TARGET_SOFT_FLOAT                                    \
+             && (CUM).fp_arg_words < MAX_ARGS_IN_REGISTERS - mips_fp_off) \
+           {                                                           \
+             int off;                                                  \
+             int i;                                                    \
+             /* We can't use move_block_from_reg, because it will use  \
+                 the wrong mode.  */                                   \
+             off = (- (mips_save_gp_regs * UNITS_PER_WORD)             \
+                    - (mips_save_fp_regs * UNITS_PER_FPREG));          \
+             for (i = 0; i < mips_save_fp_regs; i++)                   \
+               {                                                       \
+                 rtx tem =                                             \
+                   gen_rtx (MEM, DFmode,                               \
+                            plus_constant (virtual_incoming_args_rtx,  \
+                                           (off                        \
+                                            + i * GET_MODE_SIZE (DFmode)))); \
+                 emit_move_insn (tem,                                  \
+                                 gen_rtx (REG, DFmode,                 \
+                                          ((CUM).fp_arg_words          \
+                                           + FP_ARG_FIRST              \
+                                           + i                         \
+                                           + mips_fp_off)));           \
+                 if (! TARGET_FLOAT64)                                 \
+                   ++i;                                                \
+               }                                                       \
+           }                                                           \
        }                                                               \
     }                                                                  \
 }
@@ -125,6 +180,32 @@ extern struct rtx_def *mips_function_value ();
 /* ??? Should disable for mips_abi == ABI32.  */
 #define STRICT_ARGUMENT_NAMING
 
+/* A C expression that indicates when an argument must be passed by
+   reference.  If nonzero for an argument, a copy of that argument is
+   made in memory and a pointer to the argument is passed instead of the
+   argument itself.  The pointer is passed in whatever way is appropriate
+   for passing a pointer to that type.  */
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)         \
+  (mips_abi == ABI_EABI                                                        \
+   && function_arg_pass_by_reference (&CUM, MODE, TYPE, NAMED))
+
+/* A C expression that indicates when it is the called function's
+   responsibility to make a copy of arguments passed by invisible
+   reference.  Normally, the caller makes a copy and passes the
+   address of the copy to the routine being called.  When
+   FUNCTION_ARG_CALLEE_COPIES is defined and is nonzero, the caller
+   does not make a copy.  Instead, it passes a pointer to the "live"
+   value.  The called function must not modify this value.  If it can
+   be determined that the value won't be modified, it need not make a
+   copy; otherwise a copy must be made.
+
+   ??? The MIPS EABI says that the caller should copy in ``K&R mode.''
+   I don't know how to detect that here, since flag_traditional is not
+   a back end flag.  */
+#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED)             \
+  (mips_abi == ABI_EABI && (NAMED)                                     \
+   && FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED))
+
 /* ??? Unimplemented stuff follows.  */
 
 /* ??? Add support for 16 byte/128 bit long doubles here when
index f32117b..29a53ac 100644 (file)
@@ -201,7 +201,7 @@ enum mips_abi_type mips_abi;
 /* Strings to hold which cpu and instruction set architecture to use.  */
 char *mips_cpu_string;         /* for -mcpu=<xxx> */
 char *mips_isa_string;         /* for -mips{1,2,3,4} */
-char *mips_abi_string;         /* for -mabi={o32,32,n32,n64,64} */
+char *mips_abi_string;         /* for -mabi={o32,32,n32,n64,64,eabi} */
 
 /* If TRUE, we split addresses into their high and low parts in the RTL.  */
 int mips_split_addresses;
@@ -500,7 +500,7 @@ mips_const_double_ok (op, mode)
     return TRUE;
 
   /* ??? li.s does not work right with SGI's Irix 6 assembler.  */
-  if (mips_abi != ABI_32)
+  if (mips_abi != ABI_32 && mips_abi != ABI_EABI)
     return FALSE;
 
   REAL_VALUE_FROM_CONST_DOUBLE (d, op);
@@ -3031,11 +3031,17 @@ function_arg_advance (cum, mode, type, named)
       break;
 
     case SFmode:
-      cum->arg_words++;
+      if (mips_abi == ABI_EABI && ! TARGET_SOFT_FLOAT)
+       cum->fp_arg_words++;
+      else
+       cum->arg_words++;
       break;
 
     case DFmode:
-      cum->arg_words += (TARGET_64BIT ? 1 : 2);
+      if (mips_abi == ABI_EABI && ! TARGET_SOFT_FLOAT && ! TARGET_SINGLE_FLOAT)
+       cum->fp_arg_words += (TARGET_64BIT ? 1 : 2);
+      else
+       cum->arg_words += (TARGET_64BIT ? 1 : 2);
       break;
 
     case DImode:
@@ -3065,6 +3071,7 @@ function_arg (cum, mode, type, named)
   rtx ret;
   int regbase = -1;
   int bias = 0;
+  int *arg_words = &cum->arg_words;
   int struct_p = ((type != (tree)0)
                  && (TREE_CODE (type) == RECORD_TYPE
                      || TREE_CODE (type) == UNION_TYPE));
@@ -3075,6 +3082,7 @@ function_arg (cum, mode, type, named)
             cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
             type, named);
 
+  cum->last_arg_fp = 0;
   switch (mode)
     {
     case SFmode:
@@ -3091,13 +3099,28 @@ function_arg (cum, mode, type, named)
                bias = 1;
            }
        }
+      else if (mips_abi == ABI_EABI && ! TARGET_SOFT_FLOAT)
+       {
+         if (! TARGET_64BIT)
+           cum->fp_arg_words += cum->fp_arg_words & 1;
+         cum->last_arg_fp = 1;
+         arg_words = &cum->fp_arg_words;
+         regbase = FP_ARG_FIRST;
+       }
       else
        regbase = (TARGET_SOFT_FLOAT || ! named ? GP_ARG_FIRST : FP_ARG_FIRST);
       break;
 
     case DFmode:
       if (! TARGET_64BIT)
-       cum->arg_words += (cum->arg_words & 1);
+       {
+         if (mips_abi == ABI_EABI
+             && ! TARGET_SOFT_FLOAT
+             && ! TARGET_SINGLE_FLOAT)
+           cum->fp_arg_words += cum->fp_arg_words & 1;
+         else
+           cum->arg_words += cum->arg_words & 1;
+       }
       if (mips_abi == ABI_32)
        regbase = ((cum->gp_reg_found
                    || TARGET_SOFT_FLOAT
@@ -3105,6 +3128,14 @@ function_arg (cum, mode, type, named)
                    || cum->arg_number >= 2)
                   ? GP_ARG_FIRST
                   : FP_ARG_FIRST);
+      else if (mips_abi == ABI_EABI
+              && ! TARGET_SOFT_FLOAT
+              && ! TARGET_SINGLE_FLOAT)
+       {
+         cum->last_arg_fp = 1;
+         arg_words = &cum->fp_arg_words;
+         regbase = FP_ARG_FIRST;
+       }
       else
        regbase = (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT || ! named
                   ? GP_ARG_FIRST : FP_ARG_FIRST);
@@ -3118,9 +3149,8 @@ function_arg (cum, mode, type, named)
       /* Drops through.  */
     case BLKmode:
       if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD
-         && ! TARGET_64BIT)
+         && ! TARGET_64BIT && mips_abi != ABI_EABI)
        cum->arg_words += (cum->arg_words & 1);
-
       regbase = GP_ARG_FIRST;
       break;
 
@@ -3137,7 +3167,7 @@ function_arg (cum, mode, type, named)
       regbase = GP_ARG_FIRST;
     }
 
-  if (cum->arg_words >= MAX_ARGS_IN_REGISTERS)
+  if (*arg_words >= MAX_ARGS_IN_REGISTERS)
     {
       if (TARGET_DEBUG_E_MODE)
        fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : "");
@@ -3150,8 +3180,8 @@ function_arg (cum, mode, type, named)
        abort ();
 
       if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32
-         || ! named)
-       ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias);
+         || mips_abi == ABI_EABI || ! named)
+       ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
       else
        {
          /* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
@@ -3169,7 +3199,7 @@ function_arg (cum, mode, type, named)
              break;
 
          if (! field)
-           ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias);
+           ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
          else
            {
              /* Now handle the special case by returning a PARALLEL
@@ -3188,15 +3218,15 @@ function_arg (cum, mode, type, named)
                 backend to allow DImode values in fp registers.  */
 
              chunks = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_WORD;
-             if (chunks + cum->arg_words + bias > MAX_ARGS_IN_REGISTERS)
-               chunks = MAX_ARGS_IN_REGISTERS - cum->arg_words - bias;
+             if (chunks + *arg_words + bias > MAX_ARGS_IN_REGISTERS)
+               chunks = MAX_ARGS_IN_REGISTERS - *arg_words - bias;
 
              /* assign_parms checks the mode of ENTRY_PARM, so we must
                 use the actual mode here.  */
              ret = gen_rtx (PARALLEL, mode, rtvec_alloc (chunks));
 
              bitpos = 0;
-             regno = regbase + cum->arg_words + bias;
+             regno = regbase + *arg_words + bias;
              field = TYPE_FIELDS (type);
              for (i = 0; i < chunks; i++)
                {
@@ -3227,7 +3257,7 @@ function_arg (cum, mode, type, named)
        }
 
       if (TARGET_DEBUG_E_MODE)
-       fprintf (stderr, "%s%s\n", reg_names[regbase + cum->arg_words + bias],
+       fprintf (stderr, "%s%s\n", reg_names[regbase + *arg_words + bias],
                 struct_p ? ", [struct]" : "");
 
       /* The following is a hack in order to pass 1 byte structures
@@ -3250,11 +3280,11 @@ function_arg (cum, mode, type, named)
         calling convention for now.  */
 
       if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD
-         && ! TARGET_64BIT)
+         && ! TARGET_64BIT && mips_abi != ABI_EABI)
        {
          rtx amount = GEN_INT (BITS_PER_WORD
                                - int_size_in_bytes (type) * BITS_PER_UNIT);
-         rtx reg = gen_rtx (REG, word_mode, regbase + cum->arg_words + bias);
+         rtx reg = gen_rtx (REG, word_mode, regbase + *arg_words + bias);
          if (TARGET_64BIT)
            cum->adjust[ cum->num_adjusts++ ] = gen_ashldi3 (reg, reg, amount);
          else
@@ -3279,7 +3309,8 @@ function_arg_partial_nregs (cum, mode, type, named)
   if ((mode == BLKmode
        || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
        || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
-      && cum->arg_words < MAX_ARGS_IN_REGISTERS)
+      && cum->arg_words < MAX_ARGS_IN_REGISTERS
+      && mips_abi != ABI_EABI)
     {
       int words;
       if (mode == BLKmode)
@@ -3299,7 +3330,8 @@ function_arg_partial_nregs (cum, mode, type, named)
     }
 
   else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1
-          && ! TARGET_64BIT)
+          && ! TARGET_64BIT
+          && mips_abi != ABI_EABI)
     {
       if (TARGET_DEBUG_E_MODE)
        fprintf (stderr, "function_arg_partial_nregs = 1\n");
@@ -3402,11 +3434,13 @@ override_options ()
   else if (! strcmp (mips_abi_string, "64")
           || ! strcmp (mips_abi_string, "n64"))
     mips_abi = ABI_64;
+  else if (! strcmp (mips_abi_string, "eabi"))
+    mips_abi = ABI_EABI;
   else
     error ("bad value (%s) for -mabi= switch", mips_abi_string);
 
   /* A specified ISA defaults the ABI if it was not specified.  */
-  if (mips_abi_string == 0 && mips_isa_string)
+  if (mips_abi_string == 0 && mips_isa_string && mips_abi != ABI_EABI)
     {
       if (mips_isa <= 2)
        mips_abi = ABI_32;
@@ -3414,7 +3448,7 @@ override_options ()
        mips_abi = ABI_64;
     }
   /* A specified ABI defaults the ISA if it was not specified.  */
-  else if (mips_isa_string == 0 && mips_abi_string)
+  else if (mips_isa_string == 0 && mips_abi_string && mips_abi != ABI_EABI)
     {
       if (mips_abi == ABI_32)
        mips_isa = 1;
@@ -4506,7 +4540,7 @@ mips_asm_file_start (stream)
 
   /* Start a section, so that the first .popsection directive is guaranteed
      to have a previously defined section to pop back to.  */
-  if (mips_abi != ABI_32)
+  if (mips_abi != ABI_32 && mips_abi != ABI_EABI)
     fprintf (stream, "\t.section\t.text\n");
 
   /* This code exists so that we can put all externs before all symbol
@@ -4853,7 +4887,7 @@ compute_frame_size (size)
      for leaf routines (total_size == extra_size) to save the gp reg.
      The gp reg is callee saved in the 64 bit ABI, so all routines must
      save the gp reg.  */
-  if (total_size == extra_size && mips_abi == ABI_32)
+  if (total_size == extra_size && (mips_abi == ABI_32 || mips_abi == ABI_EABI))
     total_size = extra_size = 0;
   else if (TARGET_ABICALLS)
     {
@@ -5857,7 +5891,8 @@ mips_function_value (valtype, func)
   /* ??? How should we return complex float?  */
   if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
     reg = FP_RETURN;
-  else if (TREE_CODE (valtype) == RECORD_TYPE && mips_abi != ABI_32)
+  else if (TREE_CODE (valtype) == RECORD_TYPE
+          && mips_abi != ABI_32 && mips_abi != ABI_EABI)
     {
       /* A struct with only one or two floating point fields is returned in
         the floating point registers.  */
@@ -5916,6 +5951,30 @@ mips_function_value (valtype, func)
 
   return gen_rtx (REG, mode, reg);
 }
+
+/* The implementation of FUNCTION_ARG_PASS_BY_REFERENCE.  Return
+   nonzero when an argument must be passed by reference.  */
+
+int
+function_arg_pass_by_reference (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int named;
+{
+  int size;
+
+  if (mips_abi != ABI_EABI)
+    return 0;
+
+  /* ??? How should SCmode be handled?  */
+  if (type == NULL_TREE || mode == DImode || mode == DFmode)
+    return 0;
+
+  size = int_size_in_bytes (type);
+  return size == -1 || size > UNITS_PER_WORD;
+}
+
 #endif
 
 /* This function returns the register class required for a secondary
index 19abb47..8d2a614 100644 (file)
@@ -82,7 +82,8 @@ enum processor_type {
 enum mips_abi_type {
   ABI_32,
   ABI_N32,
-  ABI_64
+  ABI_64,
+  ABI_EABI
 };
 
 #ifndef MIPS_ABI_DEFAULT
@@ -166,6 +167,7 @@ extern void         final_prescan_insn ();
 extern struct rtx_def *        function_arg ();
 extern void            function_arg_advance ();
 extern int             function_arg_partial_nregs ();
+extern int             function_arg_pass_by_reference ();
 extern void            function_epilogue ();
 extern void            function_prologue ();
 extern void            gen_conditional_branch ();
@@ -803,6 +805,8 @@ while (0)
 %{mgp32:-U__mips64} %{mgp64:-D__mips64} \
 %{msingle-float:%{!msoft-float:-D__mips_single_float}} \
 %{m4650:%{!msoft-float:-D__mips_single_float}} \
+%{msoft-float:-D__mips_soft_float} \
+%{mabi=eabi:-D__mips_eabi} \
 %{EB:-UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__ -D_MIPSEB -D__MIPSEB -D__MIPSEB__ %{!ansi:-DMIPSEB}} \
 %{EL:-UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__ -D_MIPSEL -D__MIPSEL -D__MIPSEL__ %{!ansi:-DMIPSEL}} \
 %(subtarget_cpp_spec) "
@@ -1914,7 +1918,7 @@ extern struct mips_frame_info current_frame_info;
            && ((TO) == FRAME_POINTER_REGNUM                             \
                || (TO) == STACK_POINTER_REGNUM))                        \
     (OFFSET) = (current_frame_info.total_size                           \
-               - (mips_abi != ABI_32                                    \
+               - ((mips_abi != ABI_32 && mips_abi != ABI_EABI)          \
                   ? current_function_pretend_args_size                  \
                   : 0));                                                \
   else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM                      \
@@ -2112,6 +2116,8 @@ typedef struct mips_args {
   int gp_reg_found;            /* whether a gp register was found yet */
   int arg_number;              /* argument number */
   int arg_words;               /* # total words the arguments take */
+  int fp_arg_words;            /* # words for FP args (MIPS_EABI only) */
+  int last_arg_fp;             /* nonzero if last arg was FP (EABI only) */
   int num_adjusts;             /* number of adjustments made */
                                /* Adjustments made to args pass in regs.  */
                                /* ??? The size is doubled to work around a 
@@ -2507,7 +2513,7 @@ typedef struct mips_args {
           /* ??? Reject combining an address with a register for the MIPS  \
             64 bit ABI, because the SGI assembler can not handle this.  */ \
          if (!TARGET_DEBUG_A_MODE                                      \
-             && mips_abi == ABI_32                                     \
+             && (mips_abi == ABI_32 || mips_abi == ABI_EABI)           \
              && CONSTANT_ADDRESS_P (xplus1)                            \
              && ! mips_split_addresses                                 \
              && (!TARGET_EMBEDDED_PIC                                  \
@@ -2537,7 +2543,7 @@ typedef struct mips_args {
     || GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH               \
     || (GET_CODE (X) == CONST                                          \
        && ! (flag_pic && pic_address_needs_scratch (X))                \
-       && mips_abi == ABI_32))                                         \
+       && (mips_abi == ABI_32 || mips_abi == ABI_EABI)))               \
    && (!HALF_PIC_P () || !HALF_PIC_ADDRESS_P (X)))
 
 /* Define this, so that when PIC, reload won't try to reload invalid
@@ -2556,7 +2562,8 @@ typedef struct mips_args {
 #define LEGITIMATE_CONSTANT_P(X)                                       \
   ((GET_CODE (X) != CONST_DOUBLE                                       \
     || mips_const_double_ok (X, GET_MODE (X)))                         \
-   && ! (GET_CODE (X) == CONST && mips_abi != ABI_32))
+   && ! (GET_CODE (X) == CONST                                         \
+        && mips_abi != ABI_32 && mips_abi != ABI_EABI))
 
 /* A C compound statement that attempts to replace X with a valid
    memory address for an operand of mode MODE.  WIN will be a C
@@ -2618,7 +2625,7 @@ typedef struct mips_args {
   if (GET_CODE (xinsn) == CONST                                                \
       && ((flag_pic && pic_address_needs_scratch (xinsn))              \
          /* ??? SGI's Irix 6 assembler can't handle CONST.  */         \
-         || mips_abi != ABI_32))                                       \
+         || (mips_abi != ABI_32 && mips_abi != ABI_EABI)))             \
     {                                                                  \
       rtx ptr_reg = gen_reg_rtx (Pmode);                               \
       rtx constant = XEXP (XEXP (xinsn, 0), 1);                                \
index 7841f25..c8c84ee 100644 (file)
 
 #ifndef __GNUC_VA_LIST
 #define __GNUC_VA_LIST
+#if defined (__mips_eabi) && ! defined (__mips_soft_float)
+
+typedef struct {
+  /* Pointer to FP regs.  */
+  char *__fp_regs;
+  /* Number of FP regs remaining.  */
+  int __fp_left;
+  /* Pointer to GP regs followed by stack parameters.  */
+  char *__gp_regs;
+} __gnuc_va_list;
+
+#ifdef __mips64
+#define __va_reg_size 8
+#else
+#define __va_reg_size 4
+#endif
+
+enum {
+  __no_type_class = -1,
+  __void_type_class,
+  __integer_type_class,
+  __char_type_class,
+  __enumeral_type_class,
+  __boolean_type_class,
+  __pointer_type_class,
+  __reference_type_class,
+  __offset_type_class,
+  __real_type_class,
+  __complex_type_class,
+  __function_type_class,
+  __method_type_class,
+  __record_type_class,
+  __union_type_class,
+  __array_type_class,
+  __string_type_class,
+  __set_type_class,
+  __file_type_class,
+  __lang_type_class
+};
+
+#else /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
+
 typedef char * __gnuc_va_list;
+
+#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
 #endif /* not __GNUC_VA_LIST */
 
 /* If this is for internal libc use, don't define anything but
@@ -43,10 +87,19 @@ typedef char * __gnuc_va_list;
 #endif
 
 #ifdef _STDARG_H
+#if defined (__mips_eabi) && ! defined (__mips_soft_float)
+#define va_start(__AP, __LASTARG)                                      \
+  (__AP.__gp_regs = ((char *) __builtin_next_arg (__LASTARG)           \
+                    - (__builtin_args_info (2) < 8                     \
+                       ? (8 - __builtin_args_info (2)) * __va_reg_size \
+                       : 0)),                                          \
+   __AP.__fp_left = 8 - __builtin_args_info (3),                       \
+   __AP.__fp_regs = __AP.__gp_regs - __AP.__fp_left * __va_reg_size)
+#else /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
 #define va_start(__AP, __LASTARG) \
   (__AP = (__gnuc_va_list) __builtin_next_arg (__LASTARG))
-
-#else
+#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
+#else /* ! _STDARG_H */
 #define va_alist  __builtin_va_alist
 #ifdef __mips64
 /* This assumes that `long long int' is always a 64 bit type.  */
@@ -54,21 +107,68 @@ typedef char * __gnuc_va_list;
 #else
 #define va_dcl    int __builtin_va_alist; __va_ellipsis
 #endif
+#if defined (__mips_eabi) && ! defined (__mips_soft_float)
+#define va_start(__AP)                                                 \
+  (__AP.__gp_regs = ((char *) __builtin_next_arg ()                    \
+                    - (__builtin_args_info (2) < 8                     \
+                       ? (8 - __builtin_args_info (2)) * __va_reg_size \
+                       : 8)),                                          \
+   __AP.__fp_left = 8 - __builtin_args_info (3),                       \
+   __AP.__fp_regs = __AP.__gp_regs - __AP.__fp_left * __va_reg_size)
 /* Need alternate code for _MIPS_SIM_ABI64.  */
-#if defined(_MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32)
+#elif defined(_MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32)
 #define va_start(__AP)                                                 \
   (__AP = (__gnuc_va_list) __builtin_next_arg ()                       \
    + (__builtin_args_info (2) >= 8 ? -8 : 0))
 #else
 #define va_start(__AP)  __AP = (char *) &__builtin_va_alist
 #endif
-#endif
+#endif /* ! _STDARG_H */
 
 #ifndef va_end
 void va_end (__gnuc_va_list);          /* Defined in libgcc.a */
 #endif
 #define va_end(__AP)   ((void)0)
 
+#if defined (__mips_eabi) && ! defined (__mips_soft_float)
+
+#ifdef __mips64
+#define __va_next_addr(__AP, __type)                                   \
+  ((__builtin_classify_type (*(__type *) 0) == __real_type_class       \
+    && __AP.__fp_left > 0)                                             \
+   ? (--__AP.__fp_left, (__AP.__fp_regs += 8) - 8)                     \
+   : (__AP.__gp_regs += __va_reg_size) - __va_reg_size)
+#else
+#define __va_next_addr(__AP, __type)                                   \
+  ((__builtin_classify_type (*(__type *) 0) == __real_type_class       \
+    && __AP.__fp_left > 0)                                             \
+   ? (--__AP.__fp_left, (__AP.__fp_regs += 8) - 8)                     \
+   : (((__builtin_classify_type (* (__type *) 0) < record_type_class   \
+       && __alignof__ (__type) > 4)                                    \
+       ? __AP.__gp_regs = (__AP.__gp_regs + 8 - 1) & -8),              \
+      (__AP.__gp_regs += __va_reg_size) - __va_reg_size))
+#endif
+
+#ifdef __MIPSEB__
+#define va_arg(__AP, __type)                                           \
+  ((__va_rounded_size (__type) <= __va_reg_size)                       \
+   ? *(__type *) (void *) (__va_next_addr (__AP, __type)               \
+                          + __va_reg_size                              \
+                          - sizeof (__type))                           \
+   : (__builtin_classify_type (*(__type *) 0) >= __record_type_class   \
+      ? **(__type **) (void *) (__va_next_addr (__AP, __type)          \
+                               + __va_reg_size                         \
+                               - sizeof (char *))                      \
+      : *(__type *) (void *) __va_next_addr (__AP, __type)))
+#else
+#define va_arg(__AP, __type)                                           \
+  (__builtin_classify_type (* (__type *) 0) >= __record_type_class     \
+   ? **(__type **) (void *) __va_next_addr (__AP, __type)              \
+   : *(__type *) (void *) __va_next_addr (__AP, __type))
+#endif
+
+#else /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
+
 /* We cast to void * and then to TYPE * because this avoids
    a warning about increasing the alignment requirement.  */
 /* The __mips64 cases are reversed from the 32 bit cases, because the standard
@@ -106,5 +206,6 @@ void va_end (__gnuc_va_list);               /* Defined in libgcc.a */
                                         + __va_rounded_size(__type))))[-1]
 #endif
 #endif
+#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
 
 #endif /* defined (_STDARG_H) || defined (_VARARGS_H) */