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