OSDN Git Service

2008-07-04 Kai Tietz <kai.tietz@onevision.com>
authorktietz <ktietz@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 Jul 2008 08:15:27 +0000 (08:15 +0000)
committerktietz <ktietz@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 Jul 2008 08:15:27 +0000 (08:15 +0000)
* config.gcc (extra_headers): Add cross-stdarg.h for target
x86_64-*-* and i?86-*-*.
* config/i386/cross-stdarg.h: New.
* builtins.c (std_fn_abi_va_list): New.
(std_canonical_va_list_type): New.
(stabilize_va_list): Replace va_list_type_node use by
mtarget.canonical_va_list_type.
(gimplify_va_arg_expr): Likewise.
(expand_builtin_va_copy): Replace va_list_type_node use by
mtarget.fn_abi_va_list.
* tree-sra.c (is_va_list_type): New helper.
(decl_can_be_decomposed_p): Replace
va_list_type_node use by is_va_list_type.
* tree-ssa-ccp.c (optimize_stdarg_builtin): Likewise.
* tree-stdarg.c (execute_optimize_stdarg): Likewise.
* c-common.c (c_common_nodes_and_builtins): Use TARGET_ENUM_VA_LIST.
* config/i386/i386-protos.h (ix86_get_valist_type): New.
(ix86_enum_va_list): New.
* config/i386/i386.c (sysv_va_list_type_node): New.
(ms_va_list_type_node): New.
(ix86_function_type_abi): Remove sorry.
(ix86_build_builtin_va_list_abi): New.
(ix86_build_builtin_va_list): Call ix86_build_builtin_va_list_abi
for 64-bit targets.
(ix86_va_start): Replace va_list_type_node by sysv_va_list_type_node.
(ix86_init_builtins_va_builtins_abi): New.
(ix86_init_builtins): Use ix86_init_builtins_va_builtins_abi
for 64-bit targets.
(ix86_handle_abi_attribute): New.
(attribute_spec): Add sysv_abi and ms_abi.
(ix86_fn_abi_va_list): New.
(ix86_canonical_va_list_type): New.
(ix86_enum_va_list): New.
(TARGET_FN_ABI_VA_LIST): New.
(TARGET_CANONICAL_VA_LIST_TYPE): New.
* config/i386/i386.h (TARGET_ENUM_VA_LIST): New.
* doc/tm.texi (TARGET_FN_ABI_VA_LIST): New.
(TARGET_CANONICAL_VA_LIST_TYPE): New.
(TARGET_ENUM_VA_LIST): New.
* expr.h (std_fn_abi_va_list): New.
(std_canonical_va_list_type): New.
* target-def.h (TARGET_FN_ABI_VA_LIST): New.
(TARGET_CANONICAL_VA_LIST_TYPE): New.
(TARGET_INITIALIZER): Add TARGET_FN_ABI_VA_LIST and
TARGET_CANONICAL_VA_LIST_TYPE.
* target.h (struct gcc_target): Add fn_abi_va_list hook
and canonical_va_list_type hook.

2008-07-04  Kai Tietz  <kai.tietz@onevision.com>

* gcc.dg/callabi/callabi.h: New.
* gcc.dg/callabi/vaarg-1.c: New.
* gcc.dg/callabi/vaarg-2.c: New.
* gcc.dg/callabi/vaarg-3.c: New.
* gcc.dg/callabi/func-1.c: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@137452 138bc75d-0d04-0410-961f-82ee72b054a4

21 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/c-common.c
gcc/config.gcc
gcc/config/i386/cross-stdarg.h [new file with mode: 0644]
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/doc/tm.texi
gcc/expr.h
gcc/target-def.h
gcc/target.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/callabi/callabi.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/callabi/func-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/callabi/vaarg-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/callabi/vaarg-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/callabi/vaarg-3.c [new file with mode: 0644]
gcc/tree-sra.c
gcc/tree-ssa-ccp.c
gcc/tree-stdarg.c

index 700367a..a3c6b76 100644 (file)
@@ -1,3 +1,53 @@
+2008-07-04  Kai Tietz  <kai.tietz@onevision.com>
+
+       * config.gcc (extra_headers): Add cross-stdarg.h for target
+       x86_64-*-* and i?86-*-*.
+       * config/i386/cross-stdarg.h: New.
+       * builtins.c (std_fn_abi_va_list): New.
+       (std_canonical_va_list_type): New.
+       (stabilize_va_list): Replace va_list_type_node use by
+       mtarget.canonical_va_list_type.
+       (gimplify_va_arg_expr): Likewise.
+       (expand_builtin_va_copy): Replace va_list_type_node use by
+       mtarget.fn_abi_va_list.
+       * tree-sra.c (is_va_list_type): New helper.
+       (decl_can_be_decomposed_p): Replace
+       va_list_type_node use by is_va_list_type.
+       * tree-ssa-ccp.c (optimize_stdarg_builtin): Likewise.
+       * tree-stdarg.c (execute_optimize_stdarg): Likewise.
+       * c-common.c (c_common_nodes_and_builtins): Use TARGET_ENUM_VA_LIST.
+       * config/i386/i386-protos.h (ix86_get_valist_type): New.
+       (ix86_enum_va_list): New.
+       * config/i386/i386.c (sysv_va_list_type_node): New.
+       (ms_va_list_type_node): New.
+       (ix86_function_type_abi): Remove sorry.
+       (ix86_build_builtin_va_list_abi): New.
+       (ix86_build_builtin_va_list): Call ix86_build_builtin_va_list_abi
+       for 64-bit targets.
+       (ix86_va_start): Replace va_list_type_node by sysv_va_list_type_node.
+       (ix86_init_builtins_va_builtins_abi): New.
+       (ix86_init_builtins): Use ix86_init_builtins_va_builtins_abi
+       for 64-bit targets.
+       (ix86_handle_abi_attribute): New.
+       (attribute_spec): Add sysv_abi and ms_abi.
+       (ix86_fn_abi_va_list): New.
+       (ix86_canonical_va_list_type): New.
+       (ix86_enum_va_list): New.
+       (TARGET_FN_ABI_VA_LIST): New.
+       (TARGET_CANONICAL_VA_LIST_TYPE): New.
+       * config/i386/i386.h (TARGET_ENUM_VA_LIST): New.
+       * doc/tm.texi (TARGET_FN_ABI_VA_LIST): New.
+       (TARGET_CANONICAL_VA_LIST_TYPE): New.
+       (TARGET_ENUM_VA_LIST): New.
+       * expr.h (std_fn_abi_va_list): New.
+       (std_canonical_va_list_type): New.
+       * target-def.h (TARGET_FN_ABI_VA_LIST): New.
+       (TARGET_CANONICAL_VA_LIST_TYPE): New.
+       (TARGET_INITIALIZER): Add TARGET_FN_ABI_VA_LIST and
+       TARGET_CANONICAL_VA_LIST_TYPE.
+       * target.h (struct gcc_target): Add fn_abi_va_list hook
+       and canonical_va_list_type hook.
+
 2008-07-04  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * ggc-zone.c (lookup_page_table_if_allocated,
index 731955b..30bcdf8 100644 (file)
@@ -4623,18 +4623,19 @@ expand_builtin_next_arg (void)
 static tree
 stabilize_va_list (tree valist, int needs_lvalue)
 {
-  if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+  tree vatype = targetm.canonical_va_list_type (TREE_TYPE (valist));
+  if (vatype !=NULL && TREE_CODE (vatype) == ARRAY_TYPE)
     {
       if (TREE_SIDE_EFFECTS (valist))
        valist = save_expr (valist);
 
       /* For this case, the backends will be expecting a pointer to
-        TREE_TYPE (va_list_type_node), but it's possible we've
-        actually been given an array (an actual va_list_type_node).
+        vatype, but it's possible we've actually been given an array
+        (an actual TARGET_CANONICAL_VA_LIST_TYPE (valist)).
         So fix it.  */
       if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
        {
-         tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+         tree p1 = build_pointer_type (TREE_TYPE (vatype));
          valist = build_fold_addr_expr_with_type (valist, p1);
        }
     }
@@ -4647,7 +4648,7 @@ stabilize_va_list (tree valist, int needs_lvalue)
          if (! TREE_SIDE_EFFECTS (valist))
            return valist;
 
-         pt = build_pointer_type (va_list_type_node);
+         pt = build_pointer_type (vatype);
          valist = fold_build1 (ADDR_EXPR, pt, valist);
          TREE_SIDE_EFFECTS (valist) = 1;
        }
@@ -4668,6 +4669,42 @@ std_build_builtin_va_list (void)
   return ptr_type_node;
 }
 
