alpha.c (alpha_gimplify_va_arg_1, [...]): New.
authorRichard Henderson <rth@redhat.com>
Wed, 9 Jun 2004 21:44:17 +0000 (14:44 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Wed, 9 Jun 2004 21:44:17 +0000 (14:44 -0700)
        * config/alpha/alpha.c (alpha_gimplify_va_arg_1,
        alpha_gimplify_va_arg, TARGET_GIMPLIFY_VA_ARG_EXPR): New.

From-SVN: r82858

gcc/ChangeLog
gcc/config/alpha/alpha.c

index 1d85f75ebbd388de25b95629f09f4b9621987759..07072a3cd53db49501275189321c19abf5c5153d 100644 (file)
@@ -1,3 +1,8 @@
+2004-06-09  Richard Henderson  <rth@redhat.com>
+
+       * config/alpha/alpha.c (alpha_gimplify_va_arg_1,
+       alpha_gimplify_va_arg, TARGET_GIMPLIFY_VA_ARG_EXPR): New.
+
 2004-06-09  Richard Henderson  <rth@redhat.com>
 
        * expmed.c (emit_store_flag): Cope with FLOAT_STORE_FLAG_VALUE.
index 1f78205771cdf121213ff3a2af295849526557e8..b8bf569a51242adad424499566ddc5aadbae91e6 100644 (file)
@@ -52,6 +52,7 @@ Boston, MA 02111-1307, USA.  */
 #include "langhooks.h"
 #include <splay-tree.h>
 #include "cfglayout.h"
+#include "tree-gimple.h"
 
 /* Specify which cpu to schedule for.  */
 
@@ -6398,6 +6399,139 @@ alpha_va_arg (tree valist, tree type)
 
   return addr;
 }
+
+static tree
+alpha_gimplify_va_arg_1 (tree type, tree base, tree offset,
+                        tree *pre_p, tree *post_p)
+{
+  tree type_size, rounded_size, ptr_type, addend, t, addr;
+  bool indirect;
+
+  if (type == error_mark_node
+      || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+      || TREE_OVERFLOW (type_size))
+    rounded_size = size_zero_node;
+  else
+    rounded_size = fold (build (MULT_EXPR, sizetype,
+                               fold (build (TRUNC_DIV_EXPR, sizetype,
+                                            fold (build (PLUS_EXPR, sizetype,
+                                                         type_size,
+                                                         size_int (7))),
+                                            size_int (8))),
+                               size_int (8)));
+
+  /* If the type could not be passed in registers, skip the block
+     reserved for the registers.  */
+  if (MUST_PASS_IN_STACK (TYPE_MODE (type), type))
+    {
+      t = fold_convert (TREE_TYPE (offset), build_int_2 (6*8, 0));
+      t = build (MODIFY_EXPR, TREE_TYPE (offset), offset,
+                build (MAX_EXPR, TREE_TYPE (offset), offset, t));
+      gimplify_and_add (t, pre_p);
+    }
+
+  addend = offset;
+  ptr_type = build_pointer_type (type);
+  indirect = false;
+
+  if (TYPE_MODE (type) == TFmode || TYPE_MODE (type) == TCmode)
+    {
+      type = ptr_type;
+      ptr_type = build_pointer_type (type);
+      indirect = true;
+      rounded_size = size_int (UNITS_PER_WORD);
+    }
+  else if (TREE_CODE (type) == COMPLEX_TYPE)
+    {
+      tree real_part, imag_part, real_temp;
+
+      real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, offset,
+                                          pre_p, post_p);
+      append_to_statement_list (*post_p, pre_p);
+      *post_p = NULL;
+
+      /* Copy the value into a temporary, lest the formal temporary
+        be reused out from under us.  */
+      real_temp = create_tmp_var (TREE_TYPE (real_part), NULL);
+      t = build (MODIFY_EXPR, void_type_node, real_temp, real_part);
+      gimplify_and_add (t, pre_p);
+
+      imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, offset,
+                                          pre_p, post_p);
+
+      return build (COMPLEX_EXPR, type, real_temp, imag_part);
+    }
+  else if (TREE_CODE (type) == REAL_TYPE)
+    {
+      tree fpaddend, cond, fourtyeight;
+
+      fourtyeight = fold_convert (TREE_TYPE (addend), build_int_2 (6*8, 0));
+      fpaddend = fold (build (MINUS_EXPR, TREE_TYPE (addend),
+                             addend, fourtyeight));
+      cond = fold (build (LT_EXPR, boolean_type_node, addend, fourtyeight));
+      addend = fold (build (COND_EXPR, TREE_TYPE (addend), cond,
+                           fpaddend, addend));
+    }
+
+  /* Build the final address and force that value into a temporary.  */
+  addr = build (PLUS_EXPR, ptr_type, fold_convert (ptr_type, base),
+               fold_convert (ptr_type, addend));
+  if (indirect)
+    addr = build (INDIRECT_REF, type, addr);
+  gimplify_expr (&addr, pre_p, post_p, is_gimple_val, fb_rvalue);
+  append_to_statement_list (*post_p, pre_p);
+  *post_p = NULL;
+
+  /* Update the offset field.  */
+  t = fold_convert (TREE_TYPE (offset), rounded_size);
+  t = build (MODIFY_EXPR, void_type_node, offset,
+            build (PLUS_EXPR, TREE_TYPE (offset), offset, t));
+  gimplify_and_add (t, pre_p);
+
+  return build_fold_indirect_ref (addr);
+}
+
+static void
+alpha_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+{
+  tree valist, type, offset_field, base_field, offset, base, t;
+
+  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
+    {
+      std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
+      return;
+    }
+
+  valist = TREE_OPERAND (*expr_p, 0);
+  type = TREE_TYPE (*expr_p);
+
+  base_field = TYPE_FIELDS (va_list_type_node);
+  offset_field = TREE_CHAIN (base_field);
+  base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
+                     valist, base_field);
+  offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
+                       valist, offset_field);
+
+  base = create_tmp_var (TREE_TYPE (base_field), NULL);
+  offset = create_tmp_var (lang_hooks.types.type_for_size (64, 0), NULL);
+
+  /* Pull the fields of the structure out into temporaries.  */
+  t = build (MODIFY_EXPR, void_type_node, base, base_field);
+  gimplify_and_add (t, pre_p);
+
+  t = build (MODIFY_EXPR, void_type_node, offset,
+            fold_convert (TREE_TYPE (offset), offset_field));
+  gimplify_and_add (t, pre_p);
+
+  /* Find the value.  Note that this will be a stable indirection, or
+     a composite of stable indirections in the case of complex.  */
+  *expr_p = alpha_gimplify_va_arg_1 (type, base, offset, pre_p, post_p);
+
+  /* Stuff the offset temporary back into its field.  */
+  t = build (MODIFY_EXPR, void_type_node, offset_field,
+            fold_convert (TREE_TYPE (offset_field), offset));
+  gimplify_and_add (t, pre_p);
+}
 \f
 /* Builtins.  */
 
@@ -10231,6 +10365,8 @@ alpha_init_libfuncs (void)
 #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
 #undef TARGET_SPLIT_COMPLEX_ARG
 #define TARGET_SPLIT_COMPLEX_ARG alpha_split_complex_arg
+#undef TARGET_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR alpha_gimplify_va_arg
 
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list