public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch i386] Enable attribute based calling convention switching and support vaarg.
@ 2008-06-28 13:28 Kai Tietz
  2008-06-30 12:29 ` Richard Guenther
  0 siblings, 1 reply; 25+ messages in thread
From: Kai Tietz @ 2008-06-28 13:28 UTC (permalink / raw)
  To: GCC Patches
  Cc: Richard Guenther, Mark Mitchell, Jan Hubicka, Jan Hubicka, Kai Tietz

[-- Attachment #1: Type: text/plain, Size: 2647 bytes --]

Hello,

This is the updated version of the vaarg builtin and calling
convention abi switching patch.

ChangeLog

2008-06-28  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_cfun_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.cfun_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_cfun_abi_va_list): New.
	(ix86_canonical_va_list_type): New.
	(ix86_enum_va_list): New.
	(TARGET_CFUN_ABI_VA_LIST): New.
	(TARGET_CANONICAL_VA_LIST_TYPE): New.
	* config/i386/i386.h (TARGET_ENUM_VA_LIST): New.
	* doc/tm.texi (TARGET_CFUN_ABI_VA_LIST): New.
	(TARGET_CANONICAL_VA_LIST_TYPE): New.
	(TARGET_ENUM_VA_LIST): New.
	* expr.h (std_cfun_abi_va_list): New.
	(std_canonical_va_list_type): New.
	* target-def.h (TARGET_CFUN_ABI_VA_LIST): New.
	(TARGET_CANONICAL_VA_LIST_TYPE): New.
	(TARGET_INITIALIZER): Add TARGET_CFUN_ABI_VA_LIST and
	TARGET_CANONICAL_VA_LIST_TYPE.
	* target.h (struct gcc_target): Add cfun_abi_va_list hook
	and canonical_va_list_type hook.


2008-06-28  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.

Is this patch ok for apply?
I tested this patch on x86_64-pc-mingw32 target. All new testcases
work without any problems.

Cheers,
Kai

-- 
| (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: callabi.txt --]
[-- Type: text/plain, Size: 38714 bytes --]

Index: gcc/gcc/builtins.c
===================================================================
--- gcc.orig/gcc/builtins.c
+++ gcc/gcc/builtins.c
@@ -4625,18 +4625,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 (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);
 	}
     }
@@ -4649,7 +4650,7 @@ stabilize_va_list (tree valist, int need
 	  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;
 	}
@@ -4670,6 +4671,22 @@ std_build_builtin_va_list (void)
   return ptr_type_node;
 }
 
+/* The "standard" abi va_list is va_list_type_node.  */
+
+tree
+std_cfun_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 ATTRIBUTE_UNUSED)
+{
+  return va_list_type_node;
+}
+
 /* The "standard" implementation of va_start: just assign `nextarg' to
    the variable.  */
 