+/* The "standard" abi va_list is va_list_type_node.  */
+
+tree
+std_fn_abi_va_list (tree fndecl ATTRIBUTE_UNUSED)
+{
+  return va_list_type_node;
+}
+
+/* The "standard" type of va_list is va_list_type_node.  */
+
+tree
+std_canonical_va_list_type (tree type)
+{
+  tree wtype, htype;
+
+  wtype = va_list_type_node;
+  htype = type;
+  if (TREE_CODE (wtype) == ARRAY_TYPE)
+    {
+      /* If va_list is an array type, the argument may have decayed
+        to a pointer type, e.g. by being passed to another function.
+        In that case, unwrap both types so that we can compare the
+        underlying records.  */
+      if (TREE_CODE (htype) == ARRAY_TYPE
+         || POINTER_TYPE_P (htype))
+       {
+         wtype = TREE_TYPE (wtype);
+         htype = TREE_TYPE (htype);
+       }
+    }
+  if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+    return va_list_type_node;
+
+  return NULL_TREE;
+}
+
 /* The "standard" implementation of va_start: just assign `nextarg' to
    the variable.  */
 
@@ -4823,33 +4860,18 @@ dummy_object (tree type)
 enum gimplify_status
 gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
 {
-  tree promoted_type, want_va_type, have_va_type;
+  tree promoted_type, have_va_type;
   tree valist = TREE_OPERAND (*expr_p, 0);
   tree type = TREE_TYPE (*expr_p);
   tree t;
 
   /* Verify that valist is of the proper type.  */
-  want_va_type = va_list_type_node;
   have_va_type = TREE_TYPE (valist);
-
   if (have_va_type == error_mark_node)
     return GS_ERROR;
+  have_va_type = targetm.canonical_va_list_type (have_va_type);
 
-  if (TREE_CODE (want_va_type) == ARRAY_TYPE)
-    {
-      /* If va_list is an array type, the argument may have decayed
-        to a pointer type, e.g. by being passed to another function.
-        In that case, unwrap both types so that we can compare the
-        underlying records.  */
-      if (TREE_CODE (have_va_type) == ARRAY_TYPE
-         || POINTER_TYPE_P (have_va_type))
-       {
-         want_va_type = TREE_TYPE (want_va_type);
-         have_va_type = TREE_TYPE (have_va_type);
-       }
-    }
-
-  if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
+  if (have_va_type == NULL_TREE)
     {
       error ("first argument to %<va_arg%> not of type %<va_list%>");
       return GS_ERROR;
@@ -4857,7 +4879,7 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
 
   /* Generate a diagnostic for requesting data of a type that cannot
      be passed through `...' due to type promotion at the call site.  */
-  else if ((promoted_type = lang_hooks.types.type_promotes_to (type))
+  if ((promoted_type = lang_hooks.types.type_promotes_to (type))
           != type)
     {
       static bool gave_help;
@@ -4889,15 +4911,15 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
     {
       /* Make it easier for the backends by protecting the valist argument
         from multiple evaluations.  */
-      if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+      if (TREE_CODE (have_va_type) == ARRAY_TYPE)
        {
          /* For this case, the backends will be expecting a pointer to
-            TREE_TYPE (va_list_type_node), but it's possible we've
-            actually been given an array (an actual va_list_type_node).
+            TREE_TYPE (abi), but it's possible we've
+            actually been given an array (an actual TARGET_FN_ABI_VA_LIST).
             So fix it.  */
          if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
            {
-             tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+             tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
              valist = build_fold_addr_expr_with_type (valist, p1);
            }
          gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
@@ -4945,9 +4967,11 @@ expand_builtin_va_copy (tree exp)
   dst = stabilize_va_list (dst, 1);
   src = stabilize_va_list (src, 0);
 
-  if (TREE_CODE (va_list_type_node) != ARRAY_TYPE)
+  gcc_assert (cfun != NULL && cfun->decl != NULL_TREE);
+
+  if (TREE_CODE (targetm.fn_abi_va_list (cfun->decl)) != ARRAY_TYPE)
     {
-      t = build2 (MODIFY_EXPR, va_list_type_node, dst, src);
+      t = build2 (MODIFY_EXPR, targetm.fn_abi_va_list (cfun->decl), dst, src);
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
@@ -4958,8 +4982,8 @@ expand_builtin_va_copy (tree exp)
       /* Evaluate to pointers.  */
       dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
       srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
-      size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX,
-                         VOIDmode, EXPAND_NORMAL);
+      size = expand_expr (TYPE_SIZE_UNIT (targetm.fn_abi_va_list (cfun->decl)),
+                 NULL_RTX, VOIDmode, EXPAND_NORMAL);
 
       dstb = convert_memory_address (Pmode, dstb);
       srcb = convert_memory_address (Pmode, srcb);
@@ -4967,10 +4991,10 @@ expand_builtin_va_copy (tree exp)
       /* "Dereference" to BLKmode memories.  */
       dstb = gen_rtx_MEM (BLKmode, dstb);
       set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
-      set_mem_align (dstb, TYPE_ALIGN (va_list_type_node));
+      set_mem_align (dstb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl)));
       srcb = gen_rtx_MEM (BLKmode, srcb);
       set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
-      set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
+      set_mem_align (srcb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl)));
 
       /* Copy.  */
       emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
index 3a63384..2224a21 100644 (file)
@@ -4002,6 +4002,20 @@ c_common_nodes_and_builtins (void)
   lang_hooks.decls.pushdecl
     (build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
                 va_list_type_node));
+#ifdef TARGET_ENUM_VA_LIST
+  {
+    int l;
+    const char *pname;
+    tree ptype;
+    for (l = 0; TARGET_ENUM_VA_LIST (l, &pname, &ptype); ++l)
+      {
+       lang_hooks.decls.pushdecl
+         (build_decl (TYPE_DECL, get_identifier (pname),
+                      ptype));
+
+      }
+  }
+#endif
 
   if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
     {
index b29a762..eda2812 100644 (file)
@@ -281,14 +281,14 @@ i[34567]86-*-*)
        extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h
                       pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h
                       nmmintrin.h bmmintrin.h mmintrin-common.h
-                      wmmintrin.h"
+                      wmmintrin.h cross-stdarg.h"
        ;;
 x86_64-*-*)
        cpu_type=i386
        extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h
                       pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h
                       nmmintrin.h bmmintrin.h mmintrin-common.h
