+2009-03-27 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/39472
+ * config/i386/i386.c (ix86_abi): New.
+ (override_options): Handle -mabi=.
+ (ix86_function_arg_regno_p): Replace DEFAULT_ABI with
+ ix86_abi.
+ (ix86_call_abi_override): Likewise.
+ (init_cumulative_args): Likewise.
+ (function_arg_advance): Likewise.
+ (function_arg_64): Likewise.
+ (function_arg): Likewise.
+ (ix86_pass_by_reference): Likewise.
+ (ix86_function_value_regno_p): Likewise.
+ (ix86_build_builtin_va_list_abi): Likewise.
+ (setup_incoming_varargs_64): Likewise.
+ (is_va_list_char_pointer): Likewise.
+ (ix86_init_machine_status): Likewise.
+ (ix86_reg_parm_stack_space): Use enum calling_abi on
+ call_abi.
+ (ix86_function_type_abi): Return enum calling_abi. Rewrite
+ for 64bit. Replace DEFAULT_ABI with ix86_abi.
+ (ix86_function_abi): Make it static and return enum
+ calling_abi.
+ (ix86_cfun_abi): Return enum calling_abi. Replace DEFAULT_ABI
+ with ix86_abi.
+ (ix86_fn_abi_va_list): Updated.
+
+ * config/i386/i386.h (ix86_abi): New.
+ (STACK_BOUNDARY): Replace DEFAULT_ABI with ix86_abi.
+ (CONDITIONAL_REGISTER_USAGE): Likewise.
+ (CUMULATIVE_ARGS): Change call_abi type to enum calling_abi.
+ (machine_function): Likewise.
+
+ * config/i386/i386.md (untyped_call): Replace DEFAULT_ABI
+ with ix86_abi.
+ * config/i386/cygming.h (TARGET_64BIT_MS_ABI): Likewise.
+ (STACK_BOUNDARY): Likewise.
+ * config/i386/mingw32.h (EXTRA_OS_CPP_BUILTINS): Likewise.
+
+ * config/i386/i386.opt (mabi=): New.
+
+ * config/i386/i386-protos.h (ix86_cfun_abi): Changed to
+ return enum calling_abi.
+ (ix86_function_type_abi): Likewise.
+ (ix86_function_abi): Removed.
+
+ * doc/invoke.texi: Document -mabi= option for x86.
+
2009-03-27 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* builtins.c (real_dconstp): Delete.
#endif
#undef TARGET_64BIT_MS_ABI
-#define TARGET_64BIT_MS_ABI (!cfun ? DEFAULT_ABI == MS_ABI : TARGET_64BIT && cfun->machine->call_abi == MS_ABI)
+#define TARGET_64BIT_MS_ABI (!cfun ? ix86_abi == MS_ABI : TARGET_64BIT && cfun->machine->call_abi == MS_ABI)
#undef DEFAULT_ABI
#define DEFAULT_ABI (TARGET_64BIT ? MS_ABI : SYSV_ABI)
#define CHECK_STACK_LIMIT 4000
#undef STACK_BOUNDARY
-#define STACK_BOUNDARY (DEFAULT_ABI == MS_ABI ? 128 : BITS_PER_WORD)
+#define STACK_BOUNDARY (ix86_abi == MS_ABI ? 128 : BITS_PER_WORD)
/* By default, target has a 80387, uses IEEE compatible arithmetic,
returns float values in the 387 and needs stack probes.
extern bool ix86_sol10_return_in_memory (const_tree,const_tree);
extern rtx ix86_force_to_memory (enum machine_mode, rtx);
extern void ix86_free_from_memory (enum machine_mode);
-extern int ix86_cfun_abi (void);
-extern int ix86_function_abi (const_tree);
-extern int ix86_function_type_abi (const_tree);
+extern enum calling_abi ix86_cfun_abi (void);
+extern enum calling_abi 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);
/* Alignment for incoming stack boundary in bits. */
unsigned int ix86_incoming_stack_boundary;
+/* The abi used by target. */
+enum calling_abi ix86_abi = DEFAULT_ABI;
+
/* Values 1-5: see jump.c */
int ix86_branch_cost;
static bool ix86_can_inline_p (tree, tree);
static void ix86_set_current_function (tree);
+static enum calling_abi ix86_function_abi (const_tree);
+
\f
/* The svr4 ABI for the i386 says that records and unions are returned
in memory. */
error ("bad value (%s) for %sarch=%s %s",
ix86_arch_string, prefix, suffix, sw);
+ /* Validate -mabi= value. */
+ if (ix86_abi_string)
+ {
+ if (strcmp (ix86_abi_string, "sysv") == 0)
+ ix86_abi = SYSV_ABI;
+ else if (strcmp (ix86_abi_string, "ms") == 0)
+ ix86_abi = MS_ABI;
+ else
+ error ("unknown ABI (%s) for %sabi=%s %s",
+ ix86_abi_string, prefix, suffix, sw);
+ }
+
if (ix86_cmodel_string != 0)
{
if (!strcmp (ix86_cmodel_string, "small"))
default ABI. */
/* RAX is used as hidden argument to va_arg functions. */
- if (DEFAULT_ABI == SYSV_ABI && regno == AX_REG)
+ if (ix86_abi == SYSV_ABI && regno == AX_REG)
return true;
- if (DEFAULT_ABI == MS_ABI)
+ if (ix86_abi == MS_ABI)
parm_regs = x86_64_ms_abi_int_parameter_registers;
else
parm_regs = x86_64_int_parameter_registers;
- for (i = 0; i < (DEFAULT_ABI == MS_ABI ? X64_REGPARM_MAX
+ for (i = 0; i < (ix86_abi == MS_ABI ? X64_REGPARM_MAX
: X86_64_REGPARM_MAX); i++)
if (regno == parm_regs[i])
return true;
int
ix86_reg_parm_stack_space (const_tree fndecl)
{
- int call_abi = SYSV_ABI;
+ enum calling_abi call_abi = SYSV_ABI;
if (fndecl != NULL_TREE && TREE_CODE (fndecl) == FUNCTION_DECL)
call_abi = ix86_function_abi (fndecl);
else
/* Returns value SYSV_ABI, MS_ABI dependent on fntype, specifying the
call abi used. */
-int
+enum calling_abi
ix86_function_type_abi (const_tree fntype)
{
if (TARGET_64BIT && fntype != NULL)
{
- int abi;
- if (DEFAULT_ABI == SYSV_ABI)
- abi = lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (fntype)) ? MS_ABI : SYSV_ABI;
- else
- abi = lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)) ? SYSV_ABI : MS_ABI;
-
+ enum calling_abi abi = ix86_abi;
+ if (abi == SYSV_ABI)
+ {
+ if (lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (fntype)))
+ abi = MS_ABI;
+ }
+ else if (lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)))
+ abi = SYSV_ABI;
return abi;
}
- return DEFAULT_ABI;
+ return ix86_abi;
}
-int
+static enum calling_abi
ix86_function_abi (const_tree fndecl)
{
if (! fndecl)
- return DEFAULT_ABI;
+ return ix86_abi;
return ix86_function_type_abi (TREE_TYPE (fndecl));
}
/* Returns value SYSV_ABI, MS_ABI dependent on cfun, specifying the
call abi used. */
-int
+enum calling_abi
ix86_cfun_abi (void)
{
if (! cfun || ! TARGET_64BIT)
- return DEFAULT_ABI;
+ return ix86_abi;
return cfun->machine->call_abi;
}
ix86_call_abi_override (const_tree fndecl)
{
if (fndecl == NULL_TREE)
- cfun->machine->call_abi = DEFAULT_ABI;
+ cfun->machine->call_abi = ix86_abi;
else
cfun->machine->call_abi = ix86_function_type_abi (TREE_TYPE (fndecl));
}
cum->nregs = ix86_regparm;
if (TARGET_64BIT)
{
- if (cum->call_abi != DEFAULT_ABI)
- cum->nregs = DEFAULT_ABI != SYSV_ABI ? X86_64_REGPARM_MAX
+ if (cum->call_abi != ix86_abi)
+ cum->nregs = ix86_abi != SYSV_ABI ? X86_64_REGPARM_MAX
: X64_REGPARM_MAX;
}
if (TARGET_SSE)
cum->sse_nregs = SSE_REGPARM_MAX;
if (TARGET_64BIT)
{
- if (cum->call_abi != DEFAULT_ABI)
- cum->sse_nregs = DEFAULT_ABI != SYSV_ABI ? X86_64_SSE_REGPARM_MAX
+ if (cum->call_abi != ix86_abi)
+ cum->sse_nregs = ix86_abi != SYSV_ABI ? X86_64_SSE_REGPARM_MAX
: X64_SSE_REGPARM_MAX;
}
}
if (type)
mode = type_natural_mode (type, NULL);
- if (TARGET_64BIT && (cum ? cum->call_abi : DEFAULT_ABI) == MS_ABI)
+ if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
function_arg_advance_ms_64 (cum, bytes, words);
else if (TARGET_64BIT)
function_arg_advance_64 (cum, mode, type, words, named);
if (mode == VOIDmode)
return GEN_INT (cum->maybe_vaarg
? (cum->sse_nregs < 0
- ? (cum->call_abi == DEFAULT_ABI
+ ? (cum->call_abi == ix86_abi
? SSE_REGPARM_MAX
- : (DEFAULT_ABI != SYSV_ABI ? X86_64_SSE_REGPARM_MAX
+ : (ix86_abi != SYSV_ABI ? X86_64_SSE_REGPARM_MAX
: X64_SSE_REGPARM_MAX))
: cum->sse_regno)
: -1);
if (type && TREE_CODE (type) == VECTOR_TYPE)
mode = type_natural_mode (type, cum);
- if (TARGET_64BIT && (cum ? cum->call_abi : DEFAULT_ABI) == MS_ABI)
+ if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
return function_arg_ms_64 (cum, mode, omode, named, bytes);
else if (TARGET_64BIT)
return function_arg_64 (cum, mode, omode, type, named);
const_tree type, bool named ATTRIBUTE_UNUSED)
{
/* See Windows x64 Software Convention. */
- if (TARGET_64BIT && (cum ? cum->call_abi : DEFAULT_ABI) == MS_ABI)
+ if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
{
int msize = (int) GET_MODE_SIZE (mode);
if (type)
/* TODO: The function should depend on current function ABI but
builtins.c would need updating then. Therefore we use the
default ABI. */
- if (TARGET_64BIT && DEFAULT_ABI == MS_ABI)
+ if (TARGET_64BIT && ix86_abi == MS_ABI)
return false;
return TARGET_FLOAT_RETURNS_IN_80387;
static tree
ix86_build_builtin_va_list (void)
{
- tree ret = ix86_build_builtin_va_list_abi (DEFAULT_ABI);
+ tree ret = ix86_build_builtin_va_list_abi (ix86_abi);
/* Initialize abi specific va_list builtin types. */
if (TARGET_64BIT)
{
tree t;
- if (DEFAULT_ABI == MS_ABI)
+ if (ix86_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;
}
- if (DEFAULT_ABI != MS_ABI)
+ if (ix86_abi != MS_ABI)
{
t = ix86_build_builtin_va_list_abi (MS_ABI);
if (TREE_CODE (t) != RECORD_TYPE)
int i;
int regparm = ix86_regparm;
- if (cum->call_abi != DEFAULT_ABI)
- regparm = DEFAULT_ABI != SYSV_ABI ? X86_64_REGPARM_MAX : X64_REGPARM_MAX;
+ if (cum->call_abi != ix86_abi)
+ regparm = ix86_abi != SYSV_ABI ? X86_64_REGPARM_MAX : X64_REGPARM_MAX;
/* GPR size of varargs save area. */
if (cfun->va_list_gpr_size)
return true;
canonic = ix86_canonical_va_list_type (type);
return (canonic == ms_va_list_type_node
- || (DEFAULT_ABI == MS_ABI && canonic == va_list_type_node));
+ || (ix86_abi == MS_ABI && canonic == va_list_type_node));
}
/* Implement va_start. */
f = GGC_CNEW (struct machine_function);
f->use_fast_prologue_epilogue_nregs = -1;
f->tls_descriptor_call_expanded_p = 0;
- f->call_abi = DEFAULT_ABI;
+ f->call_abi = ix86_abi;
return f;
}
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)
+ if (ix86_function_abi ((const_tree) fndecl) == MS_ABI)
return ms_va_list_type_node;
else
return sysv_va_list_type_node;
MS_ABI = 1
};
-/* The default abi form used by target. */
+/* The abi used by target. */
+extern enum calling_abi ix86_abi;
+
+/* The default abi used by target. */
#define DEFAULT_ABI SYSV_ABI
/* Subtargets may reset this to 1 in order to enable 96-bit long double
/* Boundary (in *bits*) on which stack pointer should be aligned. */
#define STACK_BOUNDARY \
- (TARGET_64BIT && DEFAULT_ABI == MS_ABI ? 128 : BITS_PER_WORD)
+ (TARGET_64BIT && ix86_abi == MS_ABI ? 128 : BITS_PER_WORD)
/* Stack boundary of the main function guaranteed by OS. */
#define MAIN_STACK_BOUNDARY (TARGET_64BIT ? 128 : 32)
fixed_regs[j] = call_used_regs[j] = 1; \
if (TARGET_64BIT \
&& ((cfun && cfun->machine->call_abi == MS_ABI) \
- || (!cfun && DEFAULT_ABI == MS_ABI))) \
+ || (!cfun && ix86_abi == MS_ABI))) \
{ \
call_used_regs[SI_REG] = 0; \
call_used_regs[DI_REG] = 0; \
int maybe_vaarg; /* true for calls to possibly vardic fncts. */
int float_in_sse; /* 1 if in 32-bit mode SFmode (2 for DFmode) should
be passed in SSE registers. Otherwise 0. */
- int call_abi; /* Set to SYSV_ABI for sysv abi. Otherwise
+ enum calling_abi call_abi; /* Set to SYSV_ABI for sysv abi. Otherwise
MS_ABI for ms abi. */
} CUMULATIVE_ARGS;
int tls_descriptor_call_expanded_p;
/* This value is used for amd64 targets and specifies the current abi
to be used. MS_ABI means ms abi. Otherwise SYSV_ABI means sysv abi. */
- int call_abi;
+ enum calling_abi call_abi;
};
#define ix86_stack_locals (cfun->machine->stack_locals)
? gen_rtx_REG (XCmode, FIRST_FLOAT_REG) : NULL),
operands[0], const0_rtx,
GEN_INT ((TARGET_64BIT
- ? (DEFAULT_ABI == SYSV_ABI
+ ? (ix86_abi == SYSV_ABI
? X86_64_SSE_REGPARM_MAX
: X64_SSE_REGPARM_MAX)
: X86_32_SSE_REGPARM_MAX)
Target RejectNegative Joined Var(ix86_tune_string)
Schedule code for given CPU
+mabi=
+Target RejectNegative Joined Var(ix86_abi_string)
+Generate code that conforms to the given ABI
+
mveclibabi=
Target RejectNegative Joined Var(ix86_veclibabi_string)
Vector library ABI to use
builtin_define_std ("WINNT"); \
builtin_define_with_int_value ("_INTEGRAL_MAX_BITS", \
TYPE_PRECISION (intmax_type_node));\
- if (TARGET_64BIT && DEFAULT_ABI == MS_ABI) \
+ if (TARGET_64BIT && ix86_abi == MS_ABI) \
{ \
builtin_define ("__MINGW64__"); \
builtin_define_std ("WIN64"); \
-m96bit-long-double -mregparm=@var{num} -msseregparm @gol
-mveclibabi=@var{type} -mpc32 -mpc64 -mpc80 -mstackrealign @gol
-momit-leaf-frame-pointer -mno-red-zone -mno-tls-direct-seg-refs @gol
--mcmodel=@var{code-model} @gol
+-mcmodel=@var{code-model} -mabi=@var{name} @gol
-m32 -m64 -mlarge-data-threshold=@var{num} @gol
-mfused-madd -mno-fused-madd -msse2avx}
@option{-funsafe-math-optimizations} have to be enabled. A SVML or ACML ABI
compatible library will have to be specified at link time.
+@item -mabi=@var{name}
+@opindex mabi
+Generate code for the specified calling convention. Permissible values
+are: @samp{sysv} for the ABI used on GNU/Linux and other systems and
+@samp{ms} for the Microsoft ABI. The default is to use the Microsoft
+ABI when targeting Windows. On all other systems, the default is the
+SYSV ABI. You can control this behavior for a specific function by
+using the function attribute @samp{ms_abi}/@samp{sysv_abi}.
+@xref{Function Attributes}.
+
@item -mpush-args
@itemx -mno-push-args
@opindex mpush-args
+2009-03-27 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/39472
+ * gcc.target/x86_64/abi/callabi/func-2a.c: New.
+ * gcc.target/x86_64/abi/callabi/func-2b.c: Likewise.
+ * gcc.target/x86_64/abi/callabi/func-indirect-2a.c: Likewise.
+ * gcc.target/x86_64/abi/callabi/func-indirect-2b.c: Likewise.
+ * gcc.target/x86_64/abi/callabi/vaarg-4a.c: Likewise.
+ * gcc.target/x86_64/abi/callabi/vaarg-4b.c: Likewise.
+ * gcc.target/x86_64/abi/callabi/vaarg-5a.c: Likewise.
+ * gcc.target/x86_64/abi/callabi/vaarg-5b.c: Likewise.
+
2009-03-27 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.dg/torture/builtin-explog-1.c: Remove tests that aren't true
--- /dev/null
+/* Test for cross x86_64<->w64 abi standard calls. */
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* } } */
+/* { dg-options "-O2 -mabi=ms -std=gnu99 -ffast-math -fno-builtin" } */
+/* { dg-additional-sources "func-2b.c" } */
+
+extern void __attribute__ ((sysv_abi)) abort (void);
+long double func_cross (long double, double, float, long, int, char);
+
+long double __attribute__ ((sysv_abi))
+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 __attribute__ ((sysv_abi))
+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;
+}
--- /dev/null
+/* Test for cross x86_64<->w64 abi standard calls. */
+/* { dg-options "-mabi=ms -std=gnu99 -ffast-math -fno-builtin" } */
+
+long double 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;
+}
--- /dev/null
+/* Test for cross x86_64<->w64 abi standard calls via variable. */
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* } } */
+/* { dg-options "-O2 -mabi=ms -std=gnu99 -ffast-math -fno-builtin" } */
+/* { dg-additional-sources "func-indirect-2b.c" } */
+
+extern void __attribute__ ((sysv_abi)) abort (void);
+typedef int (*func)(void *, char *, char *, short, long long);
+extern func get_callback (void);
+
+int __attribute__ ((sysv_abi))
+main ()
+{
+ func callme = get_callback ();
+ if (callme (0, 0, 0, 0x1234, 0x1234567890abcdefLL))
+ abort ();
+ return 0;
+}
--- /dev/null
+/* Test for cross x86_64<->w64 abi standard calls via variable. */
+/* { dg-options "-O2 -mabi=ms -std=gnu99 -ffast-math -fno-builtin" } */
+
+typedef int (*func)(void *, char *, char *, short, long long);
+
+static int
+callback (void *ptr, char *string1, char *string2, short number,
+ long long rand)
+{
+ if (ptr != 0
+ || string1 != 0
+ || string2 != 0
+ || number != 0x1234
+ || rand != 0x1234567890abcdefLL)
+ return 1;
+ else
+ return 0;
+}
+
+func
+get_callback (void)
+{
+ return callback;
+}
--- /dev/null
+/* Test for cross x86_64<->w64 abi va_list calls. */
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* } } */
+/* { dg-options "-O2 -mabi=ms -std=gnu99 -fno-builtin" } */
+/* { dg-additional-sources "vaarg-4b.c" } */
+
+extern __SIZE_TYPE__ __attribute__ ((sysv_abi)) strlen (const char *);
+extern int __attribute__ ((sysv_abi)) sprintf (char *,const char *, ...);
+extern void __attribute__ ((sysv_abi)) abort (void);
+
+extern void do_cpy (char *, ...);
+
+int __attribute__ ((sysv_abi))
+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;
+}
--- /dev/null
+/* Test for cross x86_64<->w64 abi va_list calls. */
+/* { dg-options "-O2 -mabi=ms -std=gnu99 -fno-builtin" } */
+
+#include <stdarg.h>
+
+extern __SIZE_TYPE__ __attribute__ ((sysv_abi)) strlen (const char *);
+extern int __attribute__ ((sysv_abi)) sprintf (char *, const char *, ...);
+
+static void
+vdo_cpy (char *s, va_list argp)
+{
+ __SIZE_TYPE__ len;
+ char *r = s;
+ char *e;
+ *r = 0;
+ for (;;) {
+ e = va_arg (argp, char *);
+ if (*e == 0) break;
+ sprintf (r,"%s", e);
+ r += strlen (r);
+ }
+}
+
+void
+do_cpy (char *s, ...)
+{
+ va_list argp;
+ va_start (argp, s);
+ vdo_cpy (s, argp);
+ va_end (argp);
+}
--- /dev/null
+/* Test for cross x86_64<->w64 abi va_list calls. */
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* } } */
+/* { dg-options "-O2 -mabi=ms -std=gnu99 -fno-builtin" } */
+/* { dg-additional-sources "vaarg-5b.c" } */
+
+extern void __attribute__ ((sysv_abi)) abort (void);
+extern int fct2 (int, ...);
+
+#define SZ_ARGS 1ll,2ll,3ll,4ll,5ll,6ll,7ll,0ll
+
+int __attribute__ ((sysv_abi))
+main()
+{
+ if (fct2 (-1, SZ_ARGS) != 0)
+ abort ();
+ return 0;
+}
--- /dev/null
+/* Test for cross x86_64<->w64 abi va_list calls. */
+/* { dg-options "-O2 -mabi=ms -std=gnu99 -fno-builtin" } */
+
+#include <stdarg.h>
+
+#define SZ_ARGS 1ll,2ll,3ll,4ll,5ll,6ll,7ll,0ll
+
+static int __attribute__ ((sysv_abi))
+fct1 (va_list argp, ...)
+{
+ long long p1,p2;
+ int ret = 1;
+ __builtin_sysv_va_list argp_2;
+
+ __builtin_sysv_va_start (argp_2, argp);
+ do {
+ p1 = va_arg (argp_2, long long);
+ p2 = va_arg (argp, long long);
+ if (p1 != p2)
+ ret = 0;
+ } while (ret && p1 != 0);
+ __builtin_sysv_va_end (argp_2);
+
+ return ret;
+}
+
+int
+fct2 (int dummy, ...)
+{
+ va_list argp;
+ int ret = dummy;
+
+ va_start (argp, dummy);
+ ret += fct1 (argp, SZ_ARGS);
+ va_end (argp);
+ return ret;
+}