]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
IMPORT: ebtree: implement and use flsnz_long() to count bits
authorWilly Tarreau <w@1wt.eu>
Sun, 17 Dec 2023 15:43:25 +0000 (16:43 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 6 Jan 2024 12:35:13 +0000 (13:35 +0100)
The asm code shows multiple conversions. Gcc has always been terribly
bad at dealing with chars, which are constantly converted to ints for
every operation and zero-extended after each operation. But here in
addition there are conversions before and after the flsnz(). Let's
just mark the variables as long and use flsnz_long() to process them
without any conversion. This shortens the code and makes it slightly
faster.

Note that the fls operations could make use of __builtin_clz() on
gcc 4.6 and above, and it would be useful to implement native support
for ARM as well.

This is cbtree commit 1f0f83ba26f2279c8bba0080a2e09a803dddde47.
This is ebtree commit 9c38dcae22a84f0b0d9c5a56facce1ca2ad0aaef.

include/import/ebtree.h

index d6e51d5be330ff82da7c2a87b8512f4034c2dcaf..b1666bba7277708efaadf62dd330676782745f1a 100644 (file)
@@ -279,6 +279,14 @@ static inline int flsnz8(unsigned char x)
        return r+1;
 }
 
+static inline long flsnz_long(unsigned long x)
+{
+       long r;
+       __asm__("bsr %1,%0\n"
+               : "=r" (r) : "rm" (x));
+       return r + 1;
+}
+
 #else
 // returns 1 to 32 for 1<<0 to 1<<31. Undefined for 0.
 #define flsnz(___a) ({ \
@@ -297,6 +305,7 @@ static inline int flsnz8(unsigned int x)
        return flsnz8_generic(x);
 }
 
+#define flsnz_long(x) ((sizeof(long) > 4) ? flsnz64(x) : flsnz32(x))
 
 #endif
 
@@ -791,7 +800,7 @@ static forceinline int string_equal_bits(const unsigned char *a,
                                         int ignore)
 {
        int beg;
-       unsigned char c;
+       unsigned long c, d;
 
        beg = ignore >> 3;
 
@@ -799,8 +808,6 @@ static forceinline int string_equal_bits(const unsigned char *a,
         * or at the first zero we encounter on either side.
         */
        while (1) {
-               unsigned char d;
-
                c = a[beg];
                d = b[beg];
                beg++;
@@ -816,7 +823,7 @@ static forceinline int string_equal_bits(const unsigned char *a,
         * identical bits. Note that low bit numbers are assigned to high positions
         * in the byte, as we compare them as strings.
         */
-       return (beg << 3) - flsnz8(c);
+       return (beg << 3) - flsnz_long(c);
 }
 
 static forceinline int cmp_bits(const unsigned char *a, const unsigned char *b, unsigned int pos)