-                      wmmintrin.h"
+                      wmmintrin.h cross-stdarg.h"
        need_64bit_hwint=yes
        ;;
 ia64-*-*)
diff --git a/gcc/config/i386/cross-stdarg.h b/gcc/config/i386/cross-stdarg.h
new file mode 100644 (file)
index 0000000..98ac1ec
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
+
+   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, 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, if you include this header file into source
+   files compiled by GCC, this header file does not by itself cause
+   the resulting executable to be covered by the GNU General Public
+   License.  This exception does not however invalidate any other
+   reasons why the executable file might be covered by the GNU General
+   Public License.  */
+
+#ifndef __CROSS_STDARG_H_INCLUDED
+#define __CROSS_STDARG_H_INCLUDED
+
+/* Make sure that for non x64 targets cross builtins are defined.  */
+#ifndef __x86_64__
+/* Call abi ms_abi.  */
+#define __builtin_ms_va_list __builtin_va_list
+#define __builtin_ms_va_copy __builtin_va_copy
+#define __builtin_ms_va_start __builtin_va_start
+#define __builtin_ms_va_end __builtin_va_end
+
+/* Call abi sysv_abi.  */
+#define __builtin_sysv_va_list __builtin_va_list
+#define __builtin_sysv_va_copy __builtin_va_copy
+#define __builtin_sysv_va_start __builtin_va_start
+#define __builtin_sysv_va_end __builtin_va_end
+#endif
+
+#define __ms_va_copy(__d,__s) __builtin_ms_va_copy(__d,__s)
+#define __ms_va_start(__v,__l) __builtin_ms_va_start(__v,__l)
+#define __ms_va_arg(__v,__l)   __builtin_va_arg(__v,__l)
+#define __ms_va_end(__v) __builtin_ms_va_end(__v)
+
+#define __sysv_va_copy(__d,__s) __builtin_sysv_va_copy(__d,__s)
+#define __sysv_va_start(__v,__l) __builtin_sysv_va_start(__v,__l)
+#define __sysv_va_arg(__v,__l) __builtin_va_arg(__v,__l)
+#define __sysv_va_end(__v) __builtin_sysv_va_end(__v)
+
+#ifndef __GNUC_SYSV_VA_LIST
+#define __GNUC_SYSV_VA_LIST
+  typedef __builtin_sysv_va_list __gnuc_sysv_va_list;
+#endif
+
+#ifndef _SYSV_VA_LIST_DEFINED
+#define _SYSV_VA_LIST_DEFINED
+  typedef __gnuc_sysv_va_list sysv_va_list;
+#endif
+
+#ifndef __GNUC_MS_VA_LIST
+#define __GNUC_MS_VA_LIST
+  typedef __builtin_ms_va_list __gnuc_ms_va_list;
+#endif
+
+#ifndef _MS_VA_LIST_DEFINED
+#define _MS_VA_LIST_DEFINED
+  typedef __gnuc_ms_va_list ms_va_list;
+#endif
+
+#endif /* __CROSS_STDARG_H_INCLUDED */
index 8d0772d..9719ec2 100644 (file)
@@ -141,6 +141,9 @@ extern int ix86_cfun_abi (void);
 extern int ix86_function_abi (const_tree);
 extern int ix86_function_type_abi (const_tree);
 extern void ix86_call_abi_override (const_tree);
+extern tree ix86_fn_abi_va_list (tree);
+extern tree ix86_canonical_va_list_type (tree);
+extern int ix86_enum_va_list (int, const char **, tree *);
 extern int ix86_reg_parm_stack_space (const_tree);
 
 extern void ix86_split_fp_branch (enum rtx_code code, rtx, rtx,
index a0edaca..ec627e8 100644 (file)
@@ -1716,6 +1716,10 @@ unsigned int ix86_preferred_stack_boundary;
 /* Values 1-5: see jump.c */
 int ix86_branch_cost;
 
+/* Calling abi specific va_list type nodes.  */
+static GTY(()) tree sysv_va_list_type_node;
+static GTY(()) tree ms_va_list_type_node;
+
 /* Variables which are this size or smaller are put in the data/bss
    or ldata/lbss sections.  */
 
@@ -2774,9 +2778,8 @@ override_options (void)
     set_param_value ("l2-cache-size", ix86_cost->l2_cache_size);
 
   /* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0)
-     can be optimized to ap = __builtin_next_arg (0).
-     For abi switching it should be corrected.  */
-  if (!TARGET_64BIT || DEFAULT_ABI == MS_ABI)
+     can be optimized to ap = __builtin_next_arg (0).  */
+  if (!TARGET_64BIT)
     targetm.expand_builtin_va_start = NULL;
 
   if (TARGET_64BIT)
@@ -3604,9 +3607,6 @@ ix86_function_type_abi (const_tree fntype)
       else
         abi = lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)) ? SYSV_ABI : MS_ABI;
 
