diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2010-05-17 18:13:23 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2010-05-17 18:17:16 -0400 |
commit | c59bd5688299cddb71183e156e7a3c1409b90df2 (patch) | |
tree | d7b99407367b30aa7766219083ad0262c8edbab8 /arch | |
parent | 4677d4a53e0d565742277e8913e91c821453e63e (diff) |
x86, hweight: Use a 32-bit popcnt for __arch_hweight32()
Use a 32-bit popcnt instruction for __arch_hweight32(), even on
x86-64. Even though the input register will *usually* be
zero-extended due to the standard operation of the hardware, it isn't
necessarily so if the input value was the result of truncating a
64-bit operation.
Note: the POPCNT32 variant used on x86-64 has a technically
unnecessary REX prefix to make it five bytes long, the same as a CALL
instruction, therefore avoiding an unnecessary NOP.
Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: Borislav Petkov <borislav.petkov@amd.com>
LKML-Reference: <alpine.LFD.2.00.1005171443060.4195@i5.linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/arch_hweight.h | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/arch/x86/include/asm/arch_hweight.h b/arch/x86/include/asm/arch_hweight.h index d1fc3c219ae6..9686c3d9ff73 100644 --- a/arch/x86/include/asm/arch_hweight.h +++ b/arch/x86/include/asm/arch_hweight.h | |||
@@ -2,13 +2,15 @@ | |||
2 | #define _ASM_X86_HWEIGHT_H | 2 | #define _ASM_X86_HWEIGHT_H |
3 | 3 | ||
4 | #ifdef CONFIG_64BIT | 4 | #ifdef CONFIG_64BIT |
5 | /* popcnt %edi, %eax -- redundant REX prefix for alignment */ | ||
6 | #define POPCNT32 ".byte 0xf3,0x40,0x0f,0xb8,0xc7" | ||
5 | /* popcnt %rdi, %rax */ | 7 | /* popcnt %rdi, %rax */ |
6 | #define POPCNT ".byte 0xf3,0x48,0x0f,0xb8,0xc7" | 8 | #define POPCNT64 ".byte 0xf3,0x48,0x0f,0xb8,0xc7" |
7 | #define REG_IN "D" | 9 | #define REG_IN "D" |
8 | #define REG_OUT "a" | 10 | #define REG_OUT "a" |
9 | #else | 11 | #else |
10 | /* popcnt %eax, %eax */ | 12 | /* popcnt %eax, %eax */ |
11 | #define POPCNT ".byte 0xf3,0x0f,0xb8,0xc0" | 13 | #define POPCNT32 ".byte 0xf3,0x0f,0xb8,0xc0" |
12 | #define REG_IN "a" | 14 | #define REG_IN "a" |
13 | #define REG_OUT "a" | 15 | #define REG_OUT "a" |
14 | #endif | 16 | #endif |
@@ -23,7 +25,7 @@ static inline unsigned int __arch_hweight32(unsigned int w) | |||
23 | { | 25 | { |
24 | unsigned int res = 0; | 26 | unsigned int res = 0; |
25 | 27 | ||
26 | asm (ALTERNATIVE("call __sw_hweight32", POPCNT, X86_FEATURE_POPCNT) | 28 | asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT) |
27 | : "="REG_OUT (res) | 29 | : "="REG_OUT (res) |
28 | : REG_IN (w)); | 30 | : REG_IN (w)); |
29 | 31 | ||
@@ -48,7 +50,7 @@ static inline unsigned long __arch_hweight64(__u64 w) | |||
48 | return __arch_hweight32((u32)w) + | 50 | return __arch_hweight32((u32)w) + |
49 | __arch_hweight32((u32)(w >> 32)); | 51 | __arch_hweight32((u32)(w >> 32)); |
50 | #else | 52 | #else |
51 | asm (ALTERNATIVE("call __sw_hweight64", POPCNT, X86_FEATURE_POPCNT) | 53 | asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT) |
52 | : "="REG_OUT (res) | 54 | : "="REG_OUT (res) |
53 | : REG_IN (w)); | 55 | : REG_IN (w)); |
54 | #endif /* CONFIG_X86_32 */ | 56 | #endif /* CONFIG_X86_32 */ |