diff options
author | Joseph Myers <joseph@codesourcery.com> | 2009-05-08 11:22:08 +0100 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2009-05-08 11:22:08 +0100 |
commit | 2ca862e9dd939d7dd686b771f401012fb9ed9bfe (patch) | |
tree | 0d1b08d95e3e4458bfdcc780995e149747769e39 /gcc | |
parent | cb8e4445ef25e1da025712d0595274b297b78ec1 (diff) | |
download | gcc-2ca862e9dd939d7dd686b771f401012fb9ed9bfe.zip gcc-2ca862e9dd939d7dd686b771f401012fb9ed9bfe.tar.gz gcc-2ca862e9dd939d7dd686b771f401012fb9ed9bfe.tar.bz2 |
re PR c/24581 (Complex arithmetic on special cases is incorrect.)
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:
* 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.
From-SVN: r147281
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/c-typeck.c | 87 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/complex-sign-add.c | 53 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/complex-sign-mixed-add.c | 53 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/complex-sign-mixed-div.c | 45 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/complex-sign-mixed-mul.c | 53 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/complex-sign-mixed-sub.c | 53 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/complex-sign-mul.c | 53 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/complex-sign-sub.c | 53 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/complex-sign.h | 74 | ||||
-rw-r--r-- | gcc/tree-complex.c | 5 |
12 files changed, 547 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 006c508..502da99 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2009-05-08 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. + 2009-05-08 Paolo Bonzini <bonzini@gnu.org> PR rtl-optimization/33928 diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index bef5e38..4d07a88 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -9246,7 +9246,9 @@ build_binary_op (location_t location, enum tree_code code, (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, enum tree_code code, 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. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fc1bccc..1f523be 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2009-05-08 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. + 2009-05-08 Janus Weil <janus@gcc.gnu.org> PR fortran/39876 diff --git a/gcc/testsuite/gcc.dg/torture/complex-sign-add.c b/gcc/testsuite/gcc.dg/torture/complex-sign-add.c new file mode 100644 index 0000000..db92140 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/complex-sign-add.c @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-add.c b/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-add.c new file mode 100644 index 0000000..5548fe4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-add.c @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-div.c b/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-div.c new file mode 100644 index 0000000..4a315dc --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-div.c @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-mul.c b/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-mul.c new file mode 100644 index 0000000..f5b1fc4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-mul.c @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-sub.c b/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-sub.c new file mode 100644 index 0000000..adc3845 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/complex-sign-mixed-sub.c @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/torture/complex-sign-mul.c b/gcc/testsuite/gcc.dg/torture/complex-sign-mul.c new file mode 100644 index 0000000..d9a06a5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/complex-sign-mul.c @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/torture/complex-sign-sub.c b/gcc/testsuite/gcc.dg/torture/complex-sign-sub.c new file mode 100644 index 0000000..94ab17d --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/complex-sign-sub.c @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/torture/complex-sign.h b/gcc/testsuite/gcc.dg/torture/complex-sign.h new file mode 100644 index 0000000..f12e25d --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/complex-sign.h @@ -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) diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c index 7dbc63a..2835220 100644 --- a/gcc/tree-complex.c +++ b/gcc/tree-complex.c @@ -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); |