lib/util/math.c: improve portability

__builtin_clzl takes an unsigned long argument which may be smaller
than uint64_t on some platforms. GCC silently ignores the mismatch,
returning the wrong answer at runtime. Use __builtin_clzll instead and
add static assertions to detect the issue.

Attribute 'target_clones' requires 'ifunc' support which only applies to
ELF targets. Add check for defined(__ELF__).

Signed-off-by: Nick Connolly <nick.connolly@mayadata.io>
Change-Id: Iff76640b34223649de531250ad40471d829512c7
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/6317
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
This commit is contained in:
Nick Connolly 2021-02-08 14:17:24 +00:00 committed by Tomasz Zawadzki
parent 0e9ee17642
commit 424cbc3957

View File

@ -33,12 +33,14 @@
#include "spdk/stdinc.h"
#include "spdk/util.h"
#include "spdk/assert.h"
/* The following will automatically generate several version of
* this function, targeted at different architectures. This
* is only supported by GCC 6 or newer. */
#if defined(__GNUC__) && __GNUC__ >= 6 && !defined(__clang__) \
&& (defined(__i386__) || defined(__x86_64__))
&& (defined(__i386__) || defined(__x86_64__)) \
&& defined(__ELF__)
__attribute__((target_clones("bmi", "arch=core2", "arch=atom", "default")))
#endif
uint32_t
@ -48,6 +50,7 @@ spdk_u32log2(uint32_t x)
/* log(0) is undefined */
return 0;
}
SPDK_STATIC_ASSERT(sizeof(x) == sizeof(unsigned int), "Incorrect size");
return 31u - __builtin_clz(x);
}
@ -55,7 +58,8 @@ spdk_u32log2(uint32_t x)
* this function, targeted at different architectures. This
* is only supported by GCC 6 or newer. */
#if defined(__GNUC__) && __GNUC__ >= 6 && !defined(__clang__) \
&& (defined(__i386__) || defined(__x86_64__))
&& (defined(__i386__) || defined(__x86_64__)) \
&& defined(__ELF__)
__attribute__((target_clones("bmi", "arch=core2", "arch=atom", "default")))
#endif
uint64_t
@ -65,5 +69,6 @@ spdk_u64log2(uint64_t x)
/* log(0) is undefined */
return 0;
}
return 63u - __builtin_clzl(x);
SPDK_STATIC_ASSERT(sizeof(x) == sizeof(unsigned long long), "Incorrect size");
return 63u - __builtin_clzll(x);
}