From 27038b159b50e69ea216a513edbd6ee68cdf89aa Mon Sep 17 00:00:00 2001 From: Mukund Sivaraman Date: Sun, 10 Jul 2016 19:46:17 +0530 Subject: [PATCH] Use GCC builtin for clz in RPZ lookup code (#42818) --- CHANGES | 3 +++ config.h.in | 3 +++ configure | 39 +++++++++++++++++++++++++++++++++++++++ configure.in | 17 +++++++++++++++++ lib/dns/rpz.c | 31 +++++++++++++++++++++---------- 5 files changed, 83 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 00bf399789..ffc15da81f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4407. [performance] Use GCC builtin for clz in RPZ lookup code. + [RT #42818] + 4406. [bug] getrrsetbyname with a non absolute name could trigger a infinite recursion bug in lwresd and named with lwres configured if when combined diff --git a/config.h.in b/config.h.in index 0f885b1329..f3f947ebc6 100644 --- a/config.h.in +++ b/config.h.in @@ -194,6 +194,9 @@ int sigwait(const unsigned int *set, int *sig); MSVC and with C++ compilers. */ #undef FLEXIBLE_ARRAY_MEMBER +/* Define to 1 if the compiler supports __builtin_clz. */ +#undef HAVE_BUILTIN_CLZ + /* Define to 1 if the compiler supports __builtin_expect. */ #undef HAVE_BUILTIN_EXPECT diff --git a/configure b/configure index bc9bb81fbf..61222f1806 100755 --- a/configure +++ b/configure @@ -20183,6 +20183,45 @@ $as_echo "#define HAVE_BUILTIN_EXPECT 1" >>confdefs.h fi +# +# Check for __builtin_clz +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler support for __builtin_clz" >&5 +$as_echo_n "checking compiler support for __builtin_clz... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + return (__builtin_clz(0xff) == 24 ? 1 : 0); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + have_builtin_clz=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + + have_builtin_clz=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$have_builtin_clz" = "yes"; then + +$as_echo "#define HAVE_BUILTIN_CLZ 1" >>confdefs.h + +fi + # # CPU relax (for spin locks) # diff --git a/configure.in b/configure.in index 2da78c8f62..9bf4aa2f8d 100644 --- a/configure.in +++ b/configure.in @@ -4007,6 +4007,23 @@ if test "$have_builtin_expect" = "yes"; then AC_DEFINE(HAVE_BUILTIN_EXPECT, 1, [Define to 1 if the compiler supports __builtin_expect.]) fi +# +# Check for __builtin_clz +# +AC_MSG_CHECKING([compiler support for __builtin_clz]) +AC_TRY_LINK(, [ + return (__builtin_clz(0xff) == 24 ? 1 : 0); +], [ + have_builtin_clz=yes + AC_MSG_RESULT(yes) +], [ + have_builtin_clz=no + AC_MSG_RESULT(no) +]) +if test "$have_builtin_clz" = "yes"; then + AC_DEFINE(HAVE_BUILTIN_CLZ, 1, [Define to 1 if the compiler supports __builtin_clz.]) +fi + # # CPU relax (for spin locks) # diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c index b90b148982..ddd6eb2e1a 100644 --- a/lib/dns/rpz.c +++ b/lib/dns/rpz.c @@ -970,34 +970,43 @@ name2data(dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num, (void)dns_name_concatenate(&tmp_name, dns_rootname, trig_name, NULL); } -/* - * Find the first differing bit in a key (IP address) word. +#ifndef HAVE_BUILTIN_CLZ +/** + * \brief Count Leading Zeros: Find the location of the left-most set + * bit. */ -static inline int -ffs_keybit(dns_rpz_cidr_word_t w) { - int bit; +static inline unsigned int +clz(dns_rpz_cidr_word_t w) { + unsigned int bit; bit = DNS_RPZ_CIDR_WORD_BITS-1; + if ((w & 0xffff0000) != 0) { w >>= 16; bit -= 16; } + if ((w & 0xff00) != 0) { w >>= 8; bit -= 8; } + if ((w & 0xf0) != 0) { w >>= 4; bit -= 4; } + if ((w & 0xc) != 0) { w >>= 2; bit -= 2; } + if ((w & 2) != 0) --bit; + return (bit); } +#endif /* * Find the first differing bit in two keys (IP addresses). @@ -1016,12 +1025,14 @@ diff_keys(const dns_rpz_cidr_key_t *key1, dns_rpz_prefix_t prefix1, /* * find the first differing words */ - for (i = 0; - bit < maxbit; - i++, bit += DNS_RPZ_CIDR_WORD_BITS) { + for (i = 0; bit < maxbit; i++, bit += DNS_RPZ_CIDR_WORD_BITS) { delta = key1->w[i] ^ key2->w[i]; - if (delta != 0) { - bit += ffs_keybit(delta); + if (ISC_UNLIKELY(delta != 0)) { +#ifdef HAVE_BUILTIN_CLZ + bit += __builtin_clz(delta); +#else + bit += clz(delta); +#endif break; } }