Bug 36800 - va_arg for _Decimal128 on 32-bit Power mishandled in certain cases
Summary: va_arg for _Decimal128 on 32-bit Power mishandled in certain cases
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.4.0
: P3 normal
Target Milestone: 4.5.0
Assignee: Ben Elliston
URL: http://gcc.gnu.org/ml/gcc-patches/200...
Keywords:
Depends on:
Blocks:
 
Reported: 2008-07-10 23:40 UTC by Joseph S. Myers
Modified: 2009-04-09 21:29 UTC (History)
1 user (show)

See Also:
Host:
Target: powerpc*-*-linux*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2009-03-12 04:55:25


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Joseph S. Myers 2008-07-10 23:40:52 UTC
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.
Comment 1 Ben Elliston 2009-04-02 05:08:43 UTC
Testing a patch.
Comment 2 Ben Elliston 2009-04-09 21:26:59 UTC
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

Comment 3 Ben Elliston 2009-04-09 21:29:01 UTC
Should this be backported to 4.4?g