2010-07-16 Jakub Jelinek PR target/44942 * config/i386/i386-protos.h (ix86_function_arg_boundary): Change second argument to const_tree. * config/i386/i386.c (function_arg_advance): If padding needs to be inserted before argument, increment cum->words by number of padding words as well. (contains_aligned_value_p): Change argument to const_tree. (ix86_function_arg_boundary): Change second argument to const_tree. * gcc.c-torture/execute/pr44942.c: New test. * gcc.target/i386/pr44942.c: New test. --- gcc/config/i386/i386-protos.h.jj 2010-07-13 15:56:31.000000000 +0200 +++ gcc/config/i386/i386-protos.h 2010-07-15 12:45:01.000000000 +0200 @@ -137,8 +137,8 @@ extern enum machine_mode ix86_fp_compare extern rtx ix86_libcall_value (enum machine_mode); extern bool ix86_function_value_regno_p (int); extern bool ix86_function_arg_regno_p (int); -extern int ix86_function_arg_boundary (enum machine_mode, tree); -extern bool ix86_solaris_return_in_memory (const_tree,const_tree); +extern int ix86_function_arg_boundary (enum machine_mode, const_tree); +extern bool ix86_solaris_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 enum calling_abi ix86_cfun_abi (void); --- gcc/config/i386/i386.c.jj 2010-07-13 15:56:31.000000000 +0200 +++ gcc/config/i386/i386.c 2010-07-15 12:44:31.000000000 +0200 @@ -6157,9 +6157,8 @@ function_arg_advance_64 (CUMULATIVE_ARGS if (!named && VALID_AVX256_REG_MODE (mode)) return; - if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs)) - cum->words += words; - else if (sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs) + if (examine_argument (mode, type, 0, &int_nregs, &sse_nregs) + && sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs) { cum->nregs -= int_nregs; cum->sse_nregs -= sse_nregs; @@ -6167,7 +6166,11 @@ function_arg_advance_64 (CUMULATIVE_ARGS cum->sse_regno += sse_nregs; } else - cum->words += words; + { + int align = ix86_function_arg_boundary (mode, type) / BITS_PER_WORD; + cum->words = (cum->words + align - 1) & ~(align - 1); + cum->words += words; + } } static void @@ -6508,7 +6511,7 @@ ix86_pass_by_reference (CUMULATIVE_ARGS /* Return true when TYPE should be 128bit aligned for 32bit argument passing ABI. */ static bool -contains_aligned_value_p (tree type) +contains_aligned_value_p (const_tree type) { enum machine_mode mode = TYPE_MODE (type); if (((TARGET_SSE && SSE_REG_MODE_P (mode)) @@ -6558,7 +6561,7 @@ contains_aligned_value_p (tree type) specified mode and type. */ int -ix86_function_arg_boundary (enum machine_mode mode, tree type) +ix86_function_arg_boundary (enum machine_mode mode, const_tree type) { int align; if (type) --- gcc/testsuite/gcc.c-torture/execute/pr44942.c.jj 2010-07-15 13:41:28.000000000 +0200 +++ gcc/testsuite/gcc.c-torture/execute/pr44942.c 2010-07-15 13:46:40.000000000 +0200 @@ -0,0 +1,70 @@ +/* PR target/44942 */ + +#include + +void +test1 (int a, int b, int c, int d, int e, int f, int g, long double h, ...) +{ + int i; + va_list ap; + + va_start (ap, h); + i = va_arg (ap, int); + if (i != 1234) + __builtin_abort (); + va_end (ap); +} + +void +test2 (int a, int b, int c, int d, int e, int f, int g, long double h, int i, + long double j, int k, long double l, int m, long double n, ...) +{ + int o; + va_list ap; + + va_start (ap, n); + o = va_arg (ap, int); + if (o != 1234) + __builtin_abort (); + va_end (ap); +} + +void +test3 (double a, double b, double c, double d, double e, double f, + double g, long double h, ...) +{ + double i; + va_list ap; + + va_start (ap, h); + i = va_arg (ap, double); + if (i != 1234.0) + __builtin_abort (); + va_end (ap); +} + +void +test4 (double a, double b, double c, double d, double e, double f, double g, + long double h, double i, long double j, double k, long double l, + double m, long double n, ...) +{ + double o; + va_list ap; + + va_start (ap, n); + o = va_arg (ap, double); + if (o != 1234.0) + __builtin_abort (); + va_end (ap); +} + +int +main () +{ + test1 (0, 0, 0, 0, 0, 0, 0, 0.0L, 1234); + test2 (0, 0, 0, 0, 0, 0, 0, 0.0L, 0, 0.0L, 0, 0.0L, 0, 0.0L, 1234); + test3 (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0L, 1234.0); + test4 (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0L, 0.0, 0.0L, + 0.0, 0.0L, 0.0, 0.0L, 1234.0); + return 0; +} --- gcc/testsuite/gcc.target/i386/pr44942.c.jj 2010-07-15 13:52:37.000000000 +0200 +++ gcc/testsuite/gcc.target/i386/pr44942.c 2010-07-15 13:53:24.000000000 +0200 @@ -0,0 +1,44 @@ +/* PR target/44942 */ +/* { dg-do run { target lp64 } } */ + +#include +#include + +void +test1 (double a, double b, double c, double d, double e, double f, + double g, __m128d h, ...) +{ + double i; + va_list ap; + + va_start (ap, h); + i = va_arg (ap, double); + if (i != 1234.0) + __builtin_abort (); + va_end (ap); +} + +void +test2 (double a, double b, double c, double d, double e, double f, double g, + __m128d h, double i, __m128d j, double k, __m128d l, + double m, __m128d n, ...) +{ + double o; + va_list ap; + + va_start (ap, n); + o = va_arg (ap, double); + if (o != 1234.0) + __builtin_abort (); + va_end (ap); +} + +int +main () +{ + __m128d m = _mm_set1_pd (7.0); + test1 (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, m, 1234.0); + test2 (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, m, 0.0, m, + 0.0, m, 0.0, m, 1234.0); + return 0; +}