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

Kael Franco <kaelfandrew at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |kaelfandrew at gmail dot com

--- Comment #18 from Kael Franco <kaelfandrew at gmail dot com> ---
GCC and Clang does not optimize still for switch strcmp():
https://godbolt.org/z/MvdYTaWjc
```
#include <string.h>

int f0_slow (const char *arg0)
{
  if (strcmp (arg0, "llvm.") == 0)
    return 0;
  if (strcmp (arg0, "assume") == 0)
    return 1;
  if (strcmp (arg0, "gcroot") == 0)
    return 2;
  if (strcmp (arg0, "llvm.assume") == 0)
    return 3;
  if (strcmp (arg0, "llvm.memcpy.inline") == 0)
    return 4;
  return -1;
}
```
Assembly shows they both output many strcmp().
If tracking strlen() was implemented per bug 90625#c1 , it would most likely do
the following:

```
#include <string.h>

int f0_fast (const char *arg0)
{
  const size_t arg0_len = strnlen (arg0, strlen ("llvm.memcpy.inline") + 1);
  switch (arg0_len)
    {
    case 5:
      if (memcmp (arg0, "llvm.", 5) == 0)
        return 0;
      break;

    case 6:
      if (memcmp (arg0, "assume", 6) == 0)
        return 1;
      if (memcmp (arg0, "gcroot", 6) == 0)
        return 2;
      break;

    case 11:
      if (memcmp (arg0, "llvm.assume", 11) == 0)
        return 3;
      break;

    case 18:
      if (memcmp (arg0, "llvm.memcpy.inline", 18) == 0)
        return 4;
      break;

    default:
      break;
    }

  return 0;
}
```

After detecting switch strcmp(), we create a const local variable arg0_len that
strnlen(arg0, LONGEST_STRING + 1). LONGEST_STRING + 1 so GCC knows arg0 doesn't
start with LONGEST_STRING but strcmp() == 0. Then we switch on arg0_len and
memcmp (arg0, STRING, STRING_LEN) == 0. GCC and Clang remove all strcmp() uses.

This could optimize in GCC source like this example at gcc/passes.cc at line
2554:

```
static void
skip_pass (opt_pass *pass)
{
  /* Pass "reload" sets the global "reload_completed", and many
     things depend on this (e.g. instructions in .md files).  */
  if (strcmp (pass->name, "reload") == 0)
    reload_completed = 1;

  /* Similar for pass "pro_and_epilogue" and the "epilogue_completed" global
     variable.  */
  if (strcmp (pass->name, "pro_and_epilogue") == 0)
    epilogue_completed = 1;

  /* The INSN_ADDRESSES vec is normally set up by
     shorten_branches; set it up for the benefit of passes that
     run after this.  */
  if (strcmp (pass->name, "shorten") == 0)
    INSN_ADDRESSES_ALLOC (get_max_uid ());

  /* Update the cfg hooks as appropriate.  */
  if (strcmp (pass->name, "into_cfglayout") == 0)
    {
      cfg_layout_rtl_register_cfg_hooks ();
      cfun->curr_properties |= PROP_cfglayout;
    }
  if (strcmp (pass->name, "outof_cfglayout") == 0)
    {
      rtl_register_cfg_hooks ();
      cfun->curr_properties &= ~PROP_cfglayout;
    }
}
```

Reply via email to