-      if (DEFAULT_ABI == MS_ABI && abi == SYSV_ABI)
-        sorry ("using sysv calling convention on target w64 is not supported");
-
       return abi;
     }
   return DEFAULT_ABI;
@@ -5174,13 +5174,16 @@ ix86_struct_value_rtx (tree type, int incoming ATTRIBUTE_UNUSED)
 \f
 /* Create the va_list data type.  */
 
+/* Returns the calling convention specific va_list date type.
+   The argument ABI can be DEFAULT_ABI, MS_ABI, or SYSV_ABI.  */
+
 static tree
-ix86_build_builtin_va_list (void)
+ix86_build_builtin_va_list_abi (enum calling_abi abi)
 {
   tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
 
   /* For i386 we use plain pointer to argument area.  */
-  if (!TARGET_64BIT || ix86_cfun_abi () == MS_ABI)
+  if (!TARGET_64BIT || abi == MS_ABI)
     return build_pointer_type (char_type_node);
 
   record = (*lang_hooks.types.make_type) (RECORD_TYPE);
@@ -5216,6 +5219,33 @@ ix86_build_builtin_va_list (void)
   return build_array_type (record, build_index_type (size_zero_node));
 }
 
+/* Setup the builtin va_list data type and for 64-bit the additional
+   calling convention specific va_list data types.  */
+
+static tree
+ix86_build_builtin_va_list (void)
+{
+  tree ret = ix86_build_builtin_va_list_abi (DEFAULT_ABI);
+
+  /* Initialize abi specific va_list builtin types.  */
+  if (TARGET_64BIT)
+    {
+      tree t;
+
+      t = ix86_build_builtin_va_list_abi (SYSV_ABI);
+      if (TREE_CODE (t) != RECORD_TYPE)
+        t = build_variant_type_copy (t);
+      sysv_va_list_type_node = t;
+
+      t = ix86_build_builtin_va_list_abi (MS_ABI);
+      if (TREE_CODE (t) != RECORD_TYPE)
+        t = build_variant_type_copy (t);
+      ms_va_list_type_node = t;
+    }
+
+  return ret;
+}
+
 /* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
 
 static void
@@ -5371,13 +5401,14 @@ ix86_va_start (tree valist, rtx nextarg)
   tree type;
 
   /* Only 64bit target needs something special.  */
-  if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI)
+  if (!TARGET_64BIT ||
+      ix86_canonical_va_list_type (TREE_TYPE (valist)) == ms_va_list_type_node)
     {
       std_expand_builtin_va_start (valist, nextarg);
       return;
     }
 
-  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node));
   f_fpr = TREE_CHAIN (f_gpr);
   f_ovf = TREE_CHAIN (f_fpr);
   f_sav = TREE_CHAIN (f_ovf);
@@ -5450,10 +5481,11 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   enum machine_mode nat_mode;
 
   /* Only 64bit target needs something special.  */
-  if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI)
+  if (!TARGET_64BIT ||
+      ix86_canonical_va_list_type (TREE_TYPE (valist)) == ms_va_list_type_node)
     return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
 
-  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node));
   f_fpr = TREE_CHAIN (f_gpr);
   f_ovf = TREE_CHAIN (f_fpr);
   f_sav = TREE_CHAIN (f_ovf);
@@ -20216,6 +20248,55 @@ ix86_init_mmx_sse_builtins (void)
     }
 }
 