@@ -4828,15 +4845,17 @@ gimplify_va_arg_expr (tree *expr_p, tree
   tree promoted_type, want_va_type, have_va_type;
   tree valist = TREE_OPERAND (*expr_p, 0);
   tree type = TREE_TYPE (*expr_p);
+  tree abi_type;
   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;
 
+  abi_type = want_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
@@ -4891,15 +4910,15 @@ gimplify_va_arg_expr (tree *expr_p, tree
     {
       /* 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 (abi_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_CFUN_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 (abi_type));
 	      valist = build_fold_addr_expr_with_type (valist, p1);
 	    }
 	  gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
@@ -4947,9 +4966,9 @@ 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)
+  if (TREE_CODE (targetm.cfun_abi_va_list (NULL_TREE)) != ARRAY_TYPE)
     {
-      t = build2 (MODIFY_EXPR, va_list_type_node, dst, src);
+      t = build2 (MODIFY_EXPR, targetm.cfun_abi_va_list (NULL_TREE), dst, src);
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
@@ -4960,8 +4979,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.cfun_abi_va_list (NULL_TREE)),
+      		  NULL_RTX, VOIDmode, EXPAND_NORMAL);
 
       dstb = convert_memory_address (Pmode, dstb);
       srcb = convert_memory_address (Pmode, srcb);
@@ -4969,10 +4988,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.cfun_abi_va_list (NULL_TREE)));
       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.cfun_abi_va_list (NULL_TREE)));
 
       /* Copy.  */
       emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
Index: gcc/gcc/c-common.c
===================================================================
--- gcc.orig/gcc/c-common.c
+++ gcc/gcc/c-common.c
@@ -3964,6 +3964,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: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h
+++ gcc/gcc/config/i386/i386-protos.h
@@ -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_cfun_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: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -1716,6 +1716,10 @@ unsigned int ix86_preferred_stack_bounda
 /* 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 fntyp
       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;
@@ -5173,13 +5173,16 @@ ix86_struct_value_rtx (tree type, int in
 \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);
@@ -5215,6 +5218,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
@@ -5370,13 +5400,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);
@@ -5449,10 +5480,11 @@ ix86_gimplify_va_arg (tree valist, tree 
   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);
@@ -20243,11 +20275,62 @@ 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)
 {
   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
@@ -23063,6 +23146,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
@@ -25872,6 +26003,10 @@ static const struct attribute_spec ix86_
 #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 }
 };
 
@@ -25899,6 +26034,107 @@ x86_builtin_vectorization_cost (bool run
     return 0;
 }
 
+/* This function returns the calling abi specific va_list type node.
+   If FNDECL is NULL_TREE, it returns the current cfun specific
+   va_list type, otherwise the the fndecl specific type.  */
+
+tree
+ix86_cfun_abi_va_list (tree fndecl ATTRIBUTE_UNUSED)
+{
+  int abi;
+
+  if (!TARGET_64BIT)
+    return va_list_type_node;
+  if (fndecl != NULL_TREE)
+    abi = ix86_function_abi ((const_tree) fndecl);
+  else
+    abi = ix86_cfun_abi ();
+  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)
+{
+  if (TARGET_64BIT)
+    {
+      tree wtype, htype;
+
+      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 ix86_cfun_abi_va_list (NULL_TREE);
+}
+
+/* This is used in function c_common_nodes_and_builtins ()
+   to iterate through the target specific builtin types for va_list. The
+   variable IDX is used as iterator. PNAME is a pointer
+   to a 'const char *' and PTYPE is a pointer to a 'tree' type.
+   The arguments PNAME and PTYPE are used to store the result and are set
+   to the name of the va_list builtin type and its internal type.
+   If the return value is zero, then there is no element for this index.
+   Otherwise the IDX should be increased for the next call of this.
+   Note, do not iterate a base builtins name like __builtin_va_list.  */
+
+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
@@ -26027,6 +26263,12 @@ x86_builtin_vectorization_cost (bool run
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST ix86_build_builtin_va_list
 
+#undef TARGET_CFUN_ABI_VA_LIST
+#define TARGET_CFUN_ABI_VA_LIST ix86_cfun_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: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h
+++ gcc/gcc/config/i386/i386.h
@@ -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: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -4187,6 +4187,19 @@ This hook returns a type node for @code{
 The default version of the hook returns @code{void*}.
 @end deftypefn
 
+@deftypefn {Target Hook} tree TARGET_CFUN_ABI_VA_LIST (tree @var{fndecl})
+This hook returns the va_list type of the calling convention specified by cfun,
+if @var{fndecl} is @code{NULL_TREE}. Otherwise the va_list type of the calling
+convention of @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}.
+The default version of this hook returns @code{va_list_type_node}.
+@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 +4330,20 @@ function use different registers for the
 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: gcc/gcc/expr.h
===================================================================
--- gcc.orig/gcc/expr.h
+++ gcc/gcc/expr.h
@@ -342,6 +342,9 @@ extern rtx emit_store_flag_force (rtx, e
 /* 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_cfun_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: gcc/gcc/target-def.h
===================================================================
--- gcc.orig/gcc/target-def.h
+++ gcc/gcc/target-def.h
@@ -520,6 +520,8 @@
 #define TARGET_MACHINE_DEPENDENT_REORG 0
 
 #define TARGET_BUILD_BUILTIN_VA_LIST std_build_builtin_va_list
+#define TARGET_CFUN_ABI_VA_LIST std_cfun_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
@@ -820,6 +822,8 @@
   TARGET_CC_MODES_COMPATIBLE,			\
   TARGET_MACHINE_DEPENDENT_REORG,		\
   TARGET_BUILD_BUILTIN_VA_LIST,			\
+  TARGET_CFUN_ABI_VA_LIST,			\
+  TARGET_CANONICAL_VA_LIST_TYPE,			\
   TARGET_EXPAND_BUILTIN_VA_START,		\
   TARGET_GIMPLIFY_VA_ARG_EXPR,			\
   TARGET_GET_PCH_VALIDITY,			\
Index: gcc/gcc/target.h
===================================================================
--- gcc.orig/gcc/target.h
+++ gcc/gcc/target.h
@@ -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 (* cfun_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: gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
@@ -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;
+}
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
@@ -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;
+}
Index: gcc/gcc/tree-sra.c
===================================================================
--- gcc.orig/gcc/tree-sra.c
+++ gcc/gcc/tree-sra.c
@@ -308,6 +308,22 @@ sra_type_can_be_decomposed_p (tree type)
   return false;
 }
 
+/* Returns true, if the TYPE is one of the avalable va_list types.
+   Otherwise it returns false.
+   Note, that for multiple calling conventions there can be more
+   then just one va_list type be present.  */
+
+static bool
+is_va_list_type (tree type)
+{
+  if (type == NULL_TREE)
+    return false;
+  if (TYPE_MAIN_VARIANT (type)
+	 == TYPE_MAIN_VARIANT (targetm.canonical_va_list_type (type)))
+	 return true;
+  return false;
+}
+
 /* Return true if DECL can be decomposed into a set of independent
    (though not necessarily scalar) variables.  */
 
@@ -360,9 +376,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: gcc/gcc/tree-ssa-ccp.c
===================================================================
--- gcc.orig/gcc/tree-ssa-ccp.c
+++ gcc/gcc/tree-ssa-ccp.c
@@ -2748,17 +2748,19 @@ optimize_stack_restore (basic_block bb, 
 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.cfun_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: gcc/gcc/tree-stdarg.c
===================================================================
--- gcc.orig/gcc/tree-stdarg.c
+++ gcc/gcc/tree-stdarg.c
@@ -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.cfun_abi_va_list (NULL_TREE);
+  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.cfun_abi_va_list (NULL_TREE))
 	      || TREE_CODE (ap) != VAR_DECL)
 	    {
 	      va_list_escapes = true;
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
@@ -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: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -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-*-*)
Index: gcc/gcc/config/i386/cross-stdarg.h
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/cross-stdarg.h
@@ -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 */

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-06-28 13:28 [patch i386] Enable attribute based calling convention switching and support vaarg Kai Tietz
@ 2008-06-30 12:29 ` Richard Guenther
  2008-06-30 14:08   ` Kai Tietz
  0 siblings, 1 reply; 25+ messages in thread
From: Richard Guenther @ 2008-06-30 12:29 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches, Mark Mitchell, Jan Hubicka, Jan Hubicka, Kai Tietz

On Sat, Jun 28, 2008 at 3:25 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
> Hello,
>
> This is the updated version of the vaarg builtin and calling
> convention abi switching patch.

Please change the target hooks as follows.

canonical_va_list_type should return NULL_TREE for types that are
not a variant of either va_list type.

cfun_abi_va_list should not handle NULL_TREE as current_function_decl,
instead you should pass that.  The name should be changed to
fn_abi_va_list as well - after all, it's not about the current function.

In this context the gimplify_va_arg_expr hunk should properly use
want_va_type and have_va_type to the function decls parameter type
and the argument type.  In the current state of the patch it is confusing
what is actually done.

Richard.

> ChangeLog
>
> 2008-06-28  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_cfun_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.cfun_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_cfun_abi_va_list): New.
>        (ix86_canonical_va_list_type): New.
>        (ix86_enum_va_list): New.
>        (TARGET_CFUN_ABI_VA_LIST): New.
>        (TARGET_CANONICAL_VA_LIST_TYPE): New.
>        * config/i386/i386.h (TARGET_ENUM_VA_LIST): New.
>        * doc/tm.texi (TARGET_CFUN_ABI_VA_LIST): New.
>        (TARGET_CANONICAL_VA_LIST_TYPE): New.
>        (TARGET_ENUM_VA_LIST): New.
>        * expr.h (std_cfun_abi_va_list): New.
>        (std_canonical_va_list_type): New.
>        * target-def.h (TARGET_CFUN_ABI_VA_LIST): New.
>        (TARGET_CANONICAL_VA_LIST_TYPE): New.
>        (TARGET_INITIALIZER): Add TARGET_CFUN_ABI_VA_LIST and
>        TARGET_CANONICAL_VA_LIST_TYPE.
>        * target.h (struct gcc_target): Add cfun_abi_va_list hook
>        and canonical_va_list_type hook.
>
>
> 2008-06-28  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.
>
> Is this patch ok for apply?
> I tested this patch on x86_64-pc-mingw32 target. All new testcases
> work without any problems.
>
> Cheers,
> Kai
>
> --
> | (\_/) This is Bunny. Copy and paste
> | (='.'=) Bunny into your signature to help
> | (")_(") him gain world domination
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and  support vaarg.
  2008-06-30 12:29 ` Richard Guenther
@ 2008-06-30 14:08   ` Kai Tietz
  2008-06-30 15:37     ` Richard Guenther
  0 siblings, 1 reply; 25+ messages in thread
From: Kai Tietz @ 2008-06-30 14:08 UTC (permalink / raw)
  To: Richard Guenther
  Cc: GCC Patches, Jan Hubicka, Jan Hubicka, Kai Tietz, Mark Mitchell

Hello,

"Richard Guenther" <richard.guenther@gmail.com> wrote on 30.06.2008 
14:06:24:
> In this context the gimplify_va_arg_expr hunk should properly use
> want_va_type and have_va_type to the function decls parameter type
> and the argument type.  In the current state of the patch it is 
confusing
> what is actually done.

One problem I see here is that have_va_type and want_va_type are getting 
modified for comparision. This leads to the problem, that the type 
afterwards used in

...
      /* Make it easier for the backends by protecting the valist argument
         from multiple evaluations.  */
      if (TREE_CODE (abi_type) == ARRAY_TYPE)
        {
          /* For this case, the backends will be expecting a pointer to
             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 (abi_type));
              valist = build_fold_addr_expr_with_type (valist, p1);
            }
          gimplify_expr (&valist, pre_p, post_p, is_gimple_val, 
fb_rvalue);
        }
      else
        gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, 
fb_lvalue);
...

would have false type for TREE_CODE(want_type). IMHO the helper variable 
(abi_type) is necessary. Maybe it could be named different?

Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-06-30 14:08   ` Kai Tietz
@ 2008-06-30 15:37     ` Richard Guenther
  2008-07-01 12:32       ` Kai Tietz
  0 siblings, 1 reply; 25+ messages in thread
From: Richard Guenther @ 2008-06-30 15:37 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches, Jan Hubicka, Jan Hubicka, Kai Tietz, Mark Mitchell

On Mon, Jun 30, 2008 at 3:57 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> Hello,
>
> "Richard Guenther" <richard.guenther@gmail.com> wrote on 30.06.2008
> 14:06:24:
>> In this context the gimplify_va_arg_expr hunk should properly use
>> want_va_type and have_va_type to the function decls parameter type
>> and the argument type.  In the current state of the patch it is
> confusing
>> what is actually done.
>
> One problem I see here is that have_va_type and want_va_type are getting
> modified for comparision. This leads to the problem, that the type
> afterwards used in

I don't see a problem here.  If you do

want_va_type = cfun_abi_type
have_va_type = canonical_va_type (TREE_TYPE (valist))

then things should just work.  In fact, even the canonicalization
of have_va_type should not be necessary in this function.

Richard.

> ...
>      /* Make it easier for the backends by protecting the valist argument
>         from multiple evaluations.  */
>      if (TREE_CODE (abi_type) == ARRAY_TYPE)
>        {
>          /* For this case, the backends will be expecting a pointer to
>             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 (abi_type));
>              valist = build_fold_addr_expr_with_type (valist, p1);
>            }
>          gimplify_expr (&valist, pre_p, post_p, is_gimple_val,
> fb_rvalue);
>        }
>      else
>        gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval,
> fb_lvalue);
> ...
>
> would have false type for TREE_CODE(want_type). IMHO the helper variable
> (abi_type) is necessary. Maybe it could be named different?
>
> Kai
>
> |  (\_/)  This is Bunny. Copy and paste Bunny
> | (='.'=) into your signature to help him gain
> | (")_(") world domination.
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and  support vaarg.
  2008-06-30 15:37     ` Richard Guenther
@ 2008-07-01 12:32       ` Kai Tietz
  2008-07-01 19:08         ` Ralf Wildenhues
  2009-02-18  7:41         ` H.J. Lu
  0 siblings, 2 replies; 25+ messages in thread
From: Kai Tietz @ 2008-07-01 12:32 UTC (permalink / raw)
  To: Richard Guenther
  Cc: GCC Patches, Jan Hubicka, Jan Hubicka, Kai Tietz, Mark Mitchell

[-- Attachment #1: Type: text/plain, Size: 4372 bytes --]

Hello Richard,

"Richard Guenther" <richard.guenther@gmail.com> wrote on 30.06.2008 
17:24:57:

> On Mon, Jun 30, 2008 at 3:57 PM, Kai Tietz <Kai.Tietz@onevision.com> 
wrote:
> > Hello,
> >
> > "Richard Guenther" <richard.guenther@gmail.com> wrote on 30.06.2008
> > 14:06:24:
> >> In this context the gimplify_va_arg_expr hunk should properly use
> >> want_va_type and have_va_type to the function decls parameter type
> >> and the argument type.  In the current state of the patch it is
> > confusing
> >> what is actually done.
> >
> > One problem I see here is that have_va_type and want_va_type are 
getting
> > modified for comparision. This leads to the problem, that the type
> > afterwards used in
> 
> I don't see a problem here.  If you do
> 
> want_va_type = cfun_abi_type
> have_va_type = canonical_va_type (TREE_TYPE (valist))
> 
> then things should just work.  In fact, even the canonicalization
> of have_va_type should not be necessary in this function.

No, because even in *foreign* calling convention the va_arg call needs to 
generated properly. So the use of cfun_abi_type is wrong here. Otherwise 
the testcases vaarg-2.c and vaarg-3.c won't work. I elliminated in my 
patch the want_va_list type completly, because it makes here less sense. 
If the canonical call of TREE_TYPE(valist) is returning a NULL_TREE, it is 
sure that the passed in argument type is not a valid va_list type. So it 
seems to be enough to check if have_va_type is NULL_TREE for the error 
checking. I adjusted the std_canonical_va_type () function to return 
NULL_TREE if type is not va_list_type_node.

ChangeLog

2008-07-01  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-01  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.

I tested this patch on x86_64-pc-mingw32 target. All new testcases
work without any problems.
Is this patch ok for apply?

Cheers,
Kai

[-- Attachment #2: callabi_tstcase.txt --]
[-- Type: text/plain, Size: 41589 bytes --]

Index: gcc/gcc/builtins.c
===================================================================
--- gcc.orig/gcc/builtins.c
+++ gcc/gcc/builtins.c
@@ -4625,18 +4625,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);
 	}
     }
@@ -4649,7 +4650,7 @@ stabilize_va_list (tree valist, int need
 	  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;
 	}
@@ -4670,6 +4671,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.  */
 
@@ -4825,33 +4862,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;
@@ -4859,7 +4881,7 @@ gimplify_va_arg_expr (tree *expr_p, tree
 
   /* 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;
@@ -4891,15 +4913,15 @@ gimplify_va_arg_expr (tree *expr_p, tree
     {
       /* 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);
@@ -4947,9 +4969,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);
     }
@@ -4960,8 +4984,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);
@@ -4969,10 +4993,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: gcc/gcc/c-common.c
===================================================================
--- gcc.orig/gcc/c-common.c
+++ gcc/gcc/c-common.c
@@ -3964,6 +3964,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: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h
+++ gcc/gcc/config/i386/i386-protos.h
@@ -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: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -1716,6 +1716,10 @@ unsigned int ix86_preferred_stack_bounda
 /* 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 fntyp
       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;
@@ -5173,13 +5173,16 @@ ix86_struct_value_rtx (tree type, int in
 \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);
@@ -5215,6 +5218,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
@@ -5370,13 +5400,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);
@@ -5449,10 +5480,11 @@ ix86_gimplify_va_arg (tree valist, tree 
   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);
@@ -20188,6 +20220,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)
 {
@@ -20239,6 +20320,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
@@ -23054,6 +23137,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
@@ -25863,6 +25994,10 @@ static const struct attribute_spec ix86_
 #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 }
 };
 
@@ -25890,6 +26025,107 @@ x86_builtin_vectorization_cost (bool run
     return 0;
 }
 
+/* This function returns the calling abi specific va_list type node.
+   If FNDECL is NULL_TREE, it returns the current cfun specific
+   va_list type, otherwise the the fndecl specific type.  */
+
+tree
+ix86_fn_abi_va_list (tree fndecl ATTRIBUTE_UNUSED)
+{
+  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);
+}
+
+/* This is used in function c_common_nodes_and_builtins ()
+   to iterate through the target specific builtin types for va_list. The
+   variable IDX is used as iterator. PNAME is a pointer
+   to a 'const char *' and PTYPE is a pointer to a 'tree' type.
+   The arguments PNAME and PTYPE are used to store the result and are set
+   to the name of the va_list builtin type and its internal type.
+   If the return value is zero, then there is no element for this index.
+   Otherwise the IDX should be increased for the next call of this.
+   Note, do not iterate a base builtins name like __builtin_va_list.  */
+
+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
@@ -26018,6 +26254,12 @@ x86_builtin_vectorization_cost (bool run
 #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: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h
+++ gcc/gcc/config/i386/i386.h
@@ -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: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -4187,6 +4187,18 @@ This hook returns a type node for @code{
 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
 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: gcc/gcc/expr.h
===================================================================
--- gcc.orig/gcc/expr.h
+++ gcc/gcc/expr.h
@@ -342,6 +342,9 @@ extern rtx emit_store_flag_force (rtx, e
 /* 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: gcc/gcc/target-def.h
===================================================================
--- gcc.orig/gcc/target-def.h
+++ gcc/gcc/target-def.h
@@ -520,6 +520,8 @@
 #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
@@ -820,6 +822,8 @@
   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: gcc/gcc/target.h
===================================================================
--- gcc.orig/gcc/target.h
+++ gcc/gcc/target.h
@@ -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: gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
@@ -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;
+}
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
@@ -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;
+}
Index: gcc/gcc/tree-sra.c
===================================================================
--- gcc.orig/gcc/tree-sra.c
+++ gcc/gcc/tree-sra.c
@@ -308,6 +308,26 @@ sra_type_can_be_decomposed_p (tree type)
   return false;
 }
 
+/* Returns true, if the TYPE is one of the avalable va_list types.
+   Otherwise it returns false.
+   Note, that for multiple calling conventions there can be more
+   then just one va_list type be 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: gcc/gcc/tree-ssa-ccp.c
===================================================================
--- gcc.orig/gcc/tree-ssa-ccp.c
+++ gcc/gcc/tree-ssa-ccp.c
@@ -2748,17 +2748,19 @@ optimize_stack_restore (basic_block bb, 
 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: gcc/gcc/tree-stdarg.c
===================================================================
--- gcc.orig/gcc/tree-stdarg.c
+++ gcc/gcc/tree-stdarg.c
@@ -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;
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
@@ -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: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -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-*-*)
Index: gcc/gcc/config/i386/cross-stdarg.h
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/cross-stdarg.h
@@ -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 */
=

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention  switching and  support vaarg.
  2008-07-01 12:32       ` Kai Tietz
@ 2008-07-01 19:08         ` Ralf Wildenhues
  2008-07-01 19:18           ` Kai Tietz
  2009-02-18  7:41         ` H.J. Lu
  1 sibling, 1 reply; 25+ messages in thread
From: Ralf Wildenhues @ 2008-07-01 19:08 UTC (permalink / raw)
  To: Kai Tietz
  Cc: Richard Guenther, GCC Patches, Jan Hubicka, Jan Hubicka,
	Kai Tietz, Mark Mitchell

Hello Kai,

I have almost no knowledge about the specific code you're working on,
so please don't take the following general comments (plus obligatory
typo nits ;-) as a full-fledged review, but with some grains of salt:

* Kai Tietz wrote on Tue, Jul 01, 2008 at 02:19:01PM CEST:
> --- gcc.orig/gcc/config/i386/i386.c
> +++ gcc/gcc/config/i386/i386.c

> +/* This function returns the calling abi specific va_list type node.
> +   If FNDECL is NULL_TREE, it returns the current cfun specific
> +   va_list type, otherwise the the fndecl specific type.  */

s/the the/see the/  ?

> +tree
> +ix86_fn_abi_va_list (tree fndecl ATTRIBUTE_UNUSED)


> +/* This is used in function c_common_nodes_and_builtins ()
> +   to iterate through the target specific builtin types for va_list. The
> +   variable IDX is used as iterator. PNAME is a pointer
> +   to a 'const char *' and PTYPE is a pointer to a 'tree' type.
> +   The arguments PNAME and PTYPE are used to store the result and are set
> +   to the name of the va_list builtin type and its internal type.
> +   If the return value is zero, then there is no element for this index.
> +   Otherwise the IDX should be increased for the next call of this.
> +   Note, do not iterate a base builtins name like __builtin_va_list.  */
> +
> +int
> +ix86_enum_va_list (int idx, const char **pname, tree *ptree)

The comment before this function strikes me as odd, for several reasons:
First, it's longer than the function itself (not a problem in itself).
Then you start off with where this function is used, rather than what
the function does.  Isn't the most important bit of information what it
does?  Who is going to remember to adjust the comment if the function is
used in another dozen places later?  For denoting a function, it is not
really necessary to add 'function' before it, nor '()' afterwards (in
fact, the GNU Coding Standards recommend against the latter).

Next, there is no need to state the type of the arguments: that much is
clear from the function declaration.  PTYPE is a misnomer.  It seems to
me "builtins" in the last sentence is lacking an apostrophe.

Taken together, this is how I may have written the comment (beware, I
don't know exactly what this code actually does):

  /* 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.
  */

(Or even dropping the last sentence.)

> +  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;
> +}
> +


> --- gcc.orig/gcc/tree-sra.c
> +++ gcc/gcc/tree-sra.c
> @@ -308,6 +308,26 @@ sra_type_can_be_decomposed_p (tree type)
>    return false;
>  }
>  
> +/* Returns true, if the TYPE is one of the avalable va_list types.

No need for comma.
s/avalable/available/

> +   Otherwise it returns false.
> +   Note, that for multiple calling conventions there can be more
> +   then just one va_list type be present.  */

s/then/than/
s/be present/present/

> --- gcc.orig/gcc/doc/tm.texi
> +++ gcc/gcc/doc/tm.texi
> @@ -4187,6 +4187,18 @@ This hook returns a type node for @code{

> +@defmac TARGET_ENUM_VA_LIST (@var{IDX}, @var{PNAME}, @var{PTYPE})

How come the @var names are written in caps?  Several more instances
below.

> +This target macro is used in function @code{c_common_nodes_and_builtins}
> +to iterate through the target specific builtin types for va_list.

Hmm.  Here, the description (which is similar to the one before
ix86_enum_va_list) strikes me as better fitting, and I see that 
a similar style is used elsewhere in the manual.  Still, listing
first where some macro is used rather than what it does, strikes
me as odd, unless that one specific usage is the only one possible.

> 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. $$$$

The $$$$ looks spurious to me.

> +@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

Cheers,
Ralf

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-01 19:08         ` Ralf Wildenhues
@ 2008-07-01 19:18           ` Kai Tietz
  2008-07-03 13:21             ` Richard Guenther
  0 siblings, 1 reply; 25+ messages in thread
From: Kai Tietz @ 2008-07-01 19:18 UTC (permalink / raw)
  To: Ralf Wildenhues, Kai Tietz, Richard Guenther, GCC Patches,
	Jan Hubicka, Jan Hubicka, Kai Tietz, Mark Mitchell

[-- Attachment #1: Type: text/plain, Size: 259 bytes --]

Ralf,

I attached the new version of the patch. It contains the comment and
documentation changes you suggested.

Thank and cheers,
Kai

-- 
| (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: callabi.txt --]
[-- Type: text/plain, Size: 40093 bytes --]

Index: gcc/gcc/builtins.c
===================================================================
--- gcc.orig/gcc/builtins.c
+++ gcc/gcc/builtins.c
@@ -4625,18 +4625,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);
 	}
     }
@@ -4649,7 +4650,7 @@ stabilize_va_list (tree valist, int need
 	  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;
 	}
@@ -4670,6 +4671,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.  */
 
@@ -4825,33 +4862,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;
@@ -4859,7 +4881,7 @@ gimplify_va_arg_expr (tree *expr_p, tree
 
   /* 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;
@@ -4891,15 +4913,15 @@ gimplify_va_arg_expr (tree *expr_p, tree
     {
       /* 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);
@@ -4947,9 +4969,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);
     }
@@ -4960,8 +4984,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);
@@ -4969,10 +4993,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: gcc/gcc/c-common.c
===================================================================
--- gcc.orig/gcc/c-common.c
+++ gcc/gcc/c-common.c
@@ -3964,6 +3964,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: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h
+++ gcc/gcc/config/i386/i386-protos.h
@@ -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: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -1716,6 +1716,10 @@ unsigned int ix86_preferred_stack_bounda
 /* 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 fntyp
       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;
@@ -5173,13 +5173,16 @@ ix86_struct_value_rtx (tree type, int in
 \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);
@@ -5215,6 +5218,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
@@ -5370,13 +5400,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);
@@ -5449,10 +5480,11 @@ ix86_gimplify_va_arg (tree valist, tree 
   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);
@@ -20188,6 +20220,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)
 {
@@ -20239,6 +20320,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
@@ -23054,6 +23137,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
@@ -25863,6 +25994,10 @@ static const struct attribute_spec ix86_
 #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 }
 };
 
@@ -25890,6 +26025,104 @@ x86_builtin_vectorization_cost (bool run
     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
@@ -26018,6 +26251,12 @@ x86_builtin_vectorization_cost (bool run
 #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: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h
+++ gcc/gcc/config/i386/i386.h
@@ -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: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -4187,6 +4187,18 @@ This hook returns a type node for @code{
 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
 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: gcc/gcc/expr.h
===================================================================
--- gcc.orig/gcc/expr.h
+++ gcc/gcc/expr.h
@@ -342,6 +342,9 @@ extern rtx emit_store_flag_force (rtx, e
 /* 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: gcc/gcc/target-def.h
===================================================================
--- gcc.orig/gcc/target-def.h
+++ gcc/gcc/target-def.h
@@ -520,6 +520,8 @@
 #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
@@ -820,6 +822,8 @@
   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: gcc/gcc/target.h
===================================================================
--- gcc.orig/gcc/target.h
+++ gcc/gcc/target.h
@@ -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: gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
@@ -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;
+}
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
@@ -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;
+}
Index: gcc/gcc/tree-sra.c
===================================================================
--- gcc.orig/gcc/tree-sra.c
+++ gcc/gcc/tree-sra.c
@@ -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: gcc/gcc/tree-ssa-ccp.c
===================================================================
--- gcc.orig/gcc/tree-ssa-ccp.c
+++ gcc/gcc/tree-ssa-ccp.c
@@ -2748,17 +2748,19 @@ optimize_stack_restore (basic_block bb, 
 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: gcc/gcc/tree-stdarg.c
===================================================================
--- gcc.orig/gcc/tree-stdarg.c
+++ gcc/gcc/tree-stdarg.c
@@ -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;
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
@@ -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: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -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-*-*)
Index: gcc/gcc/config/i386/cross-stdarg.h
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/cross-stdarg.h
@@ -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 */

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-01 19:18           ` Kai Tietz
@ 2008-07-03 13:21             ` Richard Guenther
  2008-07-03 14:18               ` Kai Tietz
  2008-07-03 20:28               ` Ian Lance Taylor
  0 siblings, 2 replies; 25+ messages in thread
From: Richard Guenther @ 2008-07-03 13:21 UTC (permalink / raw)
  To: Kai Tietz
  Cc: Ralf Wildenhues, Kai Tietz, GCC Patches, Jan Hubicka,
	Jan Hubicka, Mark Mitchell

On Tue, Jul 1, 2008 at 9:07 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
> Ralf,
>
> I attached the new version of the patch. It contains the comment and
> documentation changes you suggested.

Much better.  Please move the tests to gcc.target/x86_64/abi.

The middle-end parts are ok if the c-common.c part is approved and
the backend parts are approved.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and  support vaarg.
  2008-07-03 13:21             ` Richard Guenther
@ 2008-07-03 14:18               ` Kai Tietz
  2008-07-03 15:10                 ` Richard Guenther
  2008-07-03 20:28               ` Ian Lance Taylor
  1 sibling, 1 reply; 25+ messages in thread
From: Kai Tietz @ 2008-07-03 14:18 UTC (permalink / raw)
  To: Richard Guenther
  Cc: GCC Patches, Jan Hubicka, Jan Hubicka, Kai Tietz, Mark Mitchell,
	Ralf Wildenhues

"Richard Guenther" <richard.guenther@gmail.com> wrote on 03.07.2008 
15:06:31:

> On Tue, Jul 1, 2008 at 9:07 PM, Kai Tietz <ktietz70@googlemail.com> 
wrote:
> > Ralf,
> >
> > I attached the new version of the patch. It contains the comment and
> > documentation changes you suggested.
> 
> Much better.  Please move the tests to gcc.target/x86_64/abi.

The problem I see here, is that the tests have to run on x86_64-*-* with 
lp64 and on x86_64-*-mingw* with llp64. If I move these tests out to 
gcc.target the w64 case isn't tested anymore.
 
> The middle-end parts are ok if the c-common.c part is approved and
> the backend parts are approved.
Honza, Mark: Could you review this patch?

Thanks,
Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-03 14:18               ` Kai Tietz
@ 2008-07-03 15:10                 ` Richard Guenther
  0 siblings, 0 replies; 25+ messages in thread
From: Richard Guenther @ 2008-07-03 15:10 UTC (permalink / raw)
  To: Kai Tietz
  Cc: GCC Patches, Jan Hubicka, Jan Hubicka, Kai Tietz, Mark Mitchell,
	Ralf Wildenhues

On Thu, Jul 3, 2008 at 4:09 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> "Richard Guenther" <richard.guenther@gmail.com> wrote on 03.07.2008
> 15:06:31:
>
>> On Tue, Jul 1, 2008 at 9:07 PM, Kai Tietz <ktietz70@googlemail.com>
> wrote:
>> > Ralf,
>> >
>> > I attached the new version of the patch. It contains the comment and
>> > documentation changes you suggested.
>>
>> Much better.  Please move the tests to gcc.target/x86_64/abi.
>
> The problem I see here, is that the tests have to run on x86_64-*-* with
> lp64 and on x86_64-*-mingw* with llp64. If I move these tests out to
> gcc.target the w64 case isn't tested anymore.

Ok, then leave them where they are.  Thanks for trying.

Richard.

>> The middle-end parts are ok if the c-common.c part is approved and
>> the backend parts are approved.
> Honza, Mark: Could you review this patch?
>
> Thanks,
> Kai
>
> |  (\_/)  This is Bunny. Copy and paste Bunny
> | (='.'=) into your signature to help him gain
> | (")_(") world domination.
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-03 13:21             ` Richard Guenther
  2008-07-03 14:18               ` Kai Tietz
@ 2008-07-03 20:28               ` Ian Lance Taylor
  2008-07-03 20:49                 ` Jan Hubicka
  1 sibling, 1 reply; 25+ messages in thread
From: Ian Lance Taylor @ 2008-07-03 20:28 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Kai Tietz, Ralf Wildenhues, Kai Tietz, GCC Patches, Jan Hubicka,
	Jan Hubicka, Mark Mitchell

"Richard Guenther" <richard.guenther@gmail.com> writes:

> On Tue, Jul 1, 2008 at 9:07 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>> Ralf,
>>
>> I attached the new version of the patch. It contains the comment and
>> documentation changes you suggested.
>
> Much better.  Please move the tests to gcc.target/x86_64/abi.
>
> The middle-end parts are ok if the c-common.c part is approved and
> the backend parts are approved.

The patch to c-common.c is OK.

Someone else will need to approve the changes to the i386 backend, I
don't know the details of this.

Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-03 20:28               ` Ian Lance Taylor
@ 2008-07-03 20:49                 ` Jan Hubicka
  2008-07-04  9:11                   ` Kai Tietz
  0 siblings, 1 reply; 25+ messages in thread
From: Jan Hubicka @ 2008-07-03 20:49 UTC (permalink / raw)
  To: Ian Lance Taylor
  Cc: Richard Guenther, Kai Tietz, Ralf Wildenhues, Kai Tietz,
	GCC Patches, Jan Hubicka, Jan Hubicka, Mark Mitchell

> "Richard Guenther" <richard.guenther@gmail.com> writes:
> 
> > On Tue, Jul 1, 2008 at 9:07 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
> >> Ralf,
> >>
> >> I attached the new version of the patch. It contains the comment and
> >> documentation changes you suggested.
> >
> > Much better.  Please move the tests to gcc.target/x86_64/abi.
> >
> > The middle-end parts are ok if the c-common.c part is approved and
> > the backend parts are approved.
> 
> The patch to c-common.c is OK.
> 
> Someone else will need to approve the changes to the i386 backend, I
> don't know the details of this.

I already approved those.  For some reason it didn't seem to got into
list.

Honza
> 
> Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and  support vaarg.
  2008-07-03 20:49                 ` Jan Hubicka
@ 2008-07-04  9:11                   ` Kai Tietz
  2008-07-04 12:30                     ` Richard Guenther
  0 siblings, 1 reply; 25+ messages in thread
From: Kai Tietz @ 2008-07-04  9:11 UTC (permalink / raw)
  To: Jan Hubicka
  Cc: GCC Patches, Jan Hubicka, Ian Lance Taylor, Jan Hubicka,
	Kai Tietz, Mark Mitchell, Ralf Wildenhues, Richard Guenther

Hello,

Committed at revision 137452.

Honza, could you add the news entry for it?

Thank you all for reviewing,
Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-04  9:11                   ` Kai Tietz
@ 2008-07-04 12:30                     ` Richard Guenther
  2008-07-04 12:54                       ` Kai Tietz
  0 siblings, 1 reply; 25+ messages in thread
From: Richard Guenther @ 2008-07-04 12:30 UTC (permalink / raw)
  To: Kai Tietz
  Cc: Jan Hubicka, GCC Patches, Jan Hubicka, Ian Lance Taylor,
	Kai Tietz, Mark Mitchell, Ralf Wildenhues

On Fri, Jul 4, 2008 at 10:17 AM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> Hello,
>
> Committed at revision 137452.
>
> Honza, could you add the news entry for it?
>
> Thank you all for reviewing,

This broke x86_64-linux badly.  Please revert the patch and sort out the
problems.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and  support vaarg.
  2008-07-04 12:30                     ` Richard Guenther
@ 2008-07-04 12:54                       ` Kai Tietz
  2008-07-04 13:13                         ` Richard Guenther
  0 siblings, 1 reply; 25+ messages in thread
From: Kai Tietz @ 2008-07-04 12:54 UTC (permalink / raw)
  To: Richard Guenther
  Cc: GCC Patches, Jan Hubicka, Ian Lance Taylor, Jan Hubicka,
	Kai Tietz, Mark Mitchell, Ralf Wildenhues

"Richard Guenther" <richard.guenther@gmail.com> wrote on 04.07.2008 
14:28:20:

> On Fri, Jul 4, 2008 at 10:17 AM, Kai Tietz <Kai.Tietz@onevision.com> 
wrote:
> > Hello,
> >
> > Committed at revision 137452.
> >
> > Honza, could you add the news entry for it?
> >
> > Thank you all for reviewing,
> 
> This broke x86_64-linux badly.  Please revert the patch and sort out the
> problems.

Ok, I revert the patch. Where is the problem? I build a cross linux64 
compiler and didn't noticed an ICE.

Cheers,
Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-04 12:54                       ` Kai Tietz
@ 2008-07-04 13:13                         ` Richard Guenther
  2008-07-04 13:19                           ` Kai Tietz
  2008-07-04 13:24                           ` Diego Novillo
  0 siblings, 2 replies; 25+ messages in thread
From: Richard Guenther @ 2008-07-04 13:13 UTC (permalink / raw)
  To: Kai Tietz
  Cc: GCC Patches, Jan Hubicka, Ian Lance Taylor, Jan Hubicka,
	Kai Tietz, Mark Mitchell, Ralf Wildenhues

On Fri, Jul 4, 2008 at 2:49 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> "Richard Guenther" <richard.guenther@gmail.com> wrote on 04.07.2008
> 14:28:20:
>
>> On Fri, Jul 4, 2008 at 10:17 AM, Kai Tietz <Kai.Tietz@onevision.com>
> wrote:
>> > Hello,
>> >
>> > Committed at revision 137452.
>> >
>> > Honza, could you add the news entry for it?
>> >
>> > Thank you all for reviewing,
>>
>> This broke x86_64-linux badly.  Please revert the patch and sort out the
>> problems.
>
> Ok, I revert the patch. Where is the problem? I build a cross linux64
> compiler and didn't noticed an ICE.

libgcov doesn't build, probably due to the same issue as all va_arg
testcases:

/space/rguenther/src/svn/trunk/gcc/testsuite/gcc.c-torture/execute/20000519-1.c:
In function 'bar':^M
/space/rguenther/src/svn/trunk/gcc/testsuite/gcc.c-torture/execute/20000519-1.c:9:
error: first argument to 'va_arg' not of type 'va_list'^M

and we ICE during expansion sometimes due to a NULL type in an
INDIRECT_REF

FAIL: gcc.c-torture/execute/vfprintf-1.c compilation,  -O0  (internal
compiler error)
...
FAIL: gcc.c-torture/execute/vprintf-chk-1.c compilation,  -O0
(internal compiler error)
...

(this is just what I saw from the execute torture, the gcov build failure
is reported from Diego)

Richard.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and  support vaarg.
  2008-07-04 13:13                         ` Richard Guenther
@ 2008-07-04 13:19                           ` Kai Tietz
  2008-07-04 13:24                           ` Diego Novillo
  1 sibling, 0 replies; 25+ messages in thread
From: Kai Tietz @ 2008-07-04 13:19 UTC (permalink / raw)
  To: Richard Guenther
  Cc: GCC Patches, Jan Hubicka, Ian Lance Taylor, Jan Hubicka,
	Kai Tietz, Mark Mitchell, Ralf Wildenhues

[-- Attachment #1: Type: text/plain, Size: 648 bytes --]

Richard,

"Richard Guenther" <richard.guenther@gmail.com> wrote on 04.07.2008 
14:54:17:

> and we ICE during expansion sometimes due to a NULL type in an
> INDIRECT_REF

Ah, the bad feeling about the NULL_TREE in stabilize_va_list () ...
I added code to resolve in targetm.canonical_va_list_type the indirect 
reference (and the address to va_list type). Could you please test the 
attached patch for linux, I think this should solve the problem.
Sadly, I have no access to a linux64 box from work.

Thanks in advance,
Kai



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

[-- Attachment #2: callabi_tstcase.txt --]
[-- Type: text/plain, Size: 41699 bytes --]

Index: gcc/gcc/builtins.c
===================================================================
--- gcc.orig/gcc/builtins.c
+++ gcc/gcc/builtins.c
@@ -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 need
 	  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,47 @@ 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;
+
+  if (INDIRECT_REF_P (type))
+    type = TREE_TYPE (type);
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type))
+    type = TREE_TYPE (type);
+
+  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 +4865,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 +4884,7 @@ gimplify_va_arg_expr (tree *expr_p, tree
 
   /* 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 +4916,15 @@ gimplify_va_arg_expr (tree *expr_p, tree
     {
       /* 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 +4972,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 +4987,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 +4996,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: gcc/gcc/c-common.c
===================================================================
--- gcc.orig/gcc/c-common.c
+++ gcc/gcc/c-common.c
@@ -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: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h
+++ gcc/gcc/config/i386/i386-protos.h
@@ -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: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -1716,6 +1716,10 @@ unsigned int ix86_preferred_stack_bounda
 /* 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 fntyp
       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 in
 \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 
   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_
 #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,111 @@ x86_builtin_vectorization_cost (bool run
     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;
+
+  /* Resolve references and pointers to va_list type.  */
+  if (INDIRECT_REF_P (type))
+    type = TREE_TYPE (type);
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type))
+    type = TREE_TYPE (type);
+
+  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 +26301,12 @@ x86_builtin_vectorization_cost (bool run
 #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: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h
+++ gcc/gcc/config/i386/i386.h
@@ -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: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -4187,6 +4187,18 @@ This hook returns a type node for @code{
 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
 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: gcc/gcc/expr.h
===================================================================
--- gcc.orig/gcc/expr.h
+++ gcc/gcc/expr.h
@@ -342,6 +342,9 @@ extern rtx emit_store_flag_force (rtx, e
 /* 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: gcc/gcc/target-def.h
===================================================================
--- gcc.orig/gcc/target-def.h
+++ gcc/gcc/target-def.h
@@ -520,6 +520,8 @@
 #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
@@ -820,6 +822,8 @@
   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: gcc/gcc/target.h
===================================================================
--- gcc.orig/gcc/target.h
+++ gcc/gcc/target.h
@@ -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: gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
@@ -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;
+}
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
@@ -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;
+}
Index: gcc/gcc/tree-sra.c
===================================================================
--- gcc.orig/gcc/tree-sra.c
+++ gcc/gcc/tree-sra.c
@@ -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: gcc/gcc/tree-ssa-ccp.c
===================================================================
--- gcc.orig/gcc/tree-ssa-ccp.c
+++ gcc/gcc/tree-ssa-ccp.c
@@ -2748,17 +2748,19 @@ optimize_stack_restore (basic_block bb, 
 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: gcc/gcc/tree-stdarg.c
===================================================================
--- gcc.orig/gcc/tree-stdarg.c
+++ gcc/gcc/tree-stdarg.c
@@ -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;
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
@@ -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: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -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-*-*)
Index: gcc/gcc/config/i386/cross-stdarg.h
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/cross-stdarg.h
@@ -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 */
=

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching   and support vaarg.
  2008-07-04 13:13                         ` Richard Guenther
  2008-07-04 13:19                           ` Kai Tietz
@ 2008-07-04 13:24                           ` Diego Novillo
  2008-07-04 13:45                             ` Kai Tietz
  1 sibling, 1 reply; 25+ messages in thread
From: Diego Novillo @ 2008-07-04 13:24 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Kai Tietz, GCC Patches, Jan Hubicka, Ian Lance Taylor,
	Jan Hubicka, Kai Tietz, Mark Mitchell, Ralf Wildenhues

On Fri, Jul 4, 2008 at 08:54, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Fri, Jul 4, 2008 at 2:49 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
>> "Richard Guenther" <richard.guenther@gmail.com> wrote on 04.07.2008
>> 14:28:20:
>>
>>> On Fri, Jul 4, 2008 at 10:17 AM, Kai Tietz <Kai.Tietz@onevision.com>
>> wrote:
>>> > Hello,
>>> >
>>> > Committed at revision 137452.
>>> >
>>> > Honza, could you add the news entry for it?
>>> >
>>> > Thank you all for reviewing,
>>>
>>> This broke x86_64-linux badly.  Please revert the patch and sort out the
>>> problems.
>>
>> Ok, I revert the patch. Where is the problem? I build a cross linux64
>> compiler and didn't noticed an ICE.
>
> libgcov doesn't build, probably due to the same issue as all va_arg
> testcases:
>
> /space/rguenther/src/svn/trunk/gcc/testsuite/gcc.c-torture/execute/20000519-1.c:
> In function 'bar':^M
> /space/rguenther/src/svn/trunk/gcc/testsuite/gcc.c-torture/execute/20000519-1.c:9:
> error: first argument to 'va_arg' not of type 'va_list'^M
>
> and we ICE during expansion sometimes due to a NULL type in an
> INDIRECT_REF
>
> FAIL: gcc.c-torture/execute/vfprintf-1.c compilation,  -O0  (internal
> compiler error)
> ...
> FAIL: gcc.c-torture/execute/vprintf-chk-1.c compilation,  -O0
> (internal compiler error)
> ...
>
> (this is just what I saw from the execute torture, the gcov build failure
> is reported from Diego)

Full build log at
http://airs.com/dnovillo/spec2000/spec2000.mule/gcc/log/20080704/build-20080704.log.gz

[ ... ]
/home/dnovillo/perf/sbox/gcc/local.x86_64/bld/./gcc/xgcc
-B/home/dnovillo/perf/sbox/gcc/local.x86_64/bld/./gcc/
-B/home/dnovillo/perf/sbox/gcc/local.x86_64/inst/x86_64-unknown-linux-gnu/bin/
-B/home/dnovillo/perf/sbox/gcc/local.x86_64/inst/x86_64-unknown-linux-gnu/lib/
-isystem /home/dnovillo/perf/sbox/gcc/local.x86_64/inst/x86_64-unknown-linux-gnu/include
-isystem /home/dnovillo/perf/sbox/gcc/local.x86_64/inst/x86_64-unknown-linux-gnu/sys-include
-g -O2 -O2  -g -O2 -DIN_GCC   -W -Wall -Wwrite-strings
-Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wc++-compat
-Wold-style-definition  -isystem ./include  -fPIC -g
-DHAVE_GTHR_DEFAULT -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED   -I. -I.
-I../.././gcc -I/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc
-I/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/.
-I/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/../gcc
-I/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/../include
-I/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/config/libbid
-DENABLE_DECIMAL_BID_FORMAT -DHAVE_CC_TLS -DUSE_TLS -o _gcov_execl.o
-MT _gcov_execl.o -MD -MP -MF _gcov_execl.dep -DL_gcov_execl -c
/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/../gcc/libgcov.c
/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/../gcc/libgcov.c:
In function '__gcov_execl':
/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/../gcc/libgcov.c:843:
warning: cast discards qualifiers from pointer target type
/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/../gcc/libgcov.c:838:
error: first argument to 'va_arg' not of type 'va_list'
/home/dnovillo/perf/sbox/gcc/local.x86_64/src/libgcc/../gcc/libgcov.c:845:
error: first argument to 'va_arg' not of type 'va_list'
make[3]: *** [_gcov_execl.o] Error 1
make[3]: Leaving directory
`/usr/local/google/dnovillo/perf/sbox/gcc/local.x86_64/bld/x86_64-unknown-linux-gnu/libgcc'
make[2]: *** [all-stage1-target-libgcc] Error 2
make[2]: Leaving directory
`/usr/local/google/dnovillo/perf/sbox/gcc/local.x86_64/bld'
make[1]: *** [stage1-bubble] Error 2
make[1]: Leaving directory
`/usr/local/google/dnovillo/perf/sbox/gcc/local.x86_64/bld'
make: *** [bootstrap] Error 2


Diego.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching  and  support vaarg.
  2008-07-04 13:24                           ` Diego Novillo
@ 2008-07-04 13:45                             ` Kai Tietz
  2008-07-04 19:27                               ` Richard Guenther
  0 siblings, 1 reply; 25+ messages in thread
From: Kai Tietz @ 2008-07-04 13:45 UTC (permalink / raw)
  To: Diego Novillo
  Cc: GCC Patches, Jan Hubicka, Ian Lance Taylor, Jan Hubicka,
	Kai Tietz, Mark Mitchell, Ralf Wildenhues, Richard Guenther

[-- Attachment #1: Type: text/plain, Size: 350 bytes --]

Diego,

I missed two )'s in the prior patch file.
I tested it by adding an assert for canonical_va_list_type in builtins.c:
stabilize_va_list() and regression tested it via linux64 cross and for 
w64.

Thanks in advance,
Kai



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.


[-- Attachment #2: callabi_tstcase.txt --]
[-- Type: text/plain, Size: 41728 bytes --]

Index: gcc/gcc/builtins.c
===================================================================
--- gcc.orig/gcc/builtins.c
+++ gcc/gcc/builtins.c
@@ -4623,18 +4623,22 @@ 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));
+
+  gcc_assert (vatype != NULL_TREE);
+
+  if (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 +4651,7 @@ stabilize_va_list (tree valist, int need
 	  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 +4672,47 @@ 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;
+
+  if (INDIRECT_REF_P (type))
+    type = TREE_TYPE (type);
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
+    type = TREE_TYPE (type);
+
+  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 +4868,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 +4887,7 @@ gimplify_va_arg_expr (tree *expr_p, tree
 
   /* 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 +4919,15 @@ gimplify_va_arg_expr (tree *expr_p, tree
     {
       /* 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 +4975,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 +4990,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 +4999,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: gcc/gcc/c-common.c
===================================================================
--- gcc.orig/gcc/c-common.c
+++ gcc/gcc/c-common.c
@@ -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: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h
+++ gcc/gcc/config/i386/i386-protos.h
@@ -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: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -1716,6 +1716,10 @@ unsigned int ix86_preferred_stack_bounda
 /* 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 fntyp
       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 in
 \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 
   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_
 #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,111 @@ x86_builtin_vectorization_cost (bool run
     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;
+
+  /* Resolve references and pointers to va_list type.  */
+  if (INDIRECT_REF_P (type))
+    type = TREE_TYPE (type);
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
+    type = TREE_TYPE (type);
+
+  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 +26301,12 @@ x86_builtin_vectorization_cost (bool run
 #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: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h
+++ gcc/gcc/config/i386/i386.h
@@ -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: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -4187,6 +4187,18 @@ This hook returns a type node for @code{
 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
 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: gcc/gcc/expr.h
===================================================================
--- gcc.orig/gcc/expr.h
+++ gcc/gcc/expr.h
@@ -342,6 +342,9 @@ extern rtx emit_store_flag_force (rtx, e
 /* 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: gcc/gcc/target-def.h
===================================================================
--- gcc.orig/gcc/target-def.h
+++ gcc/gcc/target-def.h
@@ -520,6 +520,8 @@
 #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
@@ -820,6 +822,8 @@
   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: gcc/gcc/target.h
===================================================================
--- gcc.orig/gcc/target.h
+++ gcc/gcc/target.h
@@ -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: gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
@@ -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;
+}
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
@@ -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;
+}
Index: gcc/gcc/tree-sra.c
===================================================================
--- gcc.orig/gcc/tree-sra.c
+++ gcc/gcc/tree-sra.c
@@ -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: gcc/gcc/tree-ssa-ccp.c
===================================================================
--- gcc.orig/gcc/tree-ssa-ccp.c
+++ gcc/gcc/tree-ssa-ccp.c
@@ -2748,17 +2748,19 @@ optimize_stack_restore (basic_block bb, 
 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: gcc/gcc/tree-stdarg.c
===================================================================
--- gcc.orig/gcc/tree-stdarg.c
+++ gcc/gcc/tree-stdarg.c
@@ -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;
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
@@ -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: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -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-*-*)
Index: gcc/gcc/config/i386/cross-stdarg.h
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/cross-stdarg.h
@@ -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 */
=

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-04 13:45                             ` Kai Tietz
@ 2008-07-04 19:27                               ` Richard Guenther
  2008-07-05 17:39                                 ` Kai Tietz
  0 siblings, 1 reply; 25+ messages in thread
From: Richard Guenther @ 2008-07-04 19:27 UTC (permalink / raw)
  To: Kai Tietz
  Cc: Diego Novillo, GCC Patches, Jan Hubicka, Ian Lance Taylor,
	Jan Hubicka, Kai Tietz, Mark Mitchell, Ralf Wildenhues

On Fri, Jul 4, 2008 at 3:36 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> Diego,
>
> I missed two )'s in the prior patch file.
> I tested it by adding an assert for canonical_va_list_type in builtins.c:
> stabilize_va_list() and regression tested it via linux64 cross and for
> w64.

Doesn't work.

/space/rguenther/obj/./gcc/xgcc -B/space/rguenther/obj/./gcc/
-B/usr/local/x86_64-unknown-linux-gnu/bin/
-B/usr/local/x86_64-unknown-linux-gnu/lib/ -isystem
/usr/local/x86_64-unknown-linux-gnu/include -isystem
/usr/local/x86_64-unknown-linux-gnu/sys-include -g -O2 -O2  -g -O2
-DIN_GCC   -W -Wall -Wwrite-strings -Wstrict-prototypes
-Wmissing-prototypes -Wcast-qual -Wc++-compat -Wold-style-definition
-isystem ./include  -fPIC -g -DHAVE_GTHR_DEFAULT -DIN_LIBGCC2
-D__GCC_FLOAT_NOT_NEEDED   -I. -I. -I../.././gcc
-I../../../trunk/libgcc -I../../../trunk/libgcc/.
-I../../../trunk/libgcc/../gcc -I../../../trunk/libgcc/../include
-I../../../trunk/libgcc/config/libbid -DENABLE_DECIMAL_BID_FORMAT
-DHAVE_CC_TLS -DUSE_TLS -o _gcov_execl.o -MT _gcov_execl.o -MD -MP -MF
_gcov_execl.dep -DL_gcov_execl -c
../../../trunk/libgcc/../gcc/libgcov.c
../../../trunk/libgcc/../gcc/libgcov.c: In function '__gcov_execl':
../../../trunk/libgcc/../gcc/libgcov.c:843: warning: cast discards
qualifiers from pointer target type
../../../trunk/libgcc/../gcc/libgcov.c:838: error: first argument to
'va_arg' not of type 'va_list'
../../../trunk/libgcc/../gcc/libgcov.c:845: error: first argument to
'va_arg' not of type 'va_list'
make[3]: *** [_gcov_execl.o] Error 1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-04 19:27                               ` Richard Guenther
@ 2008-07-05 17:39                                 ` Kai Tietz
  2008-07-06 14:47                                   ` Richard Guenther
  2008-07-12  8:09                                   ` Bob Wilson
  0 siblings, 2 replies; 25+ messages in thread
From: Kai Tietz @ 2008-07-05 17:39 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Kai Tietz, Diego Novillo, GCC Patches, Jan Hubicka,
	Ian Lance Taylor, Jan Hubicka, Mark Mitchell, Ralf Wildenhues

[-- Attachment #1: Type: text/plain, Size: 2406 bytes --]

Hello Richard,

2008/7/4 Richard Guenther <richard.guenther@gmail.com>:
> On Fri, Jul 4, 2008 at 3:36 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
>> Diego,
>>
>> I missed two )'s in the prior patch file.
>> I tested it by adding an assert for canonical_va_list_type in builtins.c:
>> stabilize_va_list() and regression tested it via linux64 cross and for
>> w64.
>
> Doesn't work.
>
> /space/rguenther/obj/./gcc/xgcc -B/space/rguenther/obj/./gcc/
> -B/usr/local/x86_64-unknown-linux-gnu/bin/
> -B/usr/local/x86_64-unknown-linux-gnu/lib/ -isystem
> /usr/local/x86_64-unknown-linux-gnu/include -isystem
> /usr/local/x86_64-unknown-linux-gnu/sys-include -g -O2 -O2  -g -O2
> -DIN_GCC   -W -Wall -Wwrite-strings -Wstrict-prototypes
> -Wmissing-prototypes -Wcast-qual -Wc++-compat -Wold-style-definition
> -isystem ./include  -fPIC -g -DHAVE_GTHR_DEFAULT -DIN_LIBGCC2
> -D__GCC_FLOAT_NOT_NEEDED   -I. -I. -I../.././gcc
> -I../../../trunk/libgcc -I../../../trunk/libgcc/.
> -I../../../trunk/libgcc/../gcc -I../../../trunk/libgcc/../include
> -I../../../trunk/libgcc/config/libbid -DENABLE_DECIMAL_BID_FORMAT
> -DHAVE_CC_TLS -DUSE_TLS -o _gcov_execl.o -MT _gcov_execl.o -MD -MP -MF
> _gcov_execl.dep -DL_gcov_execl -c
> ../../../trunk/libgcc/../gcc/libgcov.c
> ../../../trunk/libgcc/../gcc/libgcov.c: In function '__gcov_execl':
> ../../../trunk/libgcc/../gcc/libgcov.c:843: warning: cast discards
> qualifiers from pointer target type
> ../../../trunk/libgcc/../gcc/libgcov.c:838: error: first argument to
> 'va_arg' not of type 'va_list'
> ../../../trunk/libgcc/../gcc/libgcov.c:845: error: first argument to
> 'va_arg' not of type 'va_list'
> make[3]: *** [_gcov_execl.o] Error 1
>

I found the problem. It is related to the fact, that the native
va_list type for x86_64 is a structure. In earlier patches the type
was generated twice by the helper function
x86_build_builtin_va_list_abi. This lead to the problem, that there
are two record types use, which brings the gimple to fail.
Additionally the canonical_va_list_type method needs to handle
va_list_type_node, too. Additionally it has to dereference pointers to
va_list types.

So here is the new version of this patch. I bootstraped it on linux64
and tested the new callabi testcases.

Is this patch ok to apply?

Cheers,
Kai

-- 
| (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: callabi.txt --]
[-- Type: text/plain, Size: 42075 bytes --]

Index: gcc/gcc/builtins.c
===================================================================
--- gcc.orig/gcc/builtins.c
+++ gcc/gcc/builtins.c
@@ -4623,18 +4623,22 @@ 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));
+
+  gcc_assert (vatype != NULL_TREE);
+
+  if (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 +4651,7 @@ stabilize_va_list (tree valist, int need
 	  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 +4672,47 @@ 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;
+
+  if (INDIRECT_REF_P (type))
+    type = TREE_TYPE (type);
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
+    type = TREE_TYPE (type);
+
+  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 +4868,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 +4887,7 @@ gimplify_va_arg_expr (tree *expr_p, tree
 
   /* 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 +4919,15 @@ gimplify_va_arg_expr (tree *expr_p, tree
     {
       /* 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 +4975,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 +4990,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 +4999,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: gcc/gcc/c-common.c
===================================================================
--- gcc.orig/gcc/c-common.c
+++ gcc/gcc/c-common.c
@@ -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: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h
+++ gcc/gcc/config/i386/i386-protos.h
@@ -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: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -1716,6 +1716,10 @@ unsigned int ix86_preferred_stack_bounda
 /* 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)
@@ -3201,7 +3204,7 @@ ix86_handle_cconv_attribute (tree *node,
   if (TARGET_64BIT)
     {
       /* Do not warn when emulating the MS ABI.  */
-      if (TREE_CODE (*node) != FUNCTION_TYPE || !ix86_function_type_abi (*node))
+      if (TREE_CODE (*node) != FUNCTION_TYPE || ix86_function_type_abi (*node)!=MS_ABI)
 	warning (OPT_Wattributes, "%qs attribute ignored",
 	         IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
@@ -3604,9 +3607,6 @@ ix86_function_type_abi (const_tree fntyp
       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 in
 \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,51 @@ 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;
+      if (DEFAULT_ABI == MS_ABI)
+        {
+          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;
+        }
+      else
+        {
+          t = ret;
+          if (TREE_CODE (t) != RECORD_TYPE)
+            t = build_variant_type_copy (t);
+          sysv_va_list_type_node = t;
+        }
+      if (DEFAULT_ABI != MS_ABI)
+        {
+          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;
+        }
+      else
+        {
+          t = ret;
+          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 +5419,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 +5499,11 @@ ix86_gimplify_va_arg (tree valist, tree 
   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 +20266,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_ref, ms_va_list_type_node,
+    			      NULL_TREE);
+  fnvoid_va_copy_sysv =
+    build_function_type_list (void_type_node, sysv_va_ref,
+    			      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 +20372,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 +23198,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 +26055,10 @@ static const struct attribute_spec ix86_
 #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 +26086,128 @@ x86_builtin_vectorization_cost (bool run
     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 == 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;
+
+  /* Resolve references and pointers to va_list type.  */
+  if (INDIRECT_REF_P (type))
+    type = TREE_TYPE (type);
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
+    type = TREE_TYPE (type);
+
+  if (TARGET_64BIT)
+    {
+      wtype = va_list_type_node;
+	  gcc_assert (wtype != NULL_TREE);
+      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;
+      wtype = sysv_va_list_type_node;
+	  gcc_assert (wtype != NULL_TREE);
+      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;
+	  gcc_assert (wtype != NULL_TREE);
+      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 +26336,12 @@ x86_builtin_vectorization_cost (bool run
 #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: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h
+++ gcc/gcc/config/i386/i386.h
@@ -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: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -4187,6 +4187,18 @@ This hook returns a type node for @code{
 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
 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: gcc/gcc/expr.h
===================================================================
--- gcc.orig/gcc/expr.h
+++ gcc/gcc/expr.h
@@ -342,6 +342,9 @@ extern rtx emit_store_flag_force (rtx, e
 /* 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: gcc/gcc/target-def.h
===================================================================
--- gcc.orig/gcc/target-def.h
+++ gcc/gcc/target-def.h
@@ -520,6 +520,8 @@
 #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
@@ -820,6 +822,8 @@
   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: gcc/gcc/target.h
===================================================================
--- gcc.orig/gcc/target.h
+++ gcc/gcc/target.h
@@ -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: gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/callabi.h
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/func-1.c
@@ -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
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-1.c
@@ -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;
+}
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-2.c
@@ -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;
+}
Index: gcc/gcc/tree-sra.c
===================================================================
--- gcc.orig/gcc/tree-sra.c
+++ gcc/gcc/tree-sra.c
@@ -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: gcc/gcc/tree-ssa-ccp.c
===================================================================
--- gcc.orig/gcc/tree-ssa-ccp.c
+++ gcc/gcc/tree-ssa-ccp.c
@@ -2748,17 +2748,19 @@ optimize_stack_restore (basic_block bb, 
 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: gcc/gcc/tree-stdarg.c
===================================================================
--- gcc.orig/gcc/tree-stdarg.c
+++ gcc/gcc/tree-stdarg.c
@@ -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;
Index: gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/callabi/vaarg-3.c
@@ -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: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -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-*-*)
Index: gcc/gcc/config/i386/cross-stdarg.h
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/cross-stdarg.h
@@ -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 */

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-05 17:39                                 ` Kai Tietz
@ 2008-07-06 14:47                                   ` Richard Guenther
  2008-07-07  0:48                                     ` NightStrike
  2008-07-12  8:09                                   ` Bob Wilson
  1 sibling, 1 reply; 25+ messages in thread
From: Richard Guenther @ 2008-07-06 14:47 UTC (permalink / raw)
  To: Kai Tietz
  Cc: Kai Tietz, Diego Novillo, GCC Patches, Jan Hubicka,
	Ian Lance Taylor, Jan Hubicka, Mark Mitchell, Ralf Wildenhues

On Sat, Jul 5, 2008 at 6:07 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
> Hello Richard,
>
> 2008/7/4 Richard Guenther <richard.guenther@gmail.com>:
>> On Fri, Jul 4, 2008 at 3:36 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
>>> Diego,
>>>
>>> I missed two )'s in the prior patch file.
>>> I tested it by adding an assert for canonical_va_list_type in builtins.c:
>>> stabilize_va_list() and regression tested it via linux64 cross and for
>>> w64.
>>
>> Doesn't work.
>>
>> /space/rguenther/obj/./gcc/xgcc -B/space/rguenther/obj/./gcc/
>> -B/usr/local/x86_64-unknown-linux-gnu/bin/
>> -B/usr/local/x86_64-unknown-linux-gnu/lib/ -isystem
>> /usr/local/x86_64-unknown-linux-gnu/include -isystem
>> /usr/local/x86_64-unknown-linux-gnu/sys-include -g -O2 -O2  -g -O2
>> -DIN_GCC   -W -Wall -Wwrite-strings -Wstrict-prototypes
>> -Wmissing-prototypes -Wcast-qual -Wc++-compat -Wold-style-definition
>> -isystem ./include  -fPIC -g -DHAVE_GTHR_DEFAULT -DIN_LIBGCC2
>> -D__GCC_FLOAT_NOT_NEEDED   -I. -I. -I../.././gcc
>> -I../../../trunk/libgcc -I../../../trunk/libgcc/.
>> -I../../../trunk/libgcc/../gcc -I../../../trunk/libgcc/../include
>> -I../../../trunk/libgcc/config/libbid -DENABLE_DECIMAL_BID_FORMAT
>> -DHAVE_CC_TLS -DUSE_TLS -o _gcov_execl.o -MT _gcov_execl.o -MD -MP -MF
>> _gcov_execl.dep -DL_gcov_execl -c
>> ../../../trunk/libgcc/../gcc/libgcov.c
>> ../../../trunk/libgcc/../gcc/libgcov.c: In function '__gcov_execl':
>> ../../../trunk/libgcc/../gcc/libgcov.c:843: warning: cast discards
>> qualifiers from pointer target type
>> ../../../trunk/libgcc/../gcc/libgcov.c:838: error: first argument to
>> 'va_arg' not of type 'va_list'
>> ../../../trunk/libgcc/../gcc/libgcov.c:845: error: first argument to
>> 'va_arg' not of type 'va_list'
>> make[3]: *** [_gcov_execl.o] Error 1
>>
>
> I found the problem. It is related to the fact, that the native
> va_list type for x86_64 is a structure. In earlier patches the type
> was generated twice by the helper function
> x86_build_builtin_va_list_abi. This lead to the problem, that there
> are two record types use, which brings the gimple to fail.
> Additionally the canonical_va_list_type method needs to handle
> va_list_type_node, too. Additionally it has to dereference pointers to
> va_list types.
>
> So here is the new version of this patch. I bootstraped it on linux64
> and tested the new callabi testcases.
>
> Is this patch ok to apply?

Ok.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching and support vaarg.
  2008-07-06 14:47                                   ` Richard Guenther
@ 2008-07-07  0:48                                     ` NightStrike
  0 siblings, 0 replies; 25+ messages in thread
From: NightStrike @ 2008-07-07  0:48 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Kai Tietz, Kai Tietz, Diego Novillo, GCC Patches, Jan Hubicka,
	Ian Lance Taylor, Jan Hubicka, Mark Mitchell, Ralf Wildenhues

On 7/6/08, Richard Guenther <richard.guenther@gmail.com> wrote:
> On Sat, Jul 5, 2008 at 6:07 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
> > Hello Richard,
> >
> > 2008/7/4 Richard Guenther <richard.guenther@gmail.com>:
> >> On Fri, Jul 4, 2008 at 3:36 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> >>> Diego,
> >>>
> >>> I missed two )'s in the prior patch file.
> >>> I tested it by adding an assert for canonical_va_list_type in builtins.c:
> >>> stabilize_va_list() and regression tested it via linux64 cross and for
> >>> w64.
> >>
> >> Doesn't work.
> >>
> >> /space/rguenther/obj/./gcc/xgcc -B/space/rguenther/obj/./gcc/
> >> -B/usr/local/x86_64-unknown-linux-gnu/bin/
> >> -B/usr/local/x86_64-unknown-linux-gnu/lib/ -isystem
> >> /usr/local/x86_64-unknown-linux-gnu/include -isystem
> >> /usr/local/x86_64-unknown-linux-gnu/sys-include -g -O2 -O2  -g -O2
> >> -DIN_GCC   -W -Wall -Wwrite-strings -Wstrict-prototypes
> >> -Wmissing-prototypes -Wcast-qual -Wc++-compat -Wold-style-definition
> >> -isystem ./include  -fPIC -g -DHAVE_GTHR_DEFAULT -DIN_LIBGCC2
> >> -D__GCC_FLOAT_NOT_NEEDED   -I. -I. -I../.././gcc
> >> -I../../../trunk/libgcc -I../../../trunk/libgcc/.
> >> -I../../../trunk/libgcc/../gcc -I../../../trunk/libgcc/../include
> >> -I../../../trunk/libgcc/config/libbid -DENABLE_DECIMAL_BID_FORMAT
> >> -DHAVE_CC_TLS -DUSE_TLS -o _gcov_execl.o -MT _gcov_execl.o -MD -MP -MF
> >> _gcov_execl.dep -DL_gcov_execl -c
> >> ../../../trunk/libgcc/../gcc/libgcov.c
> >> ../../../trunk/libgcc/../gcc/libgcov.c: In function '__gcov_execl':
> >> ../../../trunk/libgcc/../gcc/libgcov.c:843: warning: cast discards
> >> qualifiers from pointer target type
> >> ../../../trunk/libgcc/../gcc/libgcov.c:838: error: first argument to
> >> 'va_arg' not of type 'va_list'
> >> ../../../trunk/libgcc/../gcc/libgcov.c:845: error: first argument to
> >> 'va_arg' not of type 'va_list'
> >> make[3]: *** [_gcov_execl.o] Error 1
> >>
> >
> > I found the problem. It is related to the fact, that the native
> > va_list type for x86_64 is a structure. In earlier patches the type
> > was generated twice by the helper function
> > x86_build_builtin_va_list_abi. This lead to the problem, that there
> > are two record types use, which brings the gimple to fail.
> > Additionally the canonical_va_list_type method needs to handle
> > va_list_type_node, too. Additionally it has to dereference pointers to
> > va_list types.
> >
> > So here is the new version of this patch. I bootstraped it on linux64
> > and tested the new callabi testcases.
> >
> > Is this patch ok to apply?
>
> Ok.
>
> Thanks,
> Richard.
>

From what I can tell, was applied to revision 137525.

Revision 137523 works fine.
Revision 137524 is the testsuite portion of the patch.
Revision 137525 is the rest of it.

Building the win64 crt with revision 137523 works fine.
Building the win64 crt with revision 137525 results in the following:

../mingw-w64-crt/gdtoa/mingw_snprintf.c:1254: internal compiler error:
tree check: expected record_type or union_type or qual_union_type,
have integer_type in find_compatible_field, at tree.c:8092
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching  and support vaarg.
  2008-07-05 17:39                                 ` Kai Tietz
  2008-07-06 14:47                                   ` Richard Guenther
@ 2008-07-12  8:09                                   ` Bob Wilson
  1 sibling, 0 replies; 25+ messages in thread
From: Bob Wilson @ 2008-07-12  8:09 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Richard Guenther, GCC Patches

Kai Tietz wrote:
> I found the problem. It is related to the fact, that the native
> va_list type for x86_64 is a structure. In earlier patches the type
> was generated twice by the helper function
> x86_build_builtin_va_list_abi. This lead to the problem, that there
> are two record types use, which brings the gimple to fail.
> Additionally the canonical_va_list_type method needs to handle
> va_list_type_node, too. Additionally it has to dereference pointers to
> va_list types.

This still breaks Xtensa, which also has a struct va_list.  The 
std_canonical_va_list_type function returns NULL_TREE when called from 
expand_builtin_va_start through stabilize_va_list, so that stabilize_va_list 
asserts.  It correctly returns va_list_type_node when called from 
gimplify_va_arg_expr.  I think the difference is that in the former case 
std_canonical_va_list_type is given a pointer to the struct type, and it does 
not "dereference" the pointer type to get to the struct:

   if (INDIRECT_REF_P (type))
     type = TREE_TYPE (type);
   else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
     type = TREE_TYPE (type);

It can handle pointers to pointers, but not pointers to structs.  I'm not 
familiar with this code and can't easily suggest a fix.

In the short term, I can work around this by defining 
TARGET_CANONICAL_VA_LIST_TYPE for Xtensa, but that doesn't seem like the right 
thing to do.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [patch i386] Enable attribute based calling convention switching   and support vaarg.
  2008-07-01 12:32       ` Kai Tietz
  2008-07-01 19:08         ` Ralf Wildenhues
@ 2009-02-18  7:41         ` H.J. Lu
  1 sibling, 0 replies; 25+ messages in thread
From: H.J. Lu @ 2009-02-18  7:41 UTC (permalink / raw)
  To: Kai Tietz
  Cc: Richard Guenther, GCC Patches, Jan Hubicka, Jan Hubicka,
	Kai Tietz, Mark Mitchell

On Tue, Jul 1, 2008 at 4:19 AM, Kai Tietz <Kai.Tietz@onevision.com> wrote:

>
> 2008-07-01  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.
>
> I tested this patch on x86_64-pc-mingw32 target. All new testcases
> work without any problems.
> Is this patch ok for apply?
>

Those testcases were never run until revision 144258, which added
gcc.dg/callabi/callabi.exp. On Linux/x86-64, I got

FAIL: gcc.dg/callabi/func-1.c execution test

I opened:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39224


-- 
H.J.

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2009-02-18  6:26 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-06-28 13:28 [patch i386] Enable attribute based calling convention switching and support vaarg Kai Tietz
2008-06-30 12:29 ` Richard Guenther
2008-06-30 14:08   ` Kai Tietz
2008-06-30 15:37     ` Richard Guenther
2008-07-01 12:32       ` Kai Tietz
2008-07-01 19:08         ` Ralf Wildenhues
2008-07-01 19:18           ` Kai Tietz
2008-07-03 13:21             ` Richard Guenther
2008-07-03 14:18               ` Kai Tietz
2008-07-03 15:10                 ` Richard Guenther
2008-07-03 20:28               ` Ian Lance Taylor
2008-07-03 20:49                 ` Jan Hubicka
2008-07-04  9:11                   ` Kai Tietz
2008-07-04 12:30                     ` Richard Guenther
2008-07-04 12:54                       ` Kai Tietz
2008-07-04 13:13                         ` Richard Guenther
2008-07-04 13:19                           ` Kai Tietz
2008-07-04 13:24                           ` Diego Novillo
2008-07-04 13:45                             ` Kai Tietz
2008-07-04 19:27                               ` Richard Guenther
2008-07-05 17:39                                 ` Kai Tietz
2008-07-06 14:47                                   ` Richard Guenther
2008-07-07  0:48                                     ` NightStrike
2008-07-12  8:09                                   ` Bob Wilson
2009-02-18  7:41         ` H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).