mips.c (mips_build_va_list): New.
authorRichard Henderson <rth@gcc.gnu.org>
Tue, 14 Sep 1999 23:29:31 +0000 (16:29 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Tue, 14 Sep 1999 23:29:31 +0000 (16:29 -0700)
        * mips.c (mips_build_va_list): New.
        (mips_va_start, mips_va_arg): New.
        * mips.h (BUILD_VA_LIST_TYPE): New.
        (EXPAND_BUILTIN_VA_START, EXPAND_BUILTIN_VA_ARG): New.

From-SVN: r29414

gcc/config/mips/mips.c
gcc/config/mips/mips.h

index a192be0..2914220 100644 (file)
@@ -3990,6 +3990,271 @@ function_arg_partial_nregs (cum, mode, type, named)
   return 0;
 }
 \f
+/* Create the va_list data type.  */
+
+tree
+mips_build_va_list ()
+{
+  if (mips_abi == ABI_EABI && !TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+    {
+      tree f_fpr, f_rem, f_gpr, record;
+
+      record = make_node (RECORD_TYPE);
+
+      f_fpr = build_decl (FIELD_DECL, get_identifier ("__fp_regs"),
+                         ptr_type_node);
+      f_rem = build_decl (FIELD_DECL, get_identifier ("__fp_left"),
+                         integer_type_node);
+      f_gpr = build_decl (FIELD_DECL, get_identifier ("__gp_regs"),
+                         ptr_type_node);
+
+      DECL_FIELD_CONTEXT (f_fpr) = record;
+      DECL_FIELD_CONTEXT (f_rem) = record;
+      DECL_FIELD_CONTEXT (f_gpr) = record;
+
+      TYPE_FIELDS (record) = f_fpr;
+      TREE_CHAIN (f_fpr) = f_rem;
+      TREE_CHAIN (f_gpr) = f_gpr;
+
+      layout_type (record);
+
+      return record;
+    }
+  else
+    return ptr_type_node;
+}
+
+/* Implement va_start.  */
+
+void
+mips_va_start (stdarg_p, valist, nextarg)
+     int stdarg_p;
+     tree valist;
+     rtx nextarg;
+{
+  int arg_words, fp_arg_words;
+  tree t, u;
+
+  arg_words = current_function_args_info.arg_words;
+  fp_arg_words = current_function_args_info.fp_arg_words;
+
+  if (mips_abi == ABI_EABI)
+    {
+      if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+       {
+         tree f_fpr, f_rem, f_gpr, fpr, rem, gpr;
+         tree gprv, fprv;
+         int gpro, fpro;
+
+         f_fpr = TYPE_FIELDS (va_list_type_node);
+         f_rem = TREE_CHAIN (f_fpr);
+         f_gpr = TREE_CHAIN (f_gpr);
+
+         fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+         rem = build (COMPONENT_REF, TREE_TYPE (f_rem), valist, f_rem);
+         gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+
+         if (arg_words < 8)
+           gpro = (8 - arg_words) * UNITS_PER_WORD;
+         else
+           gpro = (stdarg_p ? 0 : UNITS_PER_WORD);
+
+         gprv = make_tree (ptr_type_node, nextarg);
+         if (gpro != 0)
+           {
+             gprv = build (PLUS_EXPR, ptr_type_node, gprv,
+                           build_int_2 (-gpro, -1));
+           }
+
+         t = build (MODIFY_EXPR, ptr_type_node, gpr, gprv);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+         t = build (MODIFY_EXPR, integer_type_node, rem,
+                    build_int_2 (8 - fp_arg_words, 0));
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+         fpro = (8 - fp_arg_words) * 8;
+         if (fpro == 0)
+           fprv = gprv;
+         else
+           fprv = fold (build (PLUS_EXPR, ptr_type_node, gprv,
+                               build_int_2 (-fpro, -1)));
+
+         if (! TARGET_64BIT)
+           fprv = fold (build (BIT_AND_EXPR, ptr_type_node, fprv,
+                               build_int_2 (-8, -1)));
+
+         t = build (MODIFY_EXPR, ptr_type_node, fpr, fprv);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       }
+      else
+       {
+         int ofs;
+
+         if (arg_words >= 8)
+           ofs = (stdarg_p ? 0 : UNITS_PER_WORD);
+         else
+           ofs = (8 - arg_words) * UNITS_PER_WORD;
+
+         nextarg = plus_constant (nextarg, -ofs);
+         std_expand_builtin_va_start (1, valist, nextarg);
+       }
+    }
+  else
+    {
+      int ofs;
+
+      if (stdarg_p)
+       ofs = 0;
+      else
+       {
+         /* ??? This had been conditional on
+              _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
+            and both iris5.h and iris6.h define _MIPS_SIM.  */
+         if (mips_abi == ABI_N32 || mips_abi == ABI_64)
+           ofs = (arg_words >= 8 ? -UNITS_PER_WORD : 0);
+         else
+           ofs = -UNITS_PER_WORD;
+       }
+
+      nextarg = plus_constant (nextarg, ofs);
+      std_expand_builtin_va_start (1, valist, nextarg);
+    }
+}
+
+/* Implement va_arg.  */
+
+rtx
+mips_va_arg (valist, type)
+     tree valist, type;
+{
+  HOST_WIDE_INT size, rsize;
+  rtx addr_rtx;
+  tree t;
+
+  size = int_size_in_bytes (type);
+  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+
+  if (mips_abi == ABI_EABI)
+    {
+      tree gpr;
+      int indirect;
+      rtx lab_over = NULL_RTX, lab_false, r;
+
+      indirect
+       = function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
+      if (indirect)
+       size = rsize = POINTER_SIZE / BITS_PER_UNIT;
+
+      addr_rtx = gen_reg_rtx (Pmode);
+
+      if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+       {
+         tree f_fpr, f_rem, f_gpr, fpr, rem;
+
+         f_fpr = TYPE_FIELDS (va_list_type_node);
+         f_rem = TREE_CHAIN (f_fpr);
+         f_gpr = TREE_CHAIN (f_gpr);
+
+         fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+         rem = build (COMPONENT_REF, TREE_TYPE (f_rem), valist, f_rem);
+         gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+
+         if (TREE_CODE (type) == REAL_TYPE)
+           {
+             lab_false = gen_label_rtx ();
+             lab_over = gen_label_rtx ();
+
+             r = expand_expr (rem, NULL_RTX, TYPE_MODE (TREE_TYPE (rem)),
+                              EXPAND_NORMAL);
+             emit_cmp_and_jump_insns (r, const0_rtx, LE, const1_rtx,
+                                      GET_MODE (r), 1, 1, lab_false);
+
+             t = build (PLUS_EXPR, TREE_TYPE (rem), rem,
+                        build_int_2 (-1, -1));
+             t = build (MODIFY_EXPR, TREE_TYPE (rem), rem, t);
+             TREE_SIDE_EFFECTS (t) = 1;
+             expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+             t = build (POSTINCREMENT_EXPR, TREE_TYPE (fpr), fpr,
+                        build_int_2 (8, 0));
+             TREE_SIDE_EFFECTS (t) = 1;
+             r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+             if (r != addr_rtx)
+               emit_move_insn (addr_rtx, r);
+
+             emit_jump (gen_jump (lab_over));
+             emit_barrier ();
+             emit_label (lab_false);
+           }
+       }
+      else
+       gpr = valist;
+
+      if (! indirect
+         && ! TARGET_64BIT
+         && TYPE_ALIGN (type) > BITS_PER_WORD)
+       {
+         t = build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
+                    build_int_2 (2*UNITS_PER_WORD - 1, 0));
+         t = build (BIT_AND_EXPR, TREE_TYPE (t), t, 
+                    build_int_2 (-2*UNITS_PER_WORD, -1));
+         t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       }
+
+      t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr, rsize);
+      TREE_SIDE_EFFECTS (t) = 1;
+      r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+      if (r != addr_rtx)
+       emit_move_insn (addr_rtx, r);
+
+      if (lab_over)
+       emit_label (lab_over);
+
+      if (indirect)
+       {
+         r = gen_rtx_MEM (Pmode, addr_rtx);
+         MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+         emit_move_insn (addr_rtx, r);
+       }
+      else
+       {
+         if (BYTES_BIG_ENDIAN && rsize != size)
+           addr_rtx = plus_constant (addr_rtx, rsize - size);
+       }
+    }
+  else
+    {
+      int align;
+
+      /* ??? The original va-mips.h did always align, despite the fact 
+        that alignments <= UNITS_PER_WORD are preserved by the va_arg
+        increment mechanism.  */
+
+      if (TARGET_64BIT)
+       align = 8;
+      else if (TYPE_ALIGN (type) > 32)
+       align = 8;
+      else
+       align = 4;
+       
+      t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
+                build_int_2 (align - 1, 0));
+      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
+      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      /* Everything past the alignment is standard.  */
+      return std_expand_builtin_va_arg (valist, type);
+    }
+}
+\f
 /* Abort after printing out a specific insn.  */
 
 static void
index bd6f1ee..59476db 100644 (file)
@@ -2612,6 +2612,22 @@ typedef struct mips_args {
 #endif
 
 \f
+/* Define the `__builtin_va_list' type for the ABI.  */
+#define BUILD_VA_LIST_TYPE(VALIST) \
+  (VALIST) = mips_build_va_list ()
+
+/* Implement `va_start' for varargs and stdarg.  */
+#define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \
+  mips_va_start (stdarg, valist, nextarg)
+
+/* Implement `va_arg'.  */
+#define EXPAND_BUILTIN_VA_ARG(valist, type) \
+  mips_va_arg (valist, type)
+
+extern union tree_node *mips_build_va_list ();
+extern void mips_va_start ();
+extern struct rtx_def *mips_va_arg ();
+\f
 /* Output assembler code to FILE to increment profiler label # LABELNO
    for profiling a function entry.  */