https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84891
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Keywords| |wrong-code Status|UNCONFIRMED |NEW Last reconfirmed| |2018-03-16 CC| |jsm28 at gcc dot gnu.org, | |rguenth at gcc dot gnu.org Component|c++ |middle-end Ever confirmed|0 |1 --- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> --- We do /* Maybe fold x * 0 to 0. The expressions aren't the same when x is NaN, since x * 0 is also NaN. Nor are they the same in modes with signed zeros, since multiplying a negative value by 0 gives -0, not +0. */ (simplify (mult @0 real_zerop@1) (if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type)) @1)) that misses !HONOR_INFINITIES. Not sure if that will fix the issue though. It doesn't. So it's tree-complex.c breaking things: int main() () { complex double SR.24; @@ -182,16 +145,18 @@ _16 = std::char_traits<char>::length ("case INF: "); _17 = (long int) _16; std::__ostream_insert<char, std::char_traits<char> > (&cout, "case INF: ", _17); - _15 = __complex__ ( Inf, 0.0) * __complex__ (0.0, 0.0); - MEM[(struct complex *)&D.50322] = _15; + _15 = COMPLEX_EXPR < Nan, 0.0>; + REALPART_EXPR <MEM[(struct complex *)&D.50322]> = Nan; + IMAGPART_EXPR <MEM[(struct complex *)&D.50322]> = 0.0; _6 = std::operator<< <double, char, std::char_traits<char> > (&cout, &D.50322); std::operator<< <std::char_traits<char> > (_6, "\n"); D.50322 ={v} {CLOBBER}; _19 = std::char_traits<char>::length ("case NAN: "); _20 = (long int) _19; std::__ostream_insert<char, std::char_traits<char> > (&cout, "case NAN: ", _20); - _18 = __complex__ ( Nan, 0.0) * __complex__ (0.0, 0.0); - MEM[(struct complex *)&D.50338] = _18; + _18 = COMPLEX_EXPR < Nan, 0.0>; + REALPART_EXPR <MEM[(struct complex *)&D.50338]> = Nan; + IMAGPART_EXPR <MEM[(struct complex *)&D.50338]> = 0.0; _12 = std::operator<< <double, char, std::char_traits<char> > (&cout, &D.50338); std::operator<< <std::char_traits<char> > (_12, "\n"); D.50338 ={v} {CLOBBER}; @@ -203,13 +168,6 @@ not sure why it gets it correct without -fno-signed-zeros... ah, because of /* Return true if T is not a zero constant. In the case of real values, we're only interested in +0.0. */ static int some_nonzerop (tree t) { int zerop = false; /* 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_identical (&TREE_REAL_CST (t), &dconst0); else if (TREE_CODE (t) == FIXED_CST) zerop = fixed_zerop (t); else if (TREE_CODE (t) == INTEGER_CST) zerop = integer_zerop (t); return !zerop; } so we "ignore" +0.0 for -fsigned-zeros completely. The transforms are not guarded by any other flag so we'd need to add !HONOR_NANS and !HONOR_INFINITIES here, too it seems ... Patch: Index: gcc/tree-complex.c =================================================================== --- gcc/tree-complex.c (revision 258584) +++ gcc/tree-complex.c (working copy) @@ -115,7 +115,13 @@ some_nonzerop (tree t) /* 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) + if (TREE_CODE (t) == REAL_CST + /* Not detecting any zero as zero is the guard for invalid + followup transforms. So that has to include 0.0 * NaN + and friends as well. */ + && !HONOR_SIGNED_ZEROS (t) + && !HONOR_NANS (t) + && !HONOR_INFINITIES (t)) zerop = real_identical (&TREE_REAL_CST (t), &dconst0); else if (TREE_CODE (t) == FIXED_CST) zerop = fixed_zerop (t); might be quite pessimizing, so it's probably better to guard the individual "optimizations" properly... (also properly detecting positive zero as zero). The following fixes the testcase as well: Index: gcc/tree-complex.c =================================================================== --- gcc/tree-complex.c (revision 258584) +++ gcc/tree-complex.c (working copy) @@ -358,8 +364,10 @@ complex_propagate::visit_stmt (gimple *s op1_l = find_lattice_value (gimple_assign_rhs1 (stmt)); op2_l = find_lattice_value (gimple_assign_rhs2 (stmt)); - /* Obviously, if either varies, so does the result. */ - if (op1_l == VARYING || op2_l == VARYING) + /* Obviously, if either varies, so does the result. Likewise + if we have to honor NaNs or Infs in nonzero parts. */ + if (op1_l == VARYING || op2_l == VARYING + || HONOR_NANS (lhs) || HONOR_INFINITIES (lhs)) new_l = VARYING; /* Don't prematurely promote variables if we've not yet seen their inputs. */ @@ -1044,6 +1052,9 @@ expand_complex_multiplication (gimple_st tl = al, al = bl, bl = tl; } + if (HONOR_NANS (ar) || HONOR_INFINITIES (ar)) + al = bl = VARYING; + switch (PAIR (al, bl)) { case PAIR (ONLY_REAL, ONLY_REAL): probably the following hunk is needed as well for correctness. @@ -1315,6 +1326,9 @@ expand_complex_division (gimple_stmt_ite { tree rr, ri; + if (HONOR_NANS (ar) || HONOR_INFINITIES (ar)) + al = bl = VARYING; + switch (PAIR (al, bl)) { case PAIR (ONLY_REAL, ONLY_REAL): In the end the lattice is a bit "simple", a more detailed one having info about !NaN, !Inf in the respective components would be more useful. The second patch above means we preserve optimization on plus, minus, negate, conj and equality compares - not sure if those are correct in the presence of Nan/Inf, I didn't double-check these. As said above the guarding against signed zero handling should be moved down to individual optimizations as well (though I guess none survives here?). Joseph do you have any spare cycles checking tree-complex.c for this issue? Do you agree with what I said above?