From: VMware, Inc <> Date: Thu, 24 Feb 2011 22:53:40 +0000 (-0800) Subject: Add constant predicates to help gcc improve lssb and mssb code generation. X-Git-Tag: 2011.02.23-368700~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fa46e78ae9b9858e296b325ec9221ef78e544cab;p=thirdparty%2Fopen-vm-tools.git Add constant predicates to help gcc improve lssb and mssb code generation. Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/lib/include/vm_basic_asm.h b/open-vm-tools/lib/include/vm_basic_asm.h index 2f257375c..d66a35cfd 100644 --- a/open-vm-tools/lib/include/vm_basic_asm.h +++ b/open-vm-tools/lib/include/vm_basic_asm.h @@ -353,22 +353,107 @@ mssb64_0(const uint64 value) #define USE_ARCH_X86_CUSTOM #endif +/* ********************************************************** + * GCC's intrinsics for the lssb and mssb family produce sub-optimal code, + * so we use inline assembly to improve matters. However, GCC cannot + * propagate constants through inline assembly, so we help GCC out by + * allowing it to use its intrinsics for compile-time constant values. + * Some day, GCC will make better code and these can collapse to intrinsics. + * + * For example, in Decoder_AddressSize, inlined into VVT_GetVTInstrInfo: + * __builtin_ffs(a) compiles to: + * mov $0xffffffff, %esi + * bsf %eax, %eax + * cmovz %esi, %eax + * sub $0x1, %eax + * and $0x7, %eax + * + * While the code below compiles to: + * bsf %eax, %eax + * sub $0x1, %eax + * + * Ideally, GCC should have recognized non-zero input in the first case. + * Other instances of the intrinsic produce code like + * sub $1, %eax; add $1, %eax; clts + * ********************************************************** + */ + +#if __GNUC__ < 4 +#define FEWER_BUILTINS +#endif + static INLINE int lssb32_0(uint32 value) { #if defined(USE_ARCH_X86_CUSTOM) + if (!__builtin_constant_p(value)) { + if (UNLIKELY(value == 0)) { + return -1; + } else { + int pos; + __asm__ ("bsfl %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); + return pos; + } + } +#endif + return __builtin_ffs(value) - 1; +} + +#ifndef FEWER_BUILTINS +static INLINE int +mssb32_0(uint32 value) +{ + /* + * We must keep the UNLIKELY(...) outside the #if defined ... + * because __builtin_clz(0) is undefined according to gcc's + * documentation. + */ if (UNLIKELY(value == 0)) { return -1; } else { int pos; - __asm__ __volatile__("bsfl %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); +#if defined(USE_ARCH_X86_CUSTOM) + if (!__builtin_constant_p(value)) { + __asm__ ("bsrl %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); + return pos; + } +#endif + pos = 32 - __builtin_clz(value) - 1; return pos; } -#else - return __builtin_ffs(value) - 1; +} + +static INLINE int +lssb64_0(const uint64 value) +{ +#if defined(USE_ARCH_X86_CUSTOM) + if (!__builtin_constant_p(value)) { + if (UNLIKELY(value == 0)) { + return -1; + } else { + intptr_t pos; + #if defined(VM_X86_64) + __asm__ ("bsf %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); + #else + /* The coding was chosen to minimize conditionals and operations */ + pos = lssb32_0((uint32) value); + if (pos == -1) { + pos = lssb32_0((uint32) (value >> 32)); + if (pos != -1) { + return pos + 32; + } + } + #endif + return pos; + } + } #endif + return __builtin_ffsll(value) - 1; } +#endif /* !FEWER_BUILTINS */ +#if defined(FEWER_BUILTINS) +/* GCC 3.3.x does not like __bulitin_clz or __builtin_ffsll. */ static INLINE int mssb32_0(uint32 value) { @@ -376,13 +461,7 @@ mssb32_0(uint32 value) return -1; } else { int pos; - -#if defined(USE_ARCH_X86_CUSTOM) __asm__ __volatile__("bsrl %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); -#else - pos = 32 - __builtin_clz(value) - 1; -#endif - return pos; } } @@ -390,15 +469,14 @@ mssb32_0(uint32 value) static INLINE int lssb64_0(const uint64 value) { -#if defined(USE_ARCH_X86_CUSTOM) if (UNLIKELY(value == 0)) { return -1; } else { intptr_t pos; -#if defined(VM_X86_64) + #if defined(VM_X86_64) __asm__ __volatile__("bsf %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); -#else + #else /* The coding was chosen to minimize conditionals and operations */ pos = lssb32_0((uint32) value); if (pos == -1) { @@ -407,14 +485,12 @@ lssb64_0(const uint64 value) return pos + 32; } } -#endif - + #endif /* VM_X86_64 */ return pos; } -#else - return __builtin_ffsll(value) - 1; -#endif } +#endif /* FEWER_BUILTINS */ + static INLINE int mssb64_0(const uint64 value) @@ -426,7 +502,7 @@ mssb64_0(const uint64 value) #if defined(USE_ARCH_X86_CUSTOM) #if defined(VM_X86_64) - __asm__ __volatile__("bsr %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); + __asm__ ("bsr %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); #else /* The coding was chosen to minimize conditionals and operations */ if (value > 0xFFFFFFFFULL) {