This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Fix complex arithmetic and signed zeros


On Thu, May 7, 2009 at 8:27 PM, Joseph S. Myers <joseph@codesourcery.com> wrote:
> This patch implements the C99 requirements that arithmetic between one
> real and one complex operand does not convert the real operand to a
> complex type. ?This avoids excess operations on zero values in such
> cases, which are inefficient and can lead to the wrong sign of zero in
> the result (recall that positive and negative zero add to positive
> zero in all rounding modes except towards negative infinity). ?There
> appear to be no specific requirements regarding the result of
> real/complex division that make converting both operands to a common
> complex type there wrong, and that case might also need a new libgcc
> function or other special handling to avoid the conversion, so nothing
> is done about that case.
>
> There is some code in tree-complex.c that tries to optimize complex
> arithmetic with one operand real or imaginary, but if there are two
> complex operands then that is different from the case of one real and
> one complex operand because of the handling of signed zeros. ?Thus
> this must be disabled if flag_signed_zeros to get the correct
> semantics.
>
> Note that the absence of imaginary types means that expressions of the
> form (a + b * I) may still yield unwanted results in some cases
> because of b * I being b * (0.0 + 1.0i). ?As far as I know this
> (signed zeros in complex numbers) is the only use of imaginary types,
> and they are not a generally implemented feature of C99 (Annex G is an
> informative Annex, not normative; the Power ABI working group did not
> find any sign of compilers for Power Architecture that implemented
> these types). ?So I do not propose to change anything regarding their
> unimplemented state in GCC.
>
> I believe the only piece needed after this patch to make complex
> numbers support Done in c99status.html is fixing complex arithmetic
> folding (PR 30789), likely using MPC.
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu. ?OK to
> commit (the tree-complex.c part)?

Ok.

Thanks,
RIchard.

