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

            Bug ID: 109058
           Summary: RFE: analyzer should elide repeated calls to strcmp in
                    execution paths
           Product: gcc
           Version: 13.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: dmalcolm at gcc dot gnu.org
  Target Milestone: ---

Seen on a diagnostic in haproxy's cfgparse-global.c: cfg_parse_global

Consider:

--------------------------------------------------------------------------
#include <string.h>

#include "analyzer-decls.h"

int test (char **args)
{
  if (strcmp (args[0], "opt-001") == 0) {
    do_opt (1);
  } else if (strcmp (args[0], "opt-002") == 0) {
    do_opt (2);
  } else if (strcmp (args[0], "opt-003") == 0) {
    do_opt (3);
  } else if (strcmp (args[0], "opt-004") == 0) {
    do_opt (4);
  } else if (strcmp (args[0], "opt-005") == 0) {
    do_opt (5);
  } else if (strcmp (args[0], "opt-006") == 0) {
    do_opt (6);
  } else if (strcmp (args[0], "opt-007") == 0) {
    do_opt (7);
  } else if (strcmp (args[0], "opt-008") == 0) {
    do_opt (8);
  } else if (strcmp (args[0], "opt-009") == 0) {
    do_opt (9);
  } else if (strcmp (args[0], "opt-010") == 0) {
    do_opt (10);
    __analyzer_dump_path ();
  }
}
--------------------------------------------------------------------------

for which we currently emit:

--------------------------------------------------------------------------
../../src/gcc/testsuite/gcc.dg/analyzer/strcmp-path-1.c:27:5: note: path
   27 |     __analyzer_dump_path ();
      |     ^~~~~~~~~~~~~~~~~~~~~~~
  ‘test’: events 1-21
    |
    |    7 |   if (strcmp (args[0], "opt-001") == 0) {
    |      |      ^
    |      |      |
    |      |      (1) following ‘false’ branch (when the strings are
non-equal)...
    |    8 |     do_opt (1);
    |    9 |   } else if (strcmp (args[0], "opt-002") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(2) ...to here
    |      |             (3) following ‘false’ branch (when the strings are
non-equal)...
    |   10 |     do_opt (2);
    |   11 |   } else if (strcmp (args[0], "opt-003") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(4) ...to here
    |      |             (5) following ‘false’ branch (when the strings are
non-equal)...
    |   12 |     do_opt (3);
    |   13 |   } else if (strcmp (args[0], "opt-004") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(6) ...to here
    |      |             (7) following ‘false’ branch (when the strings are
non-equal)...
    |   14 |     do_opt (4);
    |   15 |   } else if (strcmp (args[0], "opt-005") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(8) ...to here
    |      |             (9) following ‘false’ branch (when the strings are
non-equal)...
    |   16 |     do_opt (5);
    |   17 |   } else if (strcmp (args[0], "opt-006") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(10) ...to here
    |      |             (11) following ‘false’ branch (when the strings are
non-equal)...
    |   18 |     do_opt (6);
    |   19 |   } else if (strcmp (args[0], "opt-007") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(12) ...to here
    |      |             (13) following ‘false’ branch (when the strings are
non-equal)...
    |   20 |     do_opt (7);
    |   21 |   } else if (strcmp (args[0], "opt-008") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(14) ...to here
    |      |             (15) following ‘false’ branch (when the strings are
non-equal)...
    |   22 |     do_opt (8);
    |   23 |   } else if (strcmp (args[0], "opt-009") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(16) ...to here
    |      |             (17) following ‘false’ branch (when the strings are
non-equal)...
    |   24 |     do_opt (9);
    |   25 |   } else if (strcmp (args[0], "opt-010") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             ||
    |      |             |(18) ...to here
    |      |             (19) following ‘true’ branch (when the strings are
equal)...
    |   26 |     do_opt (10);
    |      |     ~~~~~~~~~~~
    |      |     |
    |      |     (20) ...to here
    |   27 |     __analyzer_dump_path ();
    |      |     ~~~~~~~~~~~~~~~~~~~~~~~
    |      |     |
    |      |     (21) here
    |
--------------------------------------------------------------------------

We should probably elide all the repeated :

  following ‘false’ branch (when the strings are non-equal)...
  ...to here

events before the:

   following ‘true’ branch (when the strings are equal)...

assuming that all they're checking the same string against a series of possible
values.

This would simplify the execution path to just:

--------------------------------------------------------------------------
../../src/gcc/testsuite/gcc.dg/analyzer/strcmp-path-1.c:27:5: note: path
   27 |     __analyzer_dump_path ();
      |     ^~~~~~~~~~~~~~~~~~~~~~~
  ‘test’: events 1-3
    |
    |   25 |   } else if (strcmp (args[0], "opt-010") == 0) {
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             |
    |      |             (1) following ‘true’ branch (when the strings are
equal)...
    |   26 |     do_opt (10);
    |      |     ~~~~~~~~~~~
    |      |     |
    |      |     (2) ...to here
    |   27 |     __analyzer_dump_path ();
    |      |     ~~~~~~~~~~~~~~~~~~~~~~~
    |      |     |
    |      |     (3) here
    |
--------------------------------------------------------------------------

Reply via email to