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/config/i386/i386.c =================================================================== --- gcc.orig/gcc/config/i386/i386.c +++ gcc/gcc/config/i386/i386.c @@ -1711,6 +1711,9 @@ unsigned int ix86_preferred_stack_bounda /* Values 1-5: see jump.c */ int ix86_branch_cost; +static tree sysv_va_list_type_node; +static tree ms_va_list_type_node; + /* Variables which are this size or smaller are put in the data/bss or ldata/lbss sections. */ @@ -3599,9 +3602,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; @@ -5168,13 +5168,16 @@ ix86_struct_value_rtx (tree type, int in /* 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 (int 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); @@ -5210,6 +5213,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,7 +5401,7 @@ ix86_va_start (tree valist, rtx 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); @@ -5447,7 +5477,7 @@ ix86_gimplify_va_arg (tree valist, tree if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI) 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); @@ -20229,11 +20259,96 @@ ix86_init_mmx_sse_builtins (void) } } +/* Helper method to generate ellipsis function declarations. */ +static tree +build_function_type_list_ellipsis (tree return_type, ...) +{ + tree t, args; + va_list p; + + va_start (p, return_type); + + t = va_arg (p, tree); + for (args = NULL_TREE; t != NULL_TREE; t = va_arg (p, tree)) + args = tree_cons (NULL_TREE, t, args); + + if (args == NULL_TREE) + args = void_list_node; + else + { + args = nreverse (args); + } + args = build_function_type (return_type, args); + + va_end (p); + return args; +} + +/* 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; + + if (!TARGET_64BIT) + return; + 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_function_type_list_ellipsis (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_function_type_list_ellipsis (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, NULL_TREE); + add_builtin_function ("__builtin_sysv_va_start", fnvoid_va_start_sysv, + BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("__builtin_ms_va_end", fnvoid_va_end_ms, + BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("__builtin_sysv_va_end", fnvoid_va_end_sysv, + BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("ms_va_start", fnvoid_va_start_ms, + BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("sysv_va_start", fnvoid_va_start_sysv, + BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("ms_va_end", fnvoid_va_end_ms, + BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("sysv_va_end", fnvoid_va_end_sysv, + BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("__builtin_sysv_va_copy", fnvoid_va_copy_sysv, + BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("sysv_va_copy", fnvoid_va_copy_sysv, + BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("__builtin_ms_va_copy", fnvoid_va_copy_ms, + BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, NULL_TREE); + add_builtin_function ("ms_va_copy", fnvoid_va_copy_ms, + BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, NULL_TREE); +} + 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 @@ -23049,6 +23164,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 @@ -25858,6 +26021,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 } }; @@ -25885,6 +26052,51 @@ x86_builtin_vectorization_cost (bool run return 0; } +tree +ix86_cfun_abi_va_list (void) +{ + int abi; + + if (!TARGET_64BIT) + return va_list_type_node; + 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; +} + +/* 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. */ + +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 @@ -26013,6 +26225,9 @@ 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_EXPAND_BUILTIN_VA_START #define TARGET_EXPAND_BUILTIN_VA_START ix86_va_start 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 */ +/* { 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/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 */ +/* { 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/builtins.c =================================================================== --- gcc.orig/gcc/builtins.c +++ gcc/gcc/builtins.c @@ -4618,18 +4618,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) + if (TREE_CODE (targetm.cfun_abi_va_list ()) == 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). + TREE_TYPE (TARGET_CFUN_ABI_VA_LIST ()), 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 (targetm.cfun_abi_va_list ())); valist = build_fold_addr_expr_with_type (valist, p1); } } @@ -4642,7 +4643,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 (targetm.cfun_abi_va_list ()); valist = fold_build1 (ADDR_EXPR, pt, valist); TREE_SIDE_EFFECTS (valist) = 1; } @@ -4663,6 +4664,14 @@ 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 (void) +{ + return va_list_type_node; +} + /* The "standard" implementation of va_start: just assign `nextarg' to the variable. */ @@ -4824,7 +4833,7 @@ gimplify_va_arg_expr (tree *expr_p, tree tree t; /* Verify that valist is of the proper type. */ - want_va_type = va_list_type_node; + want_va_type = targetm.cfun_abi_va_list (); have_va_type = TREE_TYPE (valist); if (have_va_type == error_mark_node) @@ -4884,15 +4893,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 (targetm.cfun_abi_va_list ()) == 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 (TARGET_CFUN_ABI_VA_LIST ()), 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 (targetm.cfun_abi_va_list ())); valist = build_fold_addr_expr_with_type (valist, p1); } gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue); @@ -4940,9 +4949,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 ()) != ARRAY_TYPE) { - t = build2 (MODIFY_EXPR, va_list_type_node, dst, src); + t = build2 (MODIFY_EXPR, targetm.cfun_abi_va_list (), dst, src); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } @@ -4953,7 +4962,7 @@ 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, + size = expand_expr (TYPE_SIZE_UNIT (targetm.cfun_abi_va_list ()), NULL_RTX, VOIDmode, EXPAND_NORMAL); dstb = convert_memory_address (Pmode, dstb); @@ -4962,10 +4971,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 ())); 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 ())); /* 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,8 @@ 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 (void); +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.h =================================================================== --- gcc.orig/gcc/config/i386/i386.h +++ gcc/gcc/config/i386/i386.h @@ -2552,6 +2552,9 @@ struct machine_function GTY(()) #undef TARG_COND_BRANCH_COST #define TARG_COND_BRANCH_COST ix86_cost->branch_cost +#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/tree-sra.c =================================================================== --- gcc.orig/gcc/tree-sra.c +++ gcc/gcc/tree-sra.c @@ -362,7 +362,7 @@ decl_can_be_decomposed_p (tree var) 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)) + == TYPE_MAIN_VARIANT (targetm.cfun_abi_va_list ())) 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,15 +2748,16 @@ 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); + cfun_va_list = targetm.cfun_abi_va_list (); + 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); callee = get_callee_fndecl (call); switch (DECL_FUNCTION_CODE (callee)) @@ -2773,7 +2774,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 (targetm.cfun_abi_va_list ())) return NULL_TREE; lhs = build_fold_indirect_ref (lhs); @@ -2792,13 +2793,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 (targetm.cfun_abi_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 (targetm.cfun_abi_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 (); + 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 ()) || TREE_CODE (ap) != VAR_DECL) { va_list_escapes = true; Index: gcc/gcc/doc/tm.texi =================================================================== --- gcc.orig/gcc/doc/tm.texi +++ gcc/gcc/doc/tm.texi @@ -4187,6 +4187,11 @@ 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 (void) +This hook returns the va_list type of the calling convention specified by cfun. +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 +4322,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,7 @@ 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 (void); 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 @@ -517,6 +517,7 @@ #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_EXPAND_BUILTIN_VA_START 0 #define TARGET_GET_PCH_VALIDITY default_get_pch_validity @@ -816,6 +817,7 @@ TARGET_CC_MODES_COMPATIBLE, \ TARGET_MACHINE_DEPENDENT_REORG, \ TARGET_BUILD_BUILTIN_VA_LIST, \ + TARGET_CFUN_ABI_VA_LIST, \ 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 @@ -694,6 +694,9 @@ struct gcc_target /* Create the __builtin_va_list type. */ tree (* build_builtin_va_list) (void); + /* Get the cfun calling abi __builtin_va_list type. */ + tree (* cfun_abi_va_list) (void); + /* Expand the __builtin_va_start builtin. */ void (* expand_builtin_va_start) (tree valist, rtx nextarg); =