From 0b4b69ef79271e8e6a2dfa2eaa3376a75fa05d03 Mon Sep 17 00:00:00 2001 From: Kai Tietz Date: Fri, 4 Jul 2008 08:15:27 +0000 Subject: [PATCH] config.gcc (extra_headers): Add cross-stdarg.h for target x86_64-*-* and i?86-*-*. 2008-07-04 Kai Tietz * config.gcc (extra_headers): Add cross-stdarg.h for target x86_64-*-* and i?86-*-*. * config/i386/cross-stdarg.h: New. * builtins.c (std_fn_abi_va_list): New. (std_canonical_va_list_type): New. (stabilize_va_list): Replace va_list_type_node use by mtarget.canonical_va_list_type. (gimplify_va_arg_expr): Likewise. (expand_builtin_va_copy): Replace va_list_type_node use by mtarget.fn_abi_va_list. * tree-sra.c (is_va_list_type): New helper. (decl_can_be_decomposed_p): Replace va_list_type_node use by is_va_list_type. * tree-ssa-ccp.c (optimize_stdarg_builtin): Likewise. * tree-stdarg.c (execute_optimize_stdarg): Likewise. * c-common.c (c_common_nodes_and_builtins): Use TARGET_ENUM_VA_LIST. * config/i386/i386-protos.h (ix86_get_valist_type): New. (ix86_enum_va_list): New. * config/i386/i386.c (sysv_va_list_type_node): New. (ms_va_list_type_node): New. (ix86_function_type_abi): Remove sorry. (ix86_build_builtin_va_list_abi): New. (ix86_build_builtin_va_list): Call ix86_build_builtin_va_list_abi for 64-bit targets. (ix86_va_start): Replace va_list_type_node by sysv_va_list_type_node. (ix86_init_builtins_va_builtins_abi): New. (ix86_init_builtins): Use ix86_init_builtins_va_builtins_abi for 64-bit targets. (ix86_handle_abi_attribute): New. (attribute_spec): Add sysv_abi and ms_abi. (ix86_fn_abi_va_list): New. (ix86_canonical_va_list_type): New. (ix86_enum_va_list): New. (TARGET_FN_ABI_VA_LIST): New. (TARGET_CANONICAL_VA_LIST_TYPE): New. * config/i386/i386.h (TARGET_ENUM_VA_LIST): New. * doc/tm.texi (TARGET_FN_ABI_VA_LIST): New. (TARGET_CANONICAL_VA_LIST_TYPE): New. (TARGET_ENUM_VA_LIST): New. * expr.h (std_fn_abi_va_list): New. (std_canonical_va_list_type): New. * target-def.h (TARGET_FN_ABI_VA_LIST): New. (TARGET_CANONICAL_VA_LIST_TYPE): New. (TARGET_INITIALIZER): Add TARGET_FN_ABI_VA_LIST and TARGET_CANONICAL_VA_LIST_TYPE. * target.h (struct gcc_target): Add fn_abi_va_list hook and canonical_va_list_type hook. 2008-07-04 Kai Tietz * 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. From-SVN: r137452 --- gcc/ChangeLog | 50 +++++ gcc/builtins.c | 92 +++++---- gcc/c-common.c | 14 ++ gcc/config.gcc | 4 +- gcc/config/i386/cross-stdarg.h | 76 +++++++ gcc/config/i386/i386-protos.h | 3 + gcc/config/i386/i386.c | 263 +++++++++++++++++++++++-- gcc/config/i386/i386.h | 7 +- gcc/doc/tm.texi | 26 +++ gcc/expr.h | 3 + gcc/target-def.h | 4 + gcc/target.h | 6 + gcc/testsuite/ChangeLog | 8 + gcc/testsuite/gcc.dg/callabi/callabi.h | 50 +++++ gcc/testsuite/gcc.dg/callabi/func-1.c | 40 ++++ gcc/testsuite/gcc.dg/callabi/vaarg-1.c | 47 +++++ gcc/testsuite/gcc.dg/callabi/vaarg-2.c | 47 +++++ gcc/testsuite/gcc.dg/callabi/vaarg-3.c | 47 +++++ gcc/tree-sra.c | 24 ++- gcc/tree-ssa-ccp.c | 18 +- gcc/tree-stdarg.c | 12 +- 21 files changed, 776 insertions(+), 65 deletions(-) create mode 100644 gcc/config/i386/cross-stdarg.h create mode 100644 gcc/testsuite/gcc.dg/callabi/callabi.h create mode 100644 gcc/testsuite/gcc.dg/callabi/func-1.c create mode 100644 gcc/testsuite/gcc.dg/callabi/vaarg-1.c create mode 100644 gcc/testsuite/gcc.dg/callabi/vaarg-2.c create mode 100644 gcc/testsuite/gcc.dg/callabi/vaarg-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 700367a7230..a3c6b76cc3e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,53 @@ +2008-07-04 Kai Tietz + + * config.gcc (extra_headers): Add cross-stdarg.h for target + x86_64-*-* and i?86-*-*. + * config/i386/cross-stdarg.h: New. + * builtins.c (std_fn_abi_va_list): New. + (std_canonical_va_list_type): New. + (stabilize_va_list): Replace va_list_type_node use by + mtarget.canonical_va_list_type. + (gimplify_va_arg_expr): Likewise. + (expand_builtin_va_copy): Replace va_list_type_node use by + mtarget.fn_abi_va_list. + * tree-sra.c (is_va_list_type): New helper. + (decl_can_be_decomposed_p): Replace + va_list_type_node use by is_va_list_type. + * tree-ssa-ccp.c (optimize_stdarg_builtin): Likewise. + * tree-stdarg.c (execute_optimize_stdarg): Likewise. + * c-common.c (c_common_nodes_and_builtins): Use TARGET_ENUM_VA_LIST. + * config/i386/i386-protos.h (ix86_get_valist_type): New. + (ix86_enum_va_list): New. + * config/i386/i386.c (sysv_va_list_type_node): New. + (ms_va_list_type_node): New. + (ix86_function_type_abi): Remove sorry. + (ix86_build_builtin_va_list_abi): New. + (ix86_build_builtin_va_list): Call ix86_build_builtin_va_list_abi + for 64-bit targets. + (ix86_va_start): Replace va_list_type_node by sysv_va_list_type_node. + (ix86_init_builtins_va_builtins_abi): New. + (ix86_init_builtins): Use ix86_init_builtins_va_builtins_abi + for 64-bit targets. + (ix86_handle_abi_attribute): New. + (attribute_spec): Add sysv_abi and ms_abi. + (ix86_fn_abi_va_list): New. + (ix86_canonical_va_list_type): New. + (ix86_enum_va_list): New. + (TARGET_FN_ABI_VA_LIST): New. + (TARGET_CANONICAL_VA_LIST_TYPE): New. + * config/i386/i386.h (TARGET_ENUM_VA_LIST): New. + * doc/tm.texi (TARGET_FN_ABI_VA_LIST): New. + (TARGET_CANONICAL_VA_LIST_TYPE): New. + (TARGET_ENUM_VA_LIST): New. + * expr.h (std_fn_abi_va_list): New. + (std_canonical_va_list_type): New. + * target-def.h (TARGET_FN_ABI_VA_LIST): New. + (TARGET_CANONICAL_VA_LIST_TYPE): New. + (TARGET_INITIALIZER): Add TARGET_FN_ABI_VA_LIST and + TARGET_CANONICAL_VA_LIST_TYPE. + * target.h (struct gcc_target): Add fn_abi_va_list hook + and canonical_va_list_type hook. + 2008-07-04 Kaveh R. Ghazi * ggc-zone.c (lookup_page_table_if_allocated, diff --git a/gcc/builtins.c b/gcc/builtins.c index 731955b5699..30bcdf81750 100644 --- a/gcc/builtins.c +++ b/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 needs_lvalue) if (! TREE_SIDE_EFFECTS (valist)) return valist; - pt = build_pointer_type (va_list_type_node); + pt = build_pointer_type (vatype); valist = fold_build1 (ADDR_EXPR, pt, valist); TREE_SIDE_EFFECTS (valist) = 1; } @@ -4668,6 +4669,42 @@ std_build_builtin_va_list (void) return ptr_type_node; } +/* The "standard" abi va_list is va_list_type_node. */ + +tree +std_fn_abi_va_list (tree fndecl ATTRIBUTE_UNUSED) +{ + return va_list_type_node; +} + +/* The "standard" type of va_list is va_list_type_node. */ + +tree +std_canonical_va_list_type (tree type) +{ + tree wtype, htype; + + wtype = va_list_type_node; + htype = type; + if (TREE_CODE (wtype) == ARRAY_TYPE) + { + /* If va_list is an array type, the argument may have decayed + to a pointer type, e.g. by being passed to another function. + In that case, unwrap both types so that we can compare the + underlying records. */ + if (TREE_CODE (htype) == ARRAY_TYPE + || POINTER_TYPE_P (htype)) + { + wtype = TREE_TYPE (wtype); + htype = TREE_TYPE (htype); + } + } + if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype)) + return va_list_type_node; + + return NULL_TREE; +} + /* The "standard" implementation of va_start: just assign `nextarg' to the variable. */ @@ -4823,33 +4860,18 @@ dummy_object (tree type) enum gimplify_status gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) { - tree promoted_type, want_va_type, have_va_type; + tree promoted_type, have_va_type; tree valist = TREE_OPERAND (*expr_p, 0); tree type = TREE_TYPE (*expr_p); tree t; /* Verify that valist is of the proper type. */ - want_va_type = va_list_type_node; have_va_type = TREE_TYPE (valist); - if (have_va_type == error_mark_node) return GS_ERROR; + have_va_type = targetm.canonical_va_list_type (have_va_type); - if (TREE_CODE (want_va_type) == ARRAY_TYPE) - { - /* If va_list is an array type, the argument may have decayed - to a pointer type, e.g. by being passed to another function. - In that case, unwrap both types so that we can compare the - underlying records. */ - if (TREE_CODE (have_va_type) == ARRAY_TYPE - || POINTER_TYPE_P (have_va_type)) - { - want_va_type = TREE_TYPE (want_va_type); - have_va_type = TREE_TYPE (have_va_type); - } - } - - if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type)) + if (have_va_type == NULL_TREE) { error ("first argument to % not of type %"); return GS_ERROR; @@ -4857,7 +4879,7 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) /* Generate a diagnostic for requesting data of a type that cannot be passed through `...' due to type promotion at the call site. */ - else if ((promoted_type = lang_hooks.types.type_promotes_to (type)) + if ((promoted_type = lang_hooks.types.type_promotes_to (type)) != type) { static bool gave_help; @@ -4889,15 +4911,15 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) { /* Make it easier for the backends by protecting the valist argument from multiple evaluations. */ - if (TREE_CODE (va_list_type_node) == ARRAY_TYPE) + if (TREE_CODE (have_va_type) == ARRAY_TYPE) { /* For this case, the backends will be expecting a pointer to - TREE_TYPE (va_list_type_node), but it's possible we've - actually been given an array (an actual va_list_type_node). + TREE_TYPE (abi), but it's possible we've + actually been given an array (an actual TARGET_FN_ABI_VA_LIST). So fix it. */ if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE) { - tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node)); + tree p1 = build_pointer_type (TREE_TYPE (have_va_type)); valist = build_fold_addr_expr_with_type (valist, p1); } gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue); @@ -4945,9 +4967,11 @@ expand_builtin_va_copy (tree exp) dst = stabilize_va_list (dst, 1); src = stabilize_va_list (src, 0); - if (TREE_CODE (va_list_type_node) != ARRAY_TYPE) + gcc_assert (cfun != NULL && cfun->decl != NULL_TREE); + + if (TREE_CODE (targetm.fn_abi_va_list (cfun->decl)) != ARRAY_TYPE) { - t = build2 (MODIFY_EXPR, va_list_type_node, dst, src); + t = build2 (MODIFY_EXPR, targetm.fn_abi_va_list (cfun->decl), dst, src); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } @@ -4958,8 +4982,8 @@ expand_builtin_va_copy (tree exp) /* Evaluate to pointers. */ dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL); srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL); - size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX, - VOIDmode, EXPAND_NORMAL); + size = expand_expr (TYPE_SIZE_UNIT (targetm.fn_abi_va_list (cfun->decl)), + NULL_RTX, VOIDmode, EXPAND_NORMAL); dstb = convert_memory_address (Pmode, dstb); srcb = convert_memory_address (Pmode, srcb); @@ -4967,10 +4991,10 @@ expand_builtin_va_copy (tree exp) /* "Dereference" to BLKmode memories. */ dstb = gen_rtx_MEM (BLKmode, dstb); set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst)))); - set_mem_align (dstb, TYPE_ALIGN (va_list_type_node)); + set_mem_align (dstb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl))); srcb = gen_rtx_MEM (BLKmode, srcb); set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src)))); - set_mem_align (srcb, TYPE_ALIGN (va_list_type_node)); + set_mem_align (srcb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl))); /* Copy. */ emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL); diff --git a/gcc/c-common.c b/gcc/c-common.c index 3a633843f73..2224a21f0ef 100644 --- a/gcc/c-common.c +++ b/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) { diff --git a/gcc/config.gcc b/gcc/config.gcc index b29a762895c..eda28121204 100644 --- a/gcc/config.gcc +++ b/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-*-*) diff --git a/gcc/config/i386/cross-stdarg.h b/gcc/config/i386/cross-stdarg.h new file mode 100644 index 00000000000..98ac1ecd5cc --- /dev/null +++ b/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 */ diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 8d0772dbe8b..9719ec2886f 100644 --- a/gcc/config/i386/i386-protos.h +++ b/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, diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index a0edacaaaba..ec627e8f057 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1716,6 +1716,10 @@ unsigned int ix86_preferred_stack_boundary; /* Values 1-5: see jump.c */ int ix86_branch_cost; +/* Calling abi specific va_list type nodes. */ +static GTY(()) tree sysv_va_list_type_node; +static GTY(()) tree ms_va_list_type_node; + /* Variables which are this size or smaller are put in the data/bss or ldata/lbss sections. */ @@ -2774,9 +2778,8 @@ override_options (void) set_param_value ("l2-cache-size", ix86_cost->l2_cache_size); /* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0) - can be optimized to ap = __builtin_next_arg (0). - For abi switching it should be corrected. */ - if (!TARGET_64BIT || DEFAULT_ABI == MS_ABI) + can be optimized to ap = __builtin_next_arg (0). */ + if (!TARGET_64BIT) targetm.expand_builtin_va_start = NULL; if (TARGET_64BIT) @@ -3604,9 +3607,6 @@ ix86_function_type_abi (const_tree fntype) else abi = lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)) ? SYSV_ABI : MS_ABI; - if (DEFAULT_ABI == MS_ABI && abi == SYSV_ABI) - sorry ("using sysv calling convention on target w64 is not supported"); - return abi; } return DEFAULT_ABI; @@ -5174,13 +5174,16 @@ ix86_struct_value_rtx (tree type, int incoming ATTRIBUTE_UNUSED) /* Create the va_list data type. */ +/* Returns the calling convention specific va_list date type. + The argument ABI can be DEFAULT_ABI, MS_ABI, or SYSV_ABI. */ + static tree -ix86_build_builtin_va_list (void) +ix86_build_builtin_va_list_abi (enum calling_abi abi) { tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl; /* For i386 we use plain pointer to argument area. */ - if (!TARGET_64BIT || ix86_cfun_abi () == MS_ABI) + if (!TARGET_64BIT || abi == MS_ABI) return build_pointer_type (char_type_node); record = (*lang_hooks.types.make_type) (RECORD_TYPE); @@ -5216,6 +5219,33 @@ ix86_build_builtin_va_list (void) return build_array_type (record, build_index_type (size_zero_node)); } +/* Setup the builtin va_list data type and for 64-bit the additional + calling convention specific va_list data types. */ + +static tree +ix86_build_builtin_va_list (void) +{ + tree ret = ix86_build_builtin_va_list_abi (DEFAULT_ABI); + + /* Initialize abi specific va_list builtin types. */ + if (TARGET_64BIT) + { + tree t; + + t = ix86_build_builtin_va_list_abi (SYSV_ABI); + if (TREE_CODE (t) != RECORD_TYPE) + t = build_variant_type_copy (t); + sysv_va_list_type_node = t; + + t = ix86_build_builtin_va_list_abi (MS_ABI); + if (TREE_CODE (t) != RECORD_TYPE) + t = build_variant_type_copy (t); + ms_va_list_type_node = t; + } + + return ret; +} + /* Worker function for TARGET_SETUP_INCOMING_VARARGS. */ static void @@ -5371,13 +5401,14 @@ ix86_va_start (tree valist, rtx nextarg) tree type; /* Only 64bit target needs something special. */ - if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI) + if (!TARGET_64BIT || + ix86_canonical_va_list_type (TREE_TYPE (valist)) == ms_va_list_type_node) { std_expand_builtin_va_start (valist, nextarg); return; } - f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); + f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node)); f_fpr = TREE_CHAIN (f_gpr); f_ovf = TREE_CHAIN (f_fpr); f_sav = TREE_CHAIN (f_ovf); @@ -5450,10 +5481,11 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) enum machine_mode nat_mode; /* Only 64bit target needs something special. */ - if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI) + if (!TARGET_64BIT || + ix86_canonical_va_list_type (TREE_TYPE (valist)) == ms_va_list_type_node) return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); - f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); + f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node)); f_fpr = TREE_CHAIN (f_gpr); f_ovf = TREE_CHAIN (f_fpr); f_sav = TREE_CHAIN (f_ovf); @@ -20216,6 +20248,55 @@ ix86_init_mmx_sse_builtins (void) } } +/* Internal method for ix86_init_builtins. */ + +static void +ix86_init_builtins_va_builtins_abi (void) +{ + tree ms_va_ref, sysv_va_ref; + tree fnvoid_va_end_ms, fnvoid_va_end_sysv; + tree fnvoid_va_start_ms, fnvoid_va_start_sysv; + tree fnvoid_va_copy_ms, fnvoid_va_copy_sysv; + tree fnattr_ms = NULL_TREE, fnattr_sysv = NULL_TREE; + + if (!TARGET_64BIT) + return; + fnattr_ms = build_tree_list (get_identifier ("ms_abi"), NULL_TREE); + fnattr_sysv = build_tree_list (get_identifier ("sysv_abi"), NULL_TREE); + ms_va_ref = build_reference_type (ms_va_list_type_node); + sysv_va_ref = + build_pointer_type (TREE_TYPE (sysv_va_list_type_node)); + + fnvoid_va_end_ms = + build_function_type_list (void_type_node, ms_va_ref, NULL_TREE); + fnvoid_va_start_ms = + build_varargs_function_type_list (void_type_node, ms_va_ref, NULL_TREE); + fnvoid_va_end_sysv = + build_function_type_list (void_type_node, sysv_va_ref, NULL_TREE); + fnvoid_va_start_sysv = + build_varargs_function_type_list (void_type_node, sysv_va_ref, + NULL_TREE); + fnvoid_va_copy_ms = + build_function_type_list (void_type_node, ms_va_list_type_node, ms_va_ref, + NULL_TREE); + fnvoid_va_copy_sysv = + build_function_type_list (void_type_node, sysv_va_list_type_node, + sysv_va_ref, NULL_TREE); + + add_builtin_function ("__builtin_ms_va_start", fnvoid_va_start_ms, + BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_ms); + add_builtin_function ("__builtin_ms_va_end", fnvoid_va_end_ms, + BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_ms); + add_builtin_function ("__builtin_ms_va_copy", fnvoid_va_copy_ms, + BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_ms); + add_builtin_function ("__builtin_sysv_va_start", fnvoid_va_start_sysv, + BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_sysv); + add_builtin_function ("__builtin_sysv_va_end", fnvoid_va_end_sysv, + BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_sysv); + add_builtin_function ("__builtin_sysv_va_copy", fnvoid_va_copy_sysv, + BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_sysv); +} + static void ix86_init_builtins (void) { @@ -20273,6 +20354,8 @@ ix86_init_builtins (void) if (TARGET_MMX) ix86_init_mmx_sse_builtins (); + if (TARGET_64BIT) + ix86_init_builtins_va_builtins_abi (); } /* Errors in the source file can cause expand_expr to return const0_rtx @@ -23097,6 +23180,54 @@ x86_order_regs_for_local_alloc (void) reg_alloc_order [pos++] = 0; } +/* Handle a "ms_abi" or "sysv" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +ix86_handle_abi_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_TYPE + && TREE_CODE (*node) != METHOD_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning (OPT_Wattributes, "%qs attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + if (!TARGET_64BIT) + { + warning (OPT_Wattributes, "%qs attribute only available for 64-bit", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + + /* Can combine regparm with all attributes but fastcall. */ + if (is_attribute_p ("ms_abi", name)) + { + if (lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (*node))) + { + error ("ms_abi and sysv_abi attributes are not compatible"); + } + + return NULL_TREE; + } + else if (is_attribute_p ("sysv_abi", name)) + { + if (lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (*node))) + { + error ("ms_abi and sysv_abi attributes are not compatible"); + } + + return NULL_TREE; + } + + return NULL_TREE; +} + /* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in struct attribute_spec.handler. */ static tree @@ -25906,6 +26037,10 @@ static const struct attribute_spec ix86_attribute_table[] = #ifdef SUBTARGET_ATTRIBUTE_TABLE SUBTARGET_ATTRIBUTE_TABLE, #endif + /* ms_abi and sysv_abi calling convention function attributes. */ + { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute }, + { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute }, + /* End element. */ { NULL, 0, 0, false, false, false, NULL } }; @@ -25933,6 +26068,104 @@ x86_builtin_vectorization_cost (bool runtime_test) return 0; } +/* This function returns the calling abi specific va_list type node. + It returns the FNDECL specific va_list type. */ + +tree +ix86_fn_abi_va_list (tree fndecl) +{ + int abi; + + if (!TARGET_64BIT) + return va_list_type_node; + gcc_assert (fndecl != NULL_TREE); + abi = ix86_function_abi ((const_tree) fndecl); + + if (abi == DEFAULT_ABI) + return va_list_type_node; + else if (abi == MS_ABI) + return ms_va_list_type_node; + else + return sysv_va_list_type_node; +} + +/* Returns the canonical va_list type specified by TYPE. If there + is no valid TYPE provided, it return NULL_TREE. */ + +tree +ix86_canonical_va_list_type (tree type) +{ + tree wtype, htype; + if (TARGET_64BIT) + { + wtype = sysv_va_list_type_node; + htype = type; + if (TREE_CODE (wtype) == ARRAY_TYPE) + { + /* If va_list is an array type, the argument may have decayed + to a pointer type, e.g. by being passed to another function. + In that case, unwrap both types so that we can compare the + underlying records. */ + if (TREE_CODE (htype) == ARRAY_TYPE + || POINTER_TYPE_P (htype)) + { + wtype = TREE_TYPE (wtype); + htype = TREE_TYPE (htype); + } + } + if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype)) + return sysv_va_list_type_node; + wtype = ms_va_list_type_node; + htype = type; + if (TREE_CODE (wtype) == ARRAY_TYPE) + { + /* If va_list is an array type, the argument may have decayed + to a pointer type, e.g. by being passed to another function. + In that case, unwrap both types so that we can compare the + underlying records. */ + if (TREE_CODE (htype) == ARRAY_TYPE + || POINTER_TYPE_P (htype)) + { + wtype = TREE_TYPE (wtype); + htype = TREE_TYPE (htype); + } + } + if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype)) + return ms_va_list_type_node; + + return NULL_TREE; + } + return std_canonical_va_list_type (type); +} + +/* Iterate through the target-specific builtin types for va_list. + IDX denotes the iterator, *PTREE is set to the result type of + the va_list builtin, and *PNAME to its internal type. + Returns zero if there is no element for this index, otherwise + IDX should be increased upon the next call. + Note, do not iterate a base builtin's name like __builtin_va_list. + Used from c_common_nodes_and_builtins. */ + +int +ix86_enum_va_list (int idx, const char **pname, tree *ptree) +{ + if (!TARGET_64BIT) + return 0; + switch (idx) { + case 0: + *ptree = ms_va_list_type_node; + *pname = "__builtin_ms_va_list"; + break; + case 1: + *ptree = sysv_va_list_type_node; + *pname = "__builtin_sysv_va_list"; + break; + default: + return 0; + } + return 1; +} + /* Initialize the GCC target structure. */ #undef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY ix86_return_in_memory @@ -26061,6 +26294,12 @@ x86_builtin_vectorization_cost (bool runtime_test) #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST ix86_build_builtin_va_list +#undef TARGET_FN_ABI_VA_LIST +#define TARGET_FN_ABI_VA_LIST ix86_fn_abi_va_list + +#undef TARGET_CANONICAL_VA_LIST_TYPE +#define TARGET_CANONICAL_VA_LIST_TYPE ix86_canonical_va_list_type + #undef TARGET_EXPAND_BUILTIN_VA_START #define TARGET_EXPAND_BUILTIN_VA_START ix86_va_start diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index b011885424a..d17e414eb5f 100644 --- a/gcc/config/i386/i386.h +++ b/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 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index d4ba0e20814..b5418a3f465 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4187,6 +4187,18 @@ This hook returns a type node for @code{va_list} for the target. The default version of the hook returns @code{void*}. @end deftypefn +@deftypefn {Target Hook} tree TARGET_FN_ABI_VA_LIST (tree @var{fndecl}) +This hook returns the va_list type of the calling convention specified by +@var{fndecl}. +The default version of this hook returns @code{va_list_type_node}. +@end deftypefn + +@deftypefn {Target Hook} tree TARGET_CANONICAL_VA_LIST_TYPE (tree @var{type}) +This hook returns the va_list type of the calling convention specified by the +type of @var{type}. If @var{type} is not a valid va_list type, it returns +@code{NULL_TREE}. +@end deftypefn + @deftypefn {Target Hook} tree TARGET_GIMPLIFY_VA_ARG_EXPR (tree @var{valist}, tree @var{type}, tree *@var{pre_p}, tree *@var{post_p}) This hook performs target-specific gimplification of @code{VA_ARG_EXPR}. The first two parameters correspond to the @@ -4317,6 +4329,20 @@ function use different registers for the return value, this macro should recognize only the caller's register numbers. @end defmac +@defmac TARGET_ENUM_VA_LIST (@var{idx}, @var{pname}, @var{ptype}) +This target macro is used in function @code{c_common_nodes_and_builtins} +to iterate through the target specific builtin types for va_list. The +variable @var{idx} is used as iterator. @var{pname} has to be a pointer +to a @code{const char *} and @var{ptype} a pointer to a @code{tree} typed +variable. +The arguments @var{pname} and @var{ptype} are used to store the result of +this macro and are set to the name of the va_list builtin type and its +internal type. +If the return value of this macro is zero, then there is no more element. +Otherwise the @var{IDX} should be increased for the next call of this +macro to iterate through all types. +@end defmac + @defmac APPLY_RESULT_SIZE Define this macro if @samp{untyped_call} and @samp{untyped_return} need more space than is implied by @code{FUNCTION_VALUE_REGNO_P} for diff --git a/gcc/expr.h b/gcc/expr.h index beb44bd80b7..39a51fcfe13 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -342,6 +342,9 @@ extern rtx emit_store_flag_force (rtx, enum rtx_code, rtx, rtx, /* Functions from builtins.c: */ extern rtx expand_builtin (tree, rtx, rtx, enum machine_mode, int); extern tree std_build_builtin_va_list (void); +extern tree std_fn_abi_va_list (tree); +extern tree std_canonical_va_list_type (tree); + extern void std_expand_builtin_va_start (tree, rtx); extern rtx default_expand_builtin (tree, rtx, rtx, enum machine_mode, int); extern void expand_builtin_setjmp_setup (rtx, rtx); diff --git a/gcc/target-def.h b/gcc/target-def.h index 2692e94aabc..7ffb1346021 100644 --- a/gcc/target-def.h +++ b/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, \ diff --git a/gcc/target.h b/gcc/target.h index 012d1c0099b..11852430c8d 100644 --- a/gcc/target.h +++ b/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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 61a522c0bf0..ef05b67d5fd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2008-07-04 Kai Tietz + + * gcc.dg/callabi/callabi.h: New. + * gcc.dg/callabi/vaarg-1.c: New. + * gcc.dg/callabi/vaarg-2.c: New. + * gcc.dg/callabi/vaarg-3.c: New. + * gcc.dg/callabi/func-1.c: New. + 2008-07-04 Richard Sandiford * gcc.target/m68k/interrupt-2.c: New file. diff --git a/gcc/testsuite/gcc.dg/callabi/callabi.h b/gcc/testsuite/gcc.dg/callabi/callabi.h new file mode 100644 index 00000000000..d008ad659cb --- /dev/null +++ b/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 diff --git a/gcc/testsuite/gcc.dg/callabi/func-1.c b/gcc/testsuite/gcc.dg/callabi/func-1.c new file mode 100644 index 00000000000..c727dbe6e53 --- /dev/null +++ b/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 diff --git a/gcc/testsuite/gcc.dg/callabi/vaarg-1.c b/gcc/testsuite/gcc.dg/callabi/vaarg-1.c new file mode 100644 index 00000000000..1e745e56085 --- /dev/null +++ b/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; +} diff --git a/gcc/testsuite/gcc.dg/callabi/vaarg-2.c b/gcc/testsuite/gcc.dg/callabi/vaarg-2.c new file mode 100644 index 00000000000..c9b716194a6 --- /dev/null +++ b/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 */ +/* { dg-do run { target { x86_64-*-* } } } */ +/* { dg-options "-std=gnu99" } */ +#include "callabi.h" + +extern void abort (void); + +#define SZ_ARGS 1ll,2ll,3ll,4ll,5ll,6ll,7ll,0ll + +static +int CALLABI_CROSS fct1 (va_list argp, ...) +{ + long long p1,p2; + int ret = 1; + CROSS_VA_LIST argp_2; + CROSS_VA_START (argp_2,argp); + + do { + p1 = CROSS_VA_ARG (argp_2, long long); + p2 = __va_arg (argp, long long); + if (p1 != p2) + ret = 0; + } while (ret && p1 != 0); + CROSS_VA_END (argp_2); + return ret; +} + +static +int fct2 (int dummy, ...) +{ + va_list argp; + int ret = dummy; + + __va_start (argp, dummy); + ret += fct1 (argp, SZ_ARGS); + __va_end (argp); + return ret; +} + +int main() +{ + if (fct2 (-1, SZ_ARGS) != 0) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/callabi/vaarg-3.c b/gcc/testsuite/gcc.dg/callabi/vaarg-3.c new file mode 100644 index 00000000000..d0d068754e1 --- /dev/null +++ b/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 */ +/* { 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; +} diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 391511f56a7..c50c6cd225b 100644 --- a/gcc/tree-sra.c +++ b/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; diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index d4dfadbced0..da6b7855a81 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -2748,17 +2748,19 @@ optimize_stack_restore (basic_block bb, tree call, block_stmt_iterator i) static tree optimize_stdarg_builtin (tree call) { - tree callee, lhs, rhs; + tree callee, lhs, rhs, cfun_va_list; bool va_list_simple_ptr; if (TREE_CODE (call) != CALL_EXPR) return NULL_TREE; - va_list_simple_ptr = POINTER_TYPE_P (va_list_type_node) - && (TREE_TYPE (va_list_type_node) == void_type_node - || TREE_TYPE (va_list_type_node) == char_type_node); - callee = get_callee_fndecl (call); + + cfun_va_list = targetm.fn_abi_va_list (callee); + va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list) + && (TREE_TYPE (cfun_va_list) == void_type_node + || TREE_TYPE (cfun_va_list) == char_type_node); + switch (DECL_FUNCTION_CODE (callee)) { case BUILT_IN_VA_START: @@ -2773,7 +2775,7 @@ optimize_stdarg_builtin (tree call) lhs = CALL_EXPR_ARG (call, 0); if (!POINTER_TYPE_P (TREE_TYPE (lhs)) || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs))) - != TYPE_MAIN_VARIANT (va_list_type_node)) + != TYPE_MAIN_VARIANT (cfun_va_list)) return NULL_TREE; lhs = build_fold_indirect_ref (lhs); @@ -2792,13 +2794,13 @@ optimize_stdarg_builtin (tree call) lhs = CALL_EXPR_ARG (call, 0); if (!POINTER_TYPE_P (TREE_TYPE (lhs)) || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs))) - != TYPE_MAIN_VARIANT (va_list_type_node)) + != TYPE_MAIN_VARIANT (cfun_va_list)) return NULL_TREE; lhs = build_fold_indirect_ref (lhs); rhs = CALL_EXPR_ARG (call, 1); if (TYPE_MAIN_VARIANT (TREE_TYPE (rhs)) - != TYPE_MAIN_VARIANT (va_list_type_node)) + != TYPE_MAIN_VARIANT (cfun_va_list)) return NULL_TREE; rhs = fold_convert (TREE_TYPE (lhs), rhs); diff --git a/gcc/tree-stdarg.c b/gcc/tree-stdarg.c index 728c37d4d6d..f9228872dc2 100644 --- a/gcc/tree-stdarg.c +++ b/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; -- 2.30.2