The following fails on 32-bit hard-float powerpc*-*-linux* (tested for trunk, code inspection indicates present for 4.3 as well). #include <stdarg.h> extern void abort (void); void f (int a, ...) { va_list ap; if (a != 0) abort (); va_start (ap, a); if (va_arg (ap, _Decimal128) != 1.2DL) abort (); if (va_arg (ap, _Decimal128) != 2.34DL) abort (); if (va_arg (ap, _Decimal128) != 3.456DL) abort (); if (va_arg (ap, _Decimal128) != 4.567DL) abort (); if (va_arg (ap, double) != 5.125) abort (); va_end (ap); } int main (void) { f (0, 1.2DL, 2.34DL, 3.456DL, 4.567DL, 5.125); return 0; } Suppose some arguments are passed in floating-point registers using all but f8 and maybe f7 of the registers available for floating-point arguments. Suppose the next argument is _Decimal128, so is passed on the stack because an aligned pair of registers is not available, and that this _Decimal128 argument is one of the variable arguments in a call to a variadic function, and that a following argument is one that would fit in a single floating-point register if the _Decimal128 argument hadn't forced all subsequent floating-point arguments to go on the stack. Then the code to ensure that subsequent va_arg calls after the one getting that _Decimal128 argument do not look in the saved floating-point registers if ((n_reg == 2 && !regalign) || n_reg > 2) { /* Ensure that we don't find any more args in regs. Alignment has taken care of for special cases. */ t = build_gimple_modify_stmt (reg, build_int_cst (TREE_TYPE (reg), 8)); gimplify_and_add (t, pre_p); } does not trigger because regalign is set. But unlike the alignment for pairs of GPRs, the alignment here sets fpr to 7 leaving a subsequent va_arg call thinking it can take a value from f8. I think the fix is simply not to set regalign in this case, but I haven't tested this.
Testing a patch.
Subject: Bug 36800 Author: bje Date: Thu Apr 9 21:26:44 2009 New Revision: 145859 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=145859 Log: PR target/36800 PR target/36800 * config/rs6000/rs6000.c (rs6000_gimplify_va_arg): Do not set regalign for the reg == fpr and TDmode case. testsuite/ * gcc.dg/dfp/pr36800.c: New. Added: trunk/gcc/testsuite/gcc.dg/dfp/pr36800.c Modified: trunk/gcc/ChangeLog trunk/gcc/config/rs6000/rs6000.c trunk/gcc/testsuite/ChangeLog
Should this be backported to 4.4?g