Hi! noce_try_abs optimizes these cases normal abs, which doesn't really care if the original condition is x < 0 ? -x : x or x <= 0 ? -x : x, but also the x < 0 ? ~x : x case. But in this case it is significant whether for x == 0 ~x or x applies; the following patch limits the one_cmpl optimization to those cases where the optimized expression computes the same value.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/5.3? 2015-11-18 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/68376 * ifcvt.c (noce_try_abs): Disable one_cmpl optimization if encountering x <= 0 ? ~x : x or x > 0 ? ~x : x. * gcc.c-torture/execute/pr68376-1.c: New test. * gcc.c-torture/execute/pr68376-2.c: New test. --- gcc/ifcvt.c.jj 2015-11-14 19:35:54.000000000 +0100 +++ gcc/ifcvt.c 2015-11-18 11:02:48.645771477 +0100 @@ -2595,12 +2595,49 @@ noce_try_abs (struct noce_if_info *if_in /* Work around funny ideas get_condition has wrt canonicalization. Note that these rtx constants are known to be CONST_INT, and - therefore imply integer comparisons. */ + therefore imply integer comparisons. + The one_cmpl case is more complicated, as we want to handle + only x < 0 ? ~x : x or x >= 0 ? ~x : x but not + x <= 0 ? ~x : x or x > 0 ? ~x : x, as the latter two + have different result for x == 0. */ if (c == constm1_rtx && GET_CODE (cond) == GT) - ; + { + if (one_cmpl && negate) + return FALSE; + } else if (c == const1_rtx && GET_CODE (cond) == LT) - ; - else if (c != CONST0_RTX (GET_MODE (b))) + { + if (one_cmpl && !negate) + return FALSE; + } + else if (c == CONST0_RTX (GET_MODE (b))) + { + if (one_cmpl) + switch (GET_CODE (cond)) + { + case GT: + if (!negate) + return FALSE; + break; + case GE: + /* >= 0 is the same case as above > -1. */ + if (negate) + return FALSE; + break; + case LT: + if (negate) + return FALSE; + break; + case LE: + /* <= 0 is the same case as above < 1. */ + if (!negate) + return FALSE; + break; + default: + return FALSE; + } + } + else return FALSE; /* Determine what sort of operation this is. */ --- gcc/testsuite/gcc.c-torture/execute/pr68376-1.c.jj 2015-11-18 11:12:33.251522987 +0100 +++ gcc/testsuite/gcc.c-torture/execute/pr68376-1.c 2015-11-18 11:12:24.000000000 +0100 @@ -0,0 +1,24 @@ +/* PR rtl-optimization/68376 */ + +int a, b, c = 1; +signed char d; + +int +main () +{ + for (; a < 1; a++) + for (; b < 1; b++) + { + signed char e = ~d; + if (d < 1) + e = d; + d = e; + if (!c) + __builtin_abort (); + } + + if (d != 0) + __builtin_abort (); + + return 0; +} --- gcc/testsuite/gcc.c-torture/execute/pr68376-2.c.jj 2015-11-18 11:12:36.209481252 +0100 +++ gcc/testsuite/gcc.c-torture/execute/pr68376-2.c 2015-11-18 11:10:55.000000000 +0100 @@ -0,0 +1,41 @@ +/* PR rtl-optimization/68376 */ + +extern void abort (void); + +__attribute__((noinline, noclone)) int +f1 (int x) +{ + return x < 0 ? ~x : x; +} + +__attribute__((noinline, noclone)) int +f2 (int x) +{ + return x < 0 ? x : ~x; +} + +__attribute__((noinline, noclone)) int +f3 (int x) +{ + return x <= 0 ? ~x : x; +} + +__attribute__((noinline, noclone)) int +f4 (int x) +{ + return x <= 0 ? x : ~x; +} + +int +main () +{ + if (f1 (5) != 5 || f1 (-5) != 4 || f1 (0) != 0) + abort (); + if (f2 (5) != -6 || f2 (-5) != -5 || f2 (0) != -1) + abort (); + if (f3 (5) != 5 || f3 (-5) != 4 || f3 (0) != -1) + abort (); + if (f4 (5) != -6 || f4 (-5) != -5 || f4 (0) != 0) + abort (); + return 0; +} Jakub