+/* Internal method for ix86_init_builtins.  */
+
+static void
+ix86_init_builtins_va_builtins_abi (void)
+{
+  tree ms_va_ref, sysv_va_ref;
+  tree fnvoid_va_end_ms, fnvoid_va_end_sysv;
+  tree fnvoid_va_start_ms, fnvoid_va_start_sysv;
+  tree fnvoid_va_copy_ms, fnvoid_va_copy_sysv;
+  tree fnattr_ms = NULL_TREE, fnattr_sysv = NULL_TREE;
+
+  if (!TARGET_64BIT)
+    return;
+  fnattr_ms = build_tree_list (get_identifier ("ms_abi"), NULL_TREE);
+  fnattr_sysv = build_tree_list (get_identifier ("sysv_abi"), NULL_TREE);
+  ms_va_ref = build_reference_type (ms_va_list_type_node);
+  sysv_va_ref =
+    build_pointer_type (TREE_TYPE (sysv_va_list_type_node));
+
+  fnvoid_va_end_ms =
+    build_function_type_list (void_type_node, ms_va_ref, NULL_TREE);
+  fnvoid_va_start_ms =
+    build_varargs_function_type_list (void_type_node, ms_va_ref, NULL_TREE);
+  fnvoid_va_end_sysv =
+    build_function_type_list (void_type_node, sysv_va_ref, NULL_TREE);
+  fnvoid_va_start_sysv =
+    build_varargs_function_type_list (void_type_node, sysv_va_ref,
+                                      NULL_TREE);
+  fnvoid_va_copy_ms =
+    build_function_type_list (void_type_node, ms_va_list_type_node, ms_va_ref,
+                             NULL_TREE);
+  fnvoid_va_copy_sysv =
+    build_function_type_list (void_type_node, sysv_va_list_type_node,
+                             sysv_va_ref, NULL_TREE);
+
+  add_builtin_function ("__builtin_ms_va_start", fnvoid_va_start_ms,
+                       BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_ms);
+  add_builtin_function ("__builtin_ms_va_end", fnvoid_va_end_ms,
+                       BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_ms);
+  add_builtin_function ("__builtin_ms_va_copy", fnvoid_va_copy_ms,
+                       BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_ms);
+  add_builtin_function ("__builtin_sysv_va_start", fnvoid_va_start_sysv,
+                       BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+  add_builtin_function ("__builtin_sysv_va_end", fnvoid_va_end_sysv,
+                       BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+  add_builtin_function ("__builtin_sysv_va_copy", fnvoid_va_copy_sysv,
+                       BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+}
+
 static void
 ix86_init_builtins (void)
 {
@@ -20273,6 +20354,8 @@ ix86_init_builtins (void)
 
   if (TARGET_MMX)
     ix86_init_mmx_sse_builtins ();
+  if (TARGET_64BIT)
+    ix86_init_builtins_va_builtins_abi ();
 }
 
 /* Errors in the source file can cause expand_expr to return const0_rtx
@@ -23097,6 +23180,54 @@ x86_order_regs_for_local_alloc (void)
      reg_alloc_order [pos++] = 0;
 }
 
+/* Handle a "ms_abi" or "sysv" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+ix86_handle_abi_attribute (tree *node, tree name,
+                             tree args ATTRIBUTE_UNUSED,
+                             int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_TYPE
+      && TREE_CODE (*node) != METHOD_TYPE
+      && TREE_CODE (*node) != FIELD_DECL
+      && TREE_CODE (*node) != TYPE_DECL)
+    {
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (!TARGET_64BIT)
+    {
+      warning (OPT_Wattributes, "%qs attribute only available for 64-bit",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Can combine regparm with all attributes but fastcall.  */
+  if (is_attribute_p ("ms_abi", name))
+    {
+      if (lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("ms_abi and sysv_abi attributes are not compatible");
+       }
+
+      return NULL_TREE;
+    }
+  else if (is_attribute_p ("sysv_abi", name))
+    {
+      if (lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("ms_abi and sysv_abi attributes are not compatible");
+       }
+
+      return NULL_TREE;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in
    struct attribute_spec.handler.  */
 static tree
@@ -25906,6 +26037,10 @@ static const struct attribute_spec ix86_attribute_table[] =
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
   SUBTARGET_ATTRIBUTE_TABLE,
 #endif
+  /* ms_abi and sysv_abi calling convention function attributes.  */
+  { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
+  { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
+  /* End element.  */
   { NULL,        0, 0, false, false, false, NULL }
 };
 
@@ -25933,6 +26068,104 @@ x86_builtin_vectorization_cost (bool runtime_test)
     return 0;
 }
 
+/* This function returns the calling abi specific va_list type node.
+   It returns  the FNDECL specific va_list type.  */
+
+tree
+ix86_fn_abi_va_list (tree fndecl)
+{
+  int abi;
+
+  if (!TARGET_64BIT)
+    return va_list_type_node;
+  gcc_assert (fndecl != NULL_TREE);
+  abi = ix86_function_abi ((const_tree) fndecl);
+
+  if (abi == DEFAULT_ABI)
+    return va_list_type_node;
+  else if (abi == MS_ABI)
+    return ms_va_list_type_node;
+  else
+    return sysv_va_list_type_node;
+}
+
+/* Returns the canonical va_list type specified by TYPE. If there
+   is no valid TYPE provided, it return NULL_TREE.  */
+
+tree
+ix86_canonical_va_list_type (tree type)
+{
+  tree wtype, htype;
+  if (TARGET_64BIT)
+    {
+      wtype = sysv_va_list_type_node;
+      htype = type;
+      if (TREE_CODE (wtype) == ARRAY_TYPE)
+       {
+         /* If va_list is an array type, the argument may have decayed
+            to a pointer type, e.g. by being passed to another function.
+            In that case, unwrap both types so that we can compare the
+            underlying records.  */
+         if (TREE_CODE (htype) == ARRAY_TYPE
+             || POINTER_TYPE_P (htype))
+           {
+             wtype = TREE_TYPE (wtype);
+             htype = TREE_TYPE (htype);
+           }
+       }
+      if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+       return sysv_va_list_type_node;
+      wtype = ms_va_list_type_node;
+      htype = type;
+      if (TREE_CODE (wtype) == ARRAY_TYPE)
+       {
+         /* If va_list is an array type, the argument may have decayed
+            to a pointer type, e.g. by being passed to another function.
+            In that case, unwrap both types so that we can compare the
+            underlying records.  */
+         if (TREE_CODE (htype) == ARRAY_TYPE
+             || POINTER_TYPE_P (htype))
+           {
+             wtype = TREE_TYPE (wtype);
+             htype = TREE_TYPE (htype);
+           }
+       }
+      if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+       return ms_va_list_type_node;
+
+      return NULL_TREE;
+    }
+  return std_canonical_va_list_type (type);
+}
+
+/* Iterate through the target-specific builtin types for va_list.
+    IDX denotes the iterator, *PTREE is set to the result type of
+    the va_list builtin, and *PNAME to its internal type.
+    Returns zero if there is no element for this index, otherwise
+    IDX should be increased upon the next call.
+    Note, do not iterate a base builtin's name like __builtin_va_list.
+    Used from c_common_nodes_and_builtins.  */
+
+int
+ix86_enum_va_list (int idx, const char **pname, tree *ptree)
+{
+  if (!TARGET_64BIT)
+    return 0;
+  switch (idx) {
+  case 0:
+    *ptree = ms_va_list_type_node;
+    *pname = "__builtin_ms_va_list";
+    break;
+  case 1:
+    *ptree = sysv_va_list_type_node;
+    *pname = "__builtin_sysv_va_list";
+    break;
+  default:
+    return 0;
+  }
+  return 1;
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
@@ -26061,6 +26294,12 @@ x86_builtin_vectorization_cost (bool runtime_test)
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST ix86_build_builtin_va_list
 
+#undef TARGET_FN_ABI_VA_LIST
+#define TARGET_FN_ABI_VA_LIST ix86_fn_abi_va_list
+
+#undef TARGET_CANONICAL_VA_LIST_TYPE
+#define TARGET_CANONICAL_VA_LIST_TYPE ix86_canonical_va_list_type
+
 #undef TARGET_EXPAND_BUILTIN_VA_START
 #define TARGET_EXPAND_BUILTIN_VA_START ix86_va_start
 
index b011885..d17e414 100644 (file)
@@ -453,7 +453,7 @@ extern tree x86_mfence;
 #define TARGET_64BIT_MS_ABI (TARGET_64BIT && ix86_cfun_abi () == MS_ABI)
 
 /* Available call abi.  */
-enum
+enum calling_abi
 {
   SYSV_ABI = 0,
   MS_ABI = 1
@@ -2556,6 +2556,11 @@ struct machine_function GTY(())
 #undef TARG_COND_BRANCH_COST
 #define TARG_COND_BRANCH_COST           ix86_cost->branch_cost
 
+/* Enum through the target specific extra va_list types. Please, do not
+   iterate the base va_list type name.  */
+#define TARGET_ENUM_VA_LIST(IDX, PNAME, PTYPE) \
+  (!TARGET_64BIT ? 0 : ix86_enum_va_list (IDX, PNAME, PTYPE))
+
 /* Cost of any scalar operation, excluding load and store.  */
 #undef TARG_SCALAR_STMT_COST
 #define TARG_SCALAR_STMT_COST           ix86_cost->scalar_stmt_cost
index d4ba0e2..b5418a3 100644 (file)
@@ -4187,6 +4187,18 @@ This hook returns a type node for @code{va_list} for the target.
 The default version of the hook returns @code{void*}.
 @end deftypefn
 
+@deftypefn {Target Hook} tree TARGET_FN_ABI_VA_LIST (tree @var{fndecl})
+This hook returns the va_list type of the calling convention specified by
+@var{fndecl}.
+The default version of this hook returns @code{va_list_type_node}.
+@end deftypefn
+
+@deftypefn {Target Hook} tree TARGET_CANONICAL_VA_LIST_TYPE (tree @var{type})
+This hook returns the va_list type of the calling convention specified by the
+type of @var{type}. If @var{type} is not a valid va_list type, it returns
+@code{NULL_TREE}.
+@end deftypefn
+
 @deftypefn {Target Hook} tree TARGET_GIMPLIFY_VA_ARG_EXPR (tree @var{valist}, tree @var{type}, tree *@var{pre_p}, tree *@var{post_p})
 This hook performs target-specific gimplification of
 @code{VA_ARG_EXPR}.  The first two parameters correspond to the
@@ -4317,6 +4329,20 @@ function use different registers for the return value, this macro
 should recognize only the caller's register numbers.
 @end defmac
 
+@defmac TARGET_ENUM_VA_LIST (@var{idx}, @var{pname}, @var{ptype})
+This target macro is used in function @code{c_common_nodes_and_builtins}
+to iterate through the target specific builtin types for va_list. The
+variable @var{idx} is used as iterator. @var{pname} has to be a pointer
+to a @code{const char *} and @var{ptype} a pointer to a @code{tree} typed
+variable.
+The arguments @var{pname} and @var{ptype} are used to store the result of
+this macro and are set to the name of the va_list builtin type and its
+internal type.
+If the return value of this macro is zero, then there is no more element.
+Otherwise the @var{IDX} should be increased for the next call of this
+macro to iterate through all types.
+@end defmac
+
 @defmac APPLY_RESULT_SIZE
 Define this macro if @samp{untyped_call} and @samp{untyped_return}
 need more space than is implied by @code{FUNCTION_VALUE_REGNO_P} for
index beb44bd..39a51fc 100644 (file)
@@ -342,6 +342,9 @@ extern rtx emit_store_flag_force (rtx, enum rtx_code, rtx, rtx,
 /* Functions from builtins.c:  */
 extern rtx expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 extern tree std_build_builtin_va_list (void);
+extern tree std_fn_abi_va_list (tree);
+extern tree std_canonical_va_list_type (tree);
+
 extern void std_expand_builtin_va_start (tree, rtx);
 extern rtx default_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 extern void expand_builtin_setjmp_setup (rtx, rtx);
index 2692e94..7ffb134 100644 (file)
 #define TARGET_MACHINE_DEPENDENT_REORG 0
 
 #define TARGET_BUILD_BUILTIN_VA_LIST std_build_builtin_va_list
+#define TARGET_FN_ABI_VA_LIST std_fn_abi_va_list
+#define TARGET_CANONICAL_VA_LIST_TYPE std_canonical_va_list_type
 #define TARGET_EXPAND_BUILTIN_VA_START 0
 
 #define TARGET_GET_PCH_VALIDITY default_get_pch_validity
   TARGET_CC_MODES_COMPATIBLE,                  \
   TARGET_MACHINE_DEPENDENT_REORG,              \
   TARGET_BUILD_BUILTIN_VA_LIST,                        \
+  TARGET_FN_ABI_VA_LIST,                       \
+  TARGET_CANONICAL_VA_LIST_TYPE,                       \
   TARGET_EXPAND_BUILTIN_VA_START,              \
   TARGET_GIMPLIFY_VA_ARG_EXPR,                 \
   TARGET_GET_PCH_VALIDITY,                     \
index 012d1c0..1185243 100644 (file)
@@ -697,6 +697,12 @@ struct gcc_target
   /* Create the __builtin_va_list type.  */
   tree (* build_builtin_va_list) (void);
 
+  /* Get the cfun/fndecl calling abi __builtin_va_list type.  */
+  tree (* fn_abi_va_list) (tree);
+
+  /* Get the __builtin_va_list type dependent on input type.  */
+  tree (* canonical_va_list_type) (tree);
+
   /* Expand the __builtin_va_start builtin.  */
   void (* expand_builtin_va_start) (tree valist, rtx nextarg);
 
index 61a522c..ef05b67 100644 (file)
@@ -1,3 +1,11 @@
+2008-07-04  Kai Tietz  <kai.tietz@onevision.com>
+
+       * gcc.dg/callabi/callabi.h: New.
+       * gcc.dg/callabi/vaarg-1.c: New.
+       * gcc.dg/callabi/vaarg-2.c: New.
+       * gcc.dg/callabi/vaarg-3.c: New.
+       * gcc.dg/callabi/func-1.c: New.
+
 2008-07-04  Richard Sandiford  <richard@codesourcery.com>
 
        * gcc.target/m68k/interrupt-2.c: New file.
diff --git a/gcc/testsuite/gcc.dg/callabi/callabi.h b/gcc/testsuite/gcc.dg/callabi/callabi.h
new file mode 100644 (file)
index 0000000..d008ad6
--- /dev/null
@@ -0,0 +1,50 @@
+/* First the default target definition.  */
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+  typedef __builtin_va_list __gnuc_va_list;
+#endif
+
+#ifndef _VA_LIST_DEFINED
+#define _VA_LIST_DEFINED
+  typedef __gnuc_va_list va_list;
+#endif
+
+#define __va_copy(d,s) __builtin_va_copy(d,s)
+#define __va_start(v,l)        __builtin_va_start(v,l)
+#define __va_arg(v,l)  __builtin_va_arg(v,l)
+#define __va_end(v)    __builtin_va_end(v)
+
+#define __ms_va_copy(d,s) __builtin_ms_va_copy(d,s)
+#define __ms_va_start(v,l) __builtin_ms_va_start(v,l)
+#define __ms_va_arg(v,l)       __builtin_va_arg(v,l)
+#define __ms_va_end(v) __builtin_ms_va_end(v)
+
+#define __sysv_va_copy(d,s) __builtin_sysv_va_copy(d,s)
+#define __sysv_va_start(v,l) __builtin_sysv_va_start(v,l)
+#define __sysv_va_arg(v,l)     __builtin_va_arg(v,l)
+#define __sysv_va_end(v) __builtin_sysv_va_end(v)
+
+#define CALLABI_NATIVE
+
+#ifdef _WIN64
+#define CALLABI_CROSS __attribute__ ((sysv_abi))
+
+#define CROSS_VA_LIST  __builtin_sysv_va_list
+
+#define CROSS_VA_COPY(d,s) __sysv_va_copy(d,s)
+#define CROSS_VA_START(v,l) __sysv_va_start(v,l)
+#define CROSS_VA_ARG(v,l) __sysv_va_arg(v,l)
+#define CROSS_VA_END(v)  __sysv_va_end(v)
+
+#else
+
+#define CALLABI_CROSS __attribute__ ((ms_abi))
+
+#define CROSS_VA_LIST  __builtin_ms_va_list
+
+#define CROSS_VA_COPY(d,s) __ms_va_copy(d,s)
+#define CROSS_VA_START(v,l) __ms_va_start(v,l)
+#define CROSS_VA_ARG(v,l) __ms_va_arg(v,l)
+#define CROSS_VA_END(v)  __ms_va_end(v)
+
+#endif
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/callabi/func-1.c b/gcc/testsuite/gcc.dg/callabi/func-1.c
new file mode 100644 (file)
index 0000000..c727dbe
--- /dev/null
@@ -0,0 +1,40 @@
+/* Test for cross x86_64<->w64 abi standard calls.
+*/
+/* Origin: Kai Tietz <kai.tietz@onevision.com> */
+/* { dg-do run { target { x86_64-*-* } } } */
+/* { dg-options "-std=gnu99 -ffast-math" } */
+#include "callabi.h"
+
+extern void abort (void);
+
+long double
+CALLABI_CROSS func_cross (long double a, double b, float c, long d, int e,
+                         char f)
+{
+  long double ret;
+  ret = a + (long double) b + (long double) c;
+  ret *= (long double) (d + (long) e);
+  if (f>0)
+    ret += func_cross (a,b,c,d,e,-f);
+  return ret;
+}
+
+long double
+CALLABI_NATIVE func_native (long double a, double b, float c, long d, int e,
+                           char f)
+{
+  long double ret;
+  ret = a + (long double) b + (long double) c;
+  ret *= (long double) (d + (long) e);
+  if (f>0)
+    ret += func_native (a,b,c,d,e,-f);
+  return ret;
+}
+
+int main ()
+{
+  if (func_cross (1.0,2.0,3.0,1,2,3)
+      != func_native (1.0,2.0,3.0,1,2,3))
+    abort ();
+  return 0;
+}
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/callabi/vaarg-1.c b/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
new file mode 100644 (file)
index 0000000..1e745e5
--- /dev/null
@@ -0,0 +1,47 @@
+/* Test for cross x86_64<->w64 abi va_list calls.
+*/
+/* Origin: Kai Tietz <kai.tietz@onevision.com> */
+/* { dg-do run { target { x86_64-*-* } } } */
+/* { dg-options "-std=gnu99" } */
+#include "callabi.h"
+
+extern __SIZE_TYPE__ strlen (const char *);
+extern int sprintf (char *,const char *, ...);
+extern void abort (void);
+
+static
+void CALLABI_CROSS vdo_cpy (char *s, CROSS_VA_LIST argp)
+{
+  __SIZE_TYPE__ len;
+  char *r = s;
+  char *e;
+  *r = 0;
+  for (;;) {
+    e = CROSS_VA_ARG (argp,char *);
+    if (*e == 0) break;
+    sprintf (r,"%s", e);
+    r += strlen (r);
+  }
+}
+
+static
+void CALLABI_CROSS do_cpy (char *s, ...)
+{
+  CROSS_VA_LIST argp;
+  CROSS_VA_START (argp, s);
+  vdo_cpy (s, argp);
+  CROSS_VA_END (argp);
+}
+
+int main ()
+{
+  char s[256];
+
+  do_cpy (s, "1","2","3","4", "5", "6", "7", "");
+
+  if (s[0] != '1' || s[1] !='2' || s[2] != '3' || s[3] != '4'
+      || s[4] != '5' || s[5] != '6' || s[6] != '7' || s[7] != 0)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/callabi/vaarg-2.c b/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
new file mode 100644 (file)
index 0000000..c9b7161
--- /dev/null
@@ -0,0 +1,47 @@
+/* Test for cross x86_64<->w64 abi va_list calls.
+*/
+/* Origin: Kai Tietz <kai.tietz@onevision.com> */
+/* { dg-do run { target { x86_64-*-* } } } */
+/* { dg-options "-std=gnu99" } */
+#include "callabi.h"
+
+extern void abort (void);
+
+#define SZ_ARGS        1ll,2ll,3ll,4ll,5ll,6ll,7ll,0ll
+
+static
+int CALLABI_CROSS fct1 (va_list argp, ...)
+{
+  long long p1,p2;
+  int ret = 1;
+  CROSS_VA_LIST argp_2;
+  CROSS_VA_START (argp_2,argp);
+
+  do {
+    p1 = CROSS_VA_ARG (argp_2, long long);
+    p2 = __va_arg (argp, long long);
+    if (p1 != p2)
+      ret = 0;
+  } while (ret && p1 != 0);
+  CROSS_VA_END (argp_2);
+  return ret;
+}
+
+static
+int fct2 (int dummy, ...)
+{
+  va_list argp;
+  int ret = dummy;
+
+  __va_start (argp, dummy);
+  ret += fct1 (argp, SZ_ARGS);
+  __va_end (argp);
+  return ret;
+}
+
+int main()
+{
+  if (fct2 (-1, SZ_ARGS) != 0)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/callabi/vaarg-3.c b/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
new file mode 100644 (file)
index 0000000..d0d0687
--- /dev/null
@@ -0,0 +1,47 @@
+/* Test for cross x86_64<->w64 abi va_list calls.
+*/
+/* Origin: Kai Tietz <kai.tietz@onevision.com> */
+/* { dg-do run { target { x86_64-*-* } } } */
+/* { dg-options "-std=gnu99" } */
+#include "callabi.h"
+
+extern void abort (void);
+
+#define SZ_ARGS        1ll,2ll,3ll,4ll,5ll,6ll,7ll,0ll
+
+static
+int fct1 (CROSS_VA_LIST argp, ...)
+{
+  long long p1,p2;
+  int ret = 1;
+  va_list argp_2;
+
+    __va_start (argp_2,argp);
+  do {
+    p1 = __va_arg (argp_2, long long);
+    p2 = CROSS_VA_ARG (argp, long long);
+    if (p1 != p2)
+      ret = 0;
+  } while (ret && p1 != 0);
+  __va_end (argp_2);
+  return ret;
+}
+
+static
+int CALLABI_CROSS fct2 (int dummy, ...)
+{
+  CROSS_VA_LIST argp;
+  int ret = dummy;
+
+  CROSS_VA_START (argp, dummy);
+  ret += fct1 (argp, SZ_ARGS);
+  CROSS_VA_END (argp);
+  return ret;
+}
+
+int main()
+{
+  if (fct2 (-1, SZ_ARGS) != 0)
+    abort ();
+  return 0;
+}
index 391511f..c50c6cd 100644 (file)
@@ -308,6 +308,26 @@ sra_type_can_be_decomposed_p (tree type)
   return false;
 }
 
+/* Returns true if the TYPE is one of the available va_list types.
+   Otherwise it returns false.
+   Note, that for multiple calling conventions there can be more
+   than just one va_list type present.  */
+
+static bool
+is_va_list_type (tree type)
+{
+  tree h;
+
+  if (type == NULL_TREE)
+    return false;
+  h = targetm.canonical_va_list_type (type);
+  if (h == NULL_TREE)
+    return false;
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (h))
+        return true;
+  return false;
+}
+
 /* Return true if DECL can be decomposed into a set of independent
    (though not necessarily scalar) variables.  */
 
@@ -360,9 +380,7 @@ decl_can_be_decomposed_p (tree var)
      tree-stdarg.c, as the decomposition is truly a win.  This could also
      be fixed if the stdarg pass ran early, but this can't be done until
      we've aliasing information early too.  See PR 30791.  */
-  if (early_sra
-      && TYPE_MAIN_VARIANT (TREE_TYPE (var))
-        == TYPE_MAIN_VARIANT (va_list_type_node))
+  if (early_sra && is_va_list_type (TREE_TYPE (var)))
     return false;
 
   return true;
index d4dfadb..da6b785 100644 (file)
@@ -2748,17 +2748,19 @@ optimize_stack_restore (basic_block bb, tree call, block_stmt_iterator i)
 static tree
 optimize_stdarg_builtin (tree call)
 {
-  tree callee, lhs, rhs;
+  tree callee, lhs, rhs, cfun_va_list;
   bool va_list_simple_ptr;
 
   if (TREE_CODE (call) != CALL_EXPR)
     return NULL_TREE;
 
-  va_list_simple_ptr = POINTER_TYPE_P (va_list_type_node)
-                      && (TREE_TYPE (va_list_type_node) == void_type_node
-                          || TREE_TYPE (va_list_type_node) == char_type_node);
-
   callee = get_callee_fndecl (call);
+
+  cfun_va_list = targetm.fn_abi_va_list (callee);
+  va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
+                      && (TREE_TYPE (cfun_va_list) == void_type_node
+                          || TREE_TYPE (cfun_va_list) == char_type_node);
+
   switch (DECL_FUNCTION_CODE (callee))
     {
     case BUILT_IN_VA_START:
@@ -2773,7 +2775,7 @@ optimize_stdarg_builtin (tree call)
       lhs = CALL_EXPR_ARG (call, 0);
       if (!POINTER_TYPE_P (TREE_TYPE (lhs))
          || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
-            != TYPE_MAIN_VARIANT (va_list_type_node))
+            != TYPE_MAIN_VARIANT (cfun_va_list))
        return NULL_TREE;
 
       lhs = build_fold_indirect_ref (lhs);
@@ -2792,13 +2794,13 @@ optimize_stdarg_builtin (tree call)
       lhs = CALL_EXPR_ARG (call, 0);
       if (!POINTER_TYPE_P (TREE_TYPE (lhs))
          || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
-            != TYPE_MAIN_VARIANT (va_list_type_node))
+            != TYPE_MAIN_VARIANT (cfun_va_list))
        return NULL_TREE;
 
       lhs = build_fold_indirect_ref (lhs);
       rhs = CALL_EXPR_ARG (call, 1);
       if (TYPE_MAIN_VARIANT (TREE_TYPE (rhs))
-         != TYPE_MAIN_VARIANT (va_list_type_node))
+         != TYPE_MAIN_VARIANT (cfun_va_list))
        return NULL_TREE;
 
       rhs = fold_convert (TREE_TYPE (lhs), rhs);
index 728c37d..f922887 100644 (file)
@@ -605,6 +605,7 @@ execute_optimize_stdarg (void)
   bool va_list_simple_ptr;
   struct stdarg_info si;
   const char *funcname = NULL;
+  tree cfun_va_list;
 
   cfun->va_list_gpr_size = 0;
   cfun->va_list_fpr_size = 0;
@@ -615,10 +616,11 @@ execute_optimize_stdarg (void)
   if (dump_file)
     funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
 
-  va_list_simple_ptr = POINTER_TYPE_P (va_list_type_node)
-                      && (TREE_TYPE (va_list_type_node) == void_type_node
-                          || TREE_TYPE (va_list_type_node) == char_type_node);
-  gcc_assert (is_gimple_reg_type (va_list_type_node) == va_list_simple_ptr);
+  cfun_va_list = targetm.fn_abi_va_list (cfun->decl);
+  va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
+                      && (TREE_TYPE (cfun_va_list) == void_type_node
+                          || TREE_TYPE (cfun_va_list) == char_type_node);
+  gcc_assert (is_gimple_reg_type (cfun_va_list) == va_list_simple_ptr);
 
   FOR_EACH_BB (bb)
     {
@@ -671,7 +673,7 @@ execute_optimize_stdarg (void)
              ap = TREE_OPERAND (ap, 0);
            }
          if (TYPE_MAIN_VARIANT (TREE_TYPE (ap))
-             != TYPE_MAIN_VARIANT (va_list_type_node)
+             != TYPE_MAIN_VARIANT (targetm.fn_abi_va_list (cfun->decl))
              || TREE_CODE (ap) != VAR_DECL)
            {
              va_list_escapes = true;