> The C front-end code checks flag_signed_zeros because it appears the
> language-independent compiler is better with -fno-signed-zeros at
> optimizing the complex arithmetic than at optimizing the accurately
> represented real/complex arithmetic. ?Without that check,
> gcc.dg/builtins-20.c, gcc.dg/builtins-54.c and gcc.dg/pr30172-1.c fail
> (the last is checking an early GIMPLE dump before most optimizations,
> but the first two do suggest a real problem). ?The complicated ENCODE
> code in the testcases is because if you initialize both halves of a
> complex number using __real__ and __imag__ assignments (the simplest
> way of putting known values, including signed zeros, in both halves),
> the compiler hasn't worked out that the complex number has a constant
> value by the time it gets to lowering complex arithmetic, so tests
> using __real__ and __imag__ assignments wouldn't detect the
> problematic transformations for complex numbers with one part zero.
>
> 2009-05-07 ?Joseph Myers ?<joseph@codesourcery.com>
>
> ? ? ? ?PR c/24581
> ? ? ? ?* c-typeck.c (build_binary_op): Handle arithmetic between one real
> ? ? ? ?and one complex operand specially.
> ? ? ? ?* tree-complex.c (some_nonzerop): Do not identify a real value as
> ? ? ? ?zero if flag_signed_zeros.
>
> testsuite:
> 2009-05-07 ?Joseph Myers ?<joseph@codesourcery.com>
>
> ? ? ? ?PR c/24581
> ? ? ? ?* gcc.dg/torture/complex-sign.h: New header.
> ? ? ? ?* gcc.dg/torture/complex-sign-add.c,
> ? ? ? ?gcc.dg/torture/complex-sign-mixed-add.c,
> ? ? ? ?gcc.dg/torture/complex-sign-mixed-div.c,
> ? ? ? ?gcc.dg/torture/complex-sign-mixed-mul.c,
> ? ? ? ?gcc.dg/torture/complex-sign-mixed-sub.c,
> ? ? ? ?gcc.dg/torture/complex-sign-mul.c,
> ? ? ? ?gcc.dg/torture/complex-sign-sub.c: New tests.
>
> Index: tree-complex.c
> ===================================================================
> --- tree-complex.c ? ? ?(revision 147199)
> +++ tree-complex.c ? ? ?(working copy)
> @@ -99,7 +99,10 @@ some_nonzerop (tree t)
> ?{
> ? int zerop = false;
>
> - ?if (TREE_CODE (t) == REAL_CST)
> + ?/* Operations with real or imaginary part of a complex number zero
> + ? ? cannot be treated the same as operations with a real or imaginary
> + ? ? operand if we care about the signs of zeros in the result. ?*/
> + ?if (TREE_CODE (t) == REAL_CST && !flag_signed_zeros)
> ? ? zerop = REAL_VALUES_IDENTICAL (TREE_REAL_CST (t), dconst0);
> ? else if (TREE_CODE (t) == FIXED_CST)
> ? ? zerop = fixed_zerop (t);
> Index: testsuite/gcc.dg/torture/complex-sign-mixed-add.c
> ===================================================================
> --- testsuite/gcc.dg/torture/complex-sign-mixed-add.c ? (revision 0)
> +++ testsuite/gcc.dg/torture/complex-sign-mixed-add.c ? (revision 0)
> @@ -0,0 +1,53 @@
> +/* Test complex arithmetic with signed zeros. ?Mixed real/complex
> + ? addition. ?*/
> +/* { dg-do run } */
> +/* { dg-options "-std=gnu99" } */
> +
> +#include "complex-sign.h"
> +
> +#define CHECK_ADD(TYPE, COPY, ZERO, ZEROI) ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, +, +, +, +, +, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, +, +, +, -, +, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, +, +, -, +, +, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, +, +, -, -, +, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, +, -, +, +, +, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, +, -, +, -, +, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, +, -, -, +, -, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, +, -, -, -, -, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, +, +, +, +, ZERO, +, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, +, +, +, -, ZERO, +, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, +, +, -, +, ZERO, +, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, +, +, -, -, ZERO, +, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, +, -, +, +, ZERO, +, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, +, -, +, -, ZERO, -, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, +, -, -, +, ZERO, +, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, +, -, -, -, ZERO, -, -); ?\
> + ?} while (0)
> +
> +void
> +check_add_float (void)
> +{
> + ?CHECK_ADD (float, __builtin_copysignf, 0.0f, 0.0if);
> +}
> +
> +void
> +check_add_double (void)
> +{
> + ?CHECK_ADD (double, __builtin_copysign, 0.0, 0.0i);
> +}
> +
> +void
> +check_add_long_double (void)
> +{
> + ?CHECK_ADD (long double, __builtin_copysignl, 0.0l, 0.0il);
> +}
> +
> +int
> +main (void)
> +{
> + ?check_add_float ();
> + ?check_add_double ();
> + ?check_add_long_double ();
> + ?exit (0);
> +}
> Index: testsuite/gcc.dg/torture/complex-sign-mixed-sub.c
> ===================================================================
> --- testsuite/gcc.dg/torture/complex-sign-mixed-sub.c ? (revision 0)
> +++ testsuite/gcc.dg/torture/complex-sign-mixed-sub.c ? (revision 0)
> @@ -0,0 +1,53 @@
> +/* Test complex arithmetic with signed zeros. ?Mixed real/complex
> + ? subtraction. ?*/
> +/* { dg-do run } */
> +/* { dg-options "-std=gnu99" } */
> +
> +#include "complex-sign.h"
> +
> +#define CHECK_SUB(TYPE, COPY, ZERO, ZEROI) ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, -, +, +, +, +, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, -, +, +, -, +, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, -, +, -, +, +, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, -, +, -, -, +, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, -, -, +, +, -, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, -, -, +, -, -, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, -, -, -, +, +, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, -, -, -, -, +, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, -, +, +, +, ZERO, +, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, -, +, +, -, ZERO, +, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, -, +, -, +, ZERO, +, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, -, +, -, -, ZERO, +, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, -, -, +, +, ZERO, -, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, -, -, +, -, ZERO, +, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, -, -, -, +, ZERO, -, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, -, -, -, -, ZERO, +, -); ?\
> + ?} while (0)
> +
> +void
> +check_sub_float (void)
> +{
> + ?CHECK_SUB (float, __builtin_copysignf, 0.0f, 0.0if);
> +}
> +
> +void
> +check_sub_double (void)
> +{
> + ?CHECK_SUB (double, __builtin_copysign, 0.0, 0.0i);
> +}
> +
> +void
> +check_sub_long_double (void)
> +{
> + ?CHECK_SUB (long double, __builtin_copysignl, 0.0l, 0.0il);
> +}
> +
> +int
> +main (void)
> +{
> + ?check_sub_float ();
> + ?check_sub_double ();
> + ?check_sub_long_double ();
> + ?exit (0);
> +}
> Index: testsuite/gcc.dg/torture/complex-sign-mul.c
> ===================================================================
> --- testsuite/gcc.dg/torture/complex-sign-mul.c (revision 0)
> +++ testsuite/gcc.dg/torture/complex-sign-mul.c (revision 0)
> @@ -0,0 +1,53 @@
> +/* Test complex arithmetic with signed zeros. ?Pure complex
> + ? multiplication. ?*/
> +/* { dg-do run } */
> +/* { dg-options "-std=gnu99" } */
> +
> +#include "complex-sign.h"
> +
> +#define CHECK_MUL(TYPE, COPY, ZERO, ZEROI) ? ? ? ? ? ? ? ? ? ? \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, +, +, +, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, +, +, +, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, +, +, -, +, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, +, +, -, -, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, +, -, +, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, +, -, +, -, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, +, -, -, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, +, -, -, -, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, -, +, +, +, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, -, +, +, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, -, +, -, +, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, -, +, -, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, -, -, +, +, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, -, -, +, -, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, -, -, -, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, *, -, -, -, -, +, +); ? ? ? ?\
> + ?} while (0)
> +
> +void
> +check_mul_float (void)
> +{
> + ?CHECK_MUL (float, __builtin_copysignf, 0.0f, 0.0if);
> +}
> +
> +void
> +check_mul_double (void)
> +{
> + ?CHECK_MUL (double, __builtin_copysign, 0.0, 0.0i);
> +}
> +
> +void
> +check_mul_long_double (void)
> +{
> + ?CHECK_MUL (long double, __builtin_copysignl, 0.0l, 0.0il);
> +}
> +
> +int
> +main (void)
> +{
> + ?check_mul_float ();
> + ?check_mul_double ();
> + ?check_mul_long_double ();
> + ?exit (0);
> +}
> Index: testsuite/gcc.dg/torture/complex-sign.h
> ===================================================================
> --- testsuite/gcc.dg/torture/complex-sign.h ? ? (revision 0)
> +++ testsuite/gcc.dg/torture/complex-sign.h ? ? (revision 0)
> @@ -0,0 +1,74 @@
> +/* Common header for complex arithmetic sign tests. ?*/
> +
> +extern void abort (void);
> +extern void exit (int);
> +
> +#define CHECK_RES(VALUE, COPY, SIGN_REAL, SIGN_IMAG) ? ? ? ? ? \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?if ((VALUE) != 0 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? || COPY (1.0, __real__ (VALUE)) != SIGN_REAL 1.0 ? ? ? ?\
> + ? ? ? || COPY (1.0, __imag__ (VALUE)) != SIGN_IMAG 1.0) ? ? ? \
> + ? ? ?abort (); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?} while (0)
> +
> +/* This definition is intended to work with or without imaginary
> + ? types, as long as mixed real/complex arithmetic is handled
> + ? correctly. ?*/
> +#define ENCODE(ZERO, ZEROI, SA, SB) ? ? ? ? ? ? ? ? ? ?\
> + ?(SA 1 == 1 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? SB 1 == 1 ? ZERO + ZEROI : ZERO - ZEROI ? ? ? ? ? \
> + ? : SB 1 == 1 ? -(ZERO - ZEROI) : -(ZERO + ZEROI))
> +
> +#define CHECK_ARITH(TYPE, COPY, ZERO, ZEROI, OP, S1, S2, S3, S4, SR, SI) \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?_Complex TYPE a1, b1, c1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?volatile _Complex TYPE a2, b2, c2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?a1 = ENCODE(ZERO, ZEROI, S1, S2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?CHECK_RES (a1, COPY, S1, S2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?b1 = ENCODE(ZERO, ZEROI, S3, S4); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?CHECK_RES (b1, COPY, S3, S4); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?c1 = a1 OP b1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_RES (c1, COPY, SR, SI); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?a2 = ENCODE(ZERO, ZEROI, S1, S2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?CHECK_RES (a2, COPY, S1, S2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?b2 = ENCODE(ZERO, ZEROI, S3, S4); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?CHECK_RES (b2, COPY, S3, S4); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?c2 = a2 OP b2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_RES (c2, COPY, SR, SI); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?} while (0)
> +
> +#define CHECK_ARITH_RC(TYPE, COPY, ZERO, ZEROI, OP, S1, S3, S4, SR, SI) \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?TYPE a1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?_Complex TYPE b1, c1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?volatile TYPE a2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?volatile _Complex TYPE b2, c2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?a1 = S1 ZERO; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?b1 = ENCODE(ZERO, ZEROI, S3, S4); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?CHECK_RES (b1, COPY, S3, S4); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?c1 = a1 OP b1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_RES (c1, COPY, SR, SI); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?a2 = S1 ZERO; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?b2 = ENCODE(ZERO, ZEROI, S3, S4); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?CHECK_RES (b2, COPY, S3, S4); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?c2 = a2 OP b2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_RES (c2, COPY, SR, SI); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?} while (0)
> +
> +#define CHECK_ARITH_CR(TYPE, COPY, ZERO, ZEROI, OP, S1, S2, S3, V3, SR, SI) \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?_Complex TYPE a1, c1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?TYPE b1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?volatile _Complex TYPE a2, c2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?volatile TYPE b2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?a1 = ENCODE(ZERO, ZEROI, S1, S2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?CHECK_RES (a1, COPY, S1, S2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?b1 = S3 V3; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?c1 = a1 OP b1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_RES (c1, COPY, SR, SI); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?a2 = ENCODE(ZERO, ZEROI, S1, S2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?CHECK_RES (a2, COPY, S1, S2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?b2 = S3 V3; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ?c2 = a2 OP b2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_RES (c2, COPY, SR, SI); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?} while (0)
> Index: testsuite/gcc.dg/torture/complex-sign-mixed-mul.c
> ===================================================================
> --- testsuite/gcc.dg/torture/complex-sign-mixed-mul.c ? (revision 0)
> +++ testsuite/gcc.dg/torture/complex-sign-mixed-mul.c ? (revision 0)
> @@ -0,0 +1,53 @@
> +/* Test complex arithmetic with signed zeros. ?Mixed real/complex
> + ? multiplication. ?*/
> +/* { dg-do run } */
> +/* { dg-options "-std=gnu99" } */
> +
> +#include "complex-sign.h"
> +
> +#define CHECK_MUL(TYPE, COPY, ZERO, ZEROI) ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, *, +, +, +, +, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, *, +, +, -, +, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, *, +, -, +, -, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, *, +, -, -, -, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, *, -, +, +, -, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, *, -, +, -, -, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, *, -, -, +, +, -); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_RC (TYPE, COPY, ZERO, ZEROI, *, -, -, -, +, +); ? ? ? ? ? ? ? ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, *, +, +, +, ZERO, +, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, *, +, +, -, ZERO, -, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, *, +, -, +, ZERO, +, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, *, +, -, -, ZERO, -, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, *, -, +, +, ZERO, -, +); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, *, -, +, -, ZERO, +, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, *, -, -, +, ZERO, -, -); ?\
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, *, -, -, -, ZERO, +, +); ?\
> + ?} while (0)
> +
> +void
> +check_mul_float (void)
> +{
> + ?CHECK_MUL (float, __builtin_copysignf, 0.0f, 0.0if);
> +}
> +
> +void
> +check_mul_double (void)
> +{
> + ?CHECK_MUL (double, __builtin_copysign, 0.0, 0.0i);
> +}
> +
> +void
> +check_mul_long_double (void)
> +{
> + ?CHECK_MUL (long double, __builtin_copysignl, 0.0l, 0.0il);
> +}
> +
> +int
> +main (void)
> +{
> + ?check_mul_float ();
> + ?check_mul_double ();
> + ?check_mul_long_double ();
> + ?exit (0);
> +}
> Index: testsuite/gcc.dg/torture/complex-sign-add.c
> ===================================================================
> --- testsuite/gcc.dg/torture/complex-sign-add.c (revision 0)
> +++ testsuite/gcc.dg/torture/complex-sign-add.c (revision 0)
> @@ -0,0 +1,53 @@
> +/* Test complex arithmetic with signed zeros. ?Pure complex
> + ? addition. ?*/
> +/* { dg-do run } */
> +/* { dg-options "-std=gnu99" } */
> +
> +#include "complex-sign.h"
> +
> +#define CHECK_ADD(TYPE, COPY, ZERO, ZEROI) ? ? ? ? ? ? ? ? ? ? \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, +, +, +, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, +, +, +, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, +, +, -, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, +, +, -, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, +, -, +, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, +, -, +, -, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, +, -, -, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, +, -, -, -, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, -, +, +, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, -, +, +, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, -, +, -, +, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, -, +, -, -, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, -, -, +, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, -, -, +, -, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, -, -, -, +, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, +, -, -, -, -, -, -); ? ? ? ?\
> + ?} while (0)
> +
> +void
> +check_add_float (void)
> +{
> + ?CHECK_ADD (float, __builtin_copysignf, 0.0f, 0.0if);
> +}
> +
> +void
> +check_add_double (void)
> +{
> + ?CHECK_ADD (double, __builtin_copysign, 0.0, 0.0i);
> +}
> +
> +void
> +check_add_long_double (void)
> +{
> + ?CHECK_ADD (long double, __builtin_copysignl, 0.0l, 0.0il);
> +}
> +
> +int
> +main (void)
> +{
> + ?check_add_float ();
> + ?check_add_double ();
> + ?check_add_long_double ();
> + ?exit (0);
> +}
> Index: testsuite/gcc.dg/torture/complex-sign-sub.c
> ===================================================================
> --- testsuite/gcc.dg/torture/complex-sign-sub.c (revision 0)
> +++ testsuite/gcc.dg/torture/complex-sign-sub.c (revision 0)
> @@ -0,0 +1,53 @@
> +/* Test complex arithmetic with signed zeros. ?Pure complex
> + ? subtraction. ?*/
> +/* { dg-do run } */
> +/* { dg-options "-std=gnu99" } */
> +
> +#include "complex-sign.h"
> +
> +#define CHECK_SUB(TYPE, COPY, ZERO, ZEROI) ? ? ? ? ? ? ? ? ? ? \
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, +, +, +, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, +, +, +, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, +, +, -, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, +, +, -, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, +, -, +, +, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, +, -, +, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, +, -, -, +, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, +, -, -, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, -, +, +, +, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, -, +, +, -, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, -, +, -, +, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, -, +, -, -, +, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, -, -, +, +, -, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, -, -, +, -, -, +); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, -, -, -, +, +, -); ? ? ? ?\
> + ? ?CHECK_ARITH (TYPE, COPY, ZERO, ZEROI, -, -, -, -, -, +, +); ? ? ? ?\
> + ?} while (0)
> +
> +void
> +check_sub_float (void)
> +{
> + ?CHECK_SUB (float, __builtin_copysignf, 0.0f, 0.0if);
> +}
> +
> +void
> +check_sub_double (void)
> +{
> + ?CHECK_SUB (double, __builtin_copysign, 0.0, 0.0i);
> +}
> +
> +void
> +check_sub_long_double (void)
> +{
> + ?CHECK_SUB (long double, __builtin_copysignl, 0.0l, 0.0il);
> +}
> +
> +int
> +main (void)
> +{
> + ?check_sub_float ();
> + ?check_sub_double ();
> + ?check_sub_long_double ();
> + ?exit (0);
> +}
> Index: testsuite/gcc.dg/torture/complex-sign-mixed-div.c
> ===================================================================
> --- testsuite/gcc.dg/torture/complex-sign-mixed-div.c ? (revision 0)
> +++ testsuite/gcc.dg/torture/complex-sign-mixed-div.c ? (revision 0)
> @@ -0,0 +1,45 @@
> +/* Test complex arithmetic with signed zeros. ?Mixed real/complex
> + ? division. ?*/
> +/* { dg-do run } */
> +/* { dg-options "-std=gnu99" } */
> +
> +#include "complex-sign.h"
> +
> +#define CHECK_DIV(TYPE, COPY, ZERO, ZEROI, ONE) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ?do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, /, +, +, +, ONE, +, +); ? \
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, /, +, +, -, ONE, -, -); ? \
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, /, +, -, +, ONE, +, -); ? \
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, /, +, -, -, ONE, -, +); ? \
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, /, -, +, +, ONE, -, +); ? \
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, /, -, +, -, ONE, +, -); ? \
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, /, -, -, +, ONE, -, -); ? \
> + ? ?CHECK_ARITH_CR (TYPE, COPY, ZERO, ZEROI, /, -, -, -, ONE, +, +); ? \
> + ?} while (0)
> +
> +void
> +check_div_float (void)
> +{
> + ?CHECK_DIV (float, __builtin_copysignf, 0.0f, 0.0if, 1.0f);
> +}
> +
> +void
> +check_div_double (void)
> +{
> + ?CHECK_DIV (double, __builtin_copysign, 0.0, 0.0i, 1.0);
> +}
> +
> +void
> +check_div_long_double (void)
> +{
> + ?CHECK_DIV (long double, __builtin_copysignl, 0.0l, 0.0il, 1.0l);
> +}
> +
> +int
> +main (void)
> +{
> + ?check_div_float ();
> + ?check_div_double ();
> + ?check_div_long_double ();
> + ?exit (0);
> +}
> Index: c-typeck.c
> ===================================================================
> --- c-typeck.c ?(revision 147199)
> +++ c-typeck.c ?(working copy)
> @@ -9246,7 +9246,9 @@ build_binary_op (location_t location, en
> ? ? ? (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
> ? ? ? ?|| code1 == FIXED_POINT_TYPE || code1 == VECTOR_TYPE))
> ? ? {
> - ? ? ?int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
> + ? ? ?bool first_complex = (code0 == COMPLEX_TYPE);
> + ? ? ?bool second_complex = (code1 == COMPLEX_TYPE);
> + ? ? ?int none_complex = (!first_complex && !second_complex);
>
> ? ? ? if (shorten || common || short_compare)
> ? ? ? ?{
> @@ -9255,6 +9257,89 @@ build_binary_op (location_t location, en
> ? ? ? ? ? ?return error_mark_node;
> ? ? ? ?}
>
> + ? ? ?if (first_complex != second_complex
> + ? ? ? ? && (code == PLUS_EXPR
> + ? ? ? ? ? ? || code == MINUS_EXPR
> + ? ? ? ? ? ? || code == MULT_EXPR
> + ? ? ? ? ? ? || (code == TRUNC_DIV_EXPR && first_complex))
> + ? ? ? ? && TREE_CODE (TREE_TYPE (result_type)) == REAL_TYPE
> + ? ? ? ? && flag_signed_zeros)
> + ? ? ? {
> + ? ? ? ? /* An operation on mixed real/complex operands must be
> + ? ? ? ? ? ?handled specially, but the language-independent code can
> + ? ? ? ? ? ?more easily optimize the plain complex arithmetic if
> + ? ? ? ? ? ?-fno-signed-zeros. ?*/
> + ? ? ? ? tree real_type = TREE_TYPE (result_type);
> + ? ? ? ? tree real, imag;
> + ? ? ? ? if (type0 != orig_type0 || type1 != orig_type1)
> + ? ? ? ? ? {
> + ? ? ? ? ? ? gcc_assert (may_need_excess_precision && common);
> + ? ? ? ? ? ? real_result_type = c_common_type (orig_type0, orig_type1);
> + ? ? ? ? ? }
> + ? ? ? ? if (first_complex)
> + ? ? ? ? ? {
> + ? ? ? ? ? ? if (TREE_TYPE (op0) != result_type)
> + ? ? ? ? ? ? ? op0 = convert_and_check (result_type, op0);
> + ? ? ? ? ? ? if (TREE_TYPE (op1) != real_type)
> + ? ? ? ? ? ? ? op1 = convert_and_check (real_type, op1);
> + ? ? ? ? ? }
> + ? ? ? ? else
> + ? ? ? ? ? {
> + ? ? ? ? ? ? if (TREE_TYPE (op0) != real_type)
> + ? ? ? ? ? ? ? op0 = convert_and_check (real_type, op0);
> + ? ? ? ? ? ? if (TREE_TYPE (op1) != result_type)
> + ? ? ? ? ? ? ? op1 = convert_and_check (result_type, op1);
> + ? ? ? ? ? }
> + ? ? ? ? if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
> + ? ? ? ? ? return error_mark_node;
> + ? ? ? ? if (first_complex)
> + ? ? ? ? ? {
> + ? ? ? ? ? ? op0 = c_save_expr (op0);
> + ? ? ? ? ? ? real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?op0, 1);
> + ? ? ? ? ? ? imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?op0, 1);
> + ? ? ? ? ? ? switch (code)
> + ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? case MULT_EXPR:
> + ? ? ? ? ? ? ? case TRUNC_DIV_EXPR:
> + ? ? ? ? ? ? ? ? imag = build2 (resultcode, real_type, imag, op1);
> + ? ? ? ? ? ? ? ? /* Fall through. ?*/
> + ? ? ? ? ? ? ? case PLUS_EXPR:
> + ? ? ? ? ? ? ? case MINUS_EXPR:
> + ? ? ? ? ? ? ? ? real = build2 (resultcode, real_type, real, op1);
> + ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? default:
> + ? ? ? ? ? ? ? ? gcc_unreachable();
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? }
> + ? ? ? ? else
> + ? ? ? ? ? {
> + ? ? ? ? ? ? op1 = c_save_expr (op1);
> + ? ? ? ? ? ? real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?op1, 1);
> + ? ? ? ? ? ? imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?op1, 1);
> + ? ? ? ? ? ? switch (code)
> + ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? case MULT_EXPR:
> + ? ? ? ? ? ? ? ? imag = build2 (resultcode, real_type, op0, imag);
> + ? ? ? ? ? ? ? ? /* Fall through. ?*/
> + ? ? ? ? ? ? ? case PLUS_EXPR:
> + ? ? ? ? ? ? ? ? real = build2 (resultcode, real_type, op0, real);
> + ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? case MINUS_EXPR:
> + ? ? ? ? ? ? ? ? real = build2 (resultcode, real_type, op0, real);
> + ? ? ? ? ? ? ? ? imag = build1 (NEGATE_EXPR, real_type, imag);
> + ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? default:
> + ? ? ? ? ? ? ? ? gcc_unreachable();
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? }
> + ? ? ? ? ret = build2 (COMPLEX_EXPR, result_type, real, imag);
> + ? ? ? ? goto return_build_binary_op;
> + ? ? ? }
> +
> ? ? ? /* For certain operations (which identify themselves by shorten != 0)
> ? ? ? ? if both args were extended from the same smaller type,
> ? ? ? ? do the arithmetic in that type and then extend.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]