https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128588

            Bug ID: 128588
           Summary: [14/15/16/17 Regression] wrong code: if-to-switch
                    turns (a | b) != 0 of two anti-ranges into a switch on
                    their union
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: lzy20000419 at outlook dot com
  Target Milestone: ---

Fails with trunk (gcc 17.0.0 20261109, a74179d08523) and with 11.1.0 through
16.2.0; 7.5.0 through 10.5.0 work.
Target: x86_64-pc-linux-gnu (target-independent).

(x not in [13, 15]) | (x != 20) is true for every int, so f must return 8 for
every x other than 1, 2 and 3.

    __attribute__((noipa)) int
    f (int x)
    {
      if (x == 1) return 1;
      if (x == 2) return 2;
      if (x == 3) return 3;
      _Bool a = (unsigned) x - 13u > 2u;        /* x not in [13, 15] */
      _Bool b = x != 20;
      if (a | b)
        return 8;
      return 9;
    }

    int
    main (void)
    {
      if (f (20) != 8 || f (14) != 8)
        __builtin_abort ();
      return 0;
    }

    gcc -O1 t.c && ./a.out

Observed: abort, f (14) and f (20) return 9. Expected: exit 0. -O2, -O3 and -Os
fail too. -O0 and -O2 -fdisable-tree-iftoswitch work.

Godbolt (trunk): https://godbolt.org/z/v34E3Wfdj

The iftoswitch dump has case 1, case 2, case 3, case 13 ... 15 and case 20, and
the last two labels go to the edge that returns 9.

Cause: find_conditions (gimple-if-to-switch.cc) accepts _3 = a | b; if (_3 !=
0) by making one range entry per IOR operand. It only checks that both use the
same SSA name and have the same in_p. Here both are anti-ranges (in_p false).
It then uses the false edge as the switch target and emits a case label for
each range. But (x not in R1) | (x not in R2) is the complement of the
intersection of R1 and R2, not of their union.

Possible fix (not tested): in find_conditions, give up when an IOR has more
than one range and !in_p.

Disclaimer: This test case was found with LLM-assisted targeted testing, and
the report was written with LLM assistance.
  • [Bug tree-optimization/128588]... lzy20000419 at outlook dot com via Gcc-bugs

Reply via email to