sparc.c (sparc_gimplify_va_arg): New fn.
authorJason Merrill <jason@redhat.com>
Fri, 11 Jun 2004 06:08:09 +0000 (02:08 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 11 Jun 2004 06:08:09 +0000 (02:08 -0400)
        * config/sparc/sparc.c (sparc_gimplify_va_arg): New fn.
        (TARGET_GIMPLIFY_VA_ARG_EXPR): Define.

From-SVN: r82963

gcc/ChangeLog
gcc/config/sparc/sparc.c

index f9b6182eccd255a0dcc31075319e7a46e3eb2e49..00d09a0ba1eb0993f5fb237d77ef59b04e661237 100644 (file)
@@ -1,3 +1,8 @@
+2004-06-11  Jason Merrill  <jason@redhat.com>
+
+       * config/sparc/sparc.c (sparc_gimplify_va_arg): New fn.
+       (TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
+
 2004-06-11  Jerry Quinn  <jlquinn@optonline.net>
 
        * typeclass.h: Add GPL plus exception license.  Add include
index 0d19727145688a1f00846ef28d6b59ebeb5e4f2f..5be84c886e057b1a0ee8ee2755f1ea4aefdb559d 100644 (file)
@@ -47,6 +47,7 @@ Boston, MA 02111-1307, USA.  */
 #include "target.h"
 #include "target-def.h"
 #include "cfglayout.h"
+#include "tree-gimple.h"
 
 /* Global variables for machine-dependent things.  */
 
@@ -181,6 +182,7 @@ static bool sparc_promote_prototypes (tree);
 static rtx sparc_struct_value_rtx (tree, int);
 static bool sparc_return_in_memory (tree, tree);
 static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
+static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
 \f
 /* Option handling.  */
 
@@ -289,6 +291,9 @@ enum processor_type sparc_cpu;
 #undef TARGET_STRICT_ARGUMENT_NAMING
 #define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
 
+#undef TARGET_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Validate and override various options, and do some machine dependent
@@ -6041,6 +6046,96 @@ sparc_va_arg (tree valist, tree type)
 
   return addr_rtx;
 }
+
+tree
+sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
+{
+  HOST_WIDE_INT size, rsize, align;
+  tree addr, incr;
+  bool indirect;
+  tree ptrtype = build_pointer_type (type);
+
+  if (function_arg_pass_by_reference (0, TYPE_MODE (type), type, 0))
+    {
+      indirect = true;
+      size = rsize = UNITS_PER_WORD;
+      align = 0;
+    }
+  else
+    {
+      indirect = false;
+      size = int_size_in_bytes (type);
+      rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+      align = 0;
+    
+      if (TARGET_ARCH64)
+       {
+         /* For SPARC64, objects requiring 16-byte alignment get it.  */
+         if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
+           align = 2 * UNITS_PER_WORD;
+
+         /* SPARC-V9 ABI states that structures up to 16 bytes in size
+            are given whole slots as needed.  */
+         if (AGGREGATE_TYPE_P (type))
+           {
+             if (size == 0)
+               size = rsize = UNITS_PER_WORD;
+             else
+               size = rsize;
+           }
+       }
+    }
+
+  incr = valist;
+  if (align)
+    {
+      incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+                          ssize_int (align - 1)));
+      incr = fold (build2 (BIT_AND_EXPR, ptr_type_node, incr,
+                          ssize_int (-align)));
+    }
+
+  gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue);
+  addr = incr;
+
+  if (BYTES_BIG_ENDIAN && size < rsize)
+    addr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+                        ssize_int (rsize - size)));
+
+  if (indirect)
+    {
+      addr = fold_convert (build_pointer_type (ptrtype), addr);
+      addr = build_fold_indirect_ref (addr);
+    }
+  /* If the address isn't aligned properly for the type,
+     we may need to copy to a temporary.  
+     FIXME: This is inefficient.  Usually we can do this
+     in registers.  */
+  else if (align == 0
+          && TYPE_ALIGN (type) > BITS_PER_WORD)
+    {
+      tree tmp = create_tmp_var (type, "va_arg_tmp");
+      tree dest_addr = build_fold_addr_expr (tmp);
+
+      tree copy = build_function_call_expr
+       (implicit_built_in_decls[BUILT_IN_MEMCPY],
+        tree_cons (NULL_TREE, dest_addr,
+                   tree_cons (NULL_TREE, addr,
+                              tree_cons (NULL_TREE, size_int (rsize),
+                                         NULL_TREE))));
+
+      gimplify_and_add (copy, pre_p);
+      addr = dest_addr;
+    }
+  else
+    addr = fold_convert (ptrtype, addr);
+
+  incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, ssize_int (rsize)));
+  incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
+  gimplify_and_add (incr, post_p);
+
+  return build_fold_indirect_ref (addr);
+}
 \f
 /* Return the string to output a conditional branch to LABEL, which is
    the operand number of the label.  OP is the conditional expression.