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;
}
}
```