| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | #ifndef _BITPOSITION_H_ |
| 6 | #define _BITPOSITION_H_ |
| 7 | |
| 8 | //------------------------------------------------------------------------ |
| 9 | // BitPosition: Return the position of the single bit that is set in 'value'. |
| 10 | // |
| 11 | // Return Value: |
| 12 | // The position (0 is LSB) of bit that is set in 'value' |
| 13 | // |
| 14 | // Notes: |
| 15 | // 'value' must have exactly one bit set. |
| 16 | // The algorithm is as follows: |
| 17 | // - PRIME is a prime bigger than sizeof(unsigned int), which is not of the |
| 18 | // form 2^n-1. |
| 19 | // - Taking the modulo of 'value' with this will produce a unique hash for all |
| 20 | // powers of 2 (which is what "value" is). |
| 21 | // - Entries in hashTable[] which are -1 should never be used. There |
| 22 | // should be PRIME-8*sizeof(value) entries which are -1 . |
| 23 | // |
| 24 | inline |
| 25 | unsigned BitPosition(unsigned value) |
| 26 | { |
| 27 | _ASSERTE((value != 0) && ((value & (value-1)) == 0)); |
| 28 | #if defined(_ARM_) && defined(__llvm__) |
| 29 | // use intrinsic functions for arm32 |
| 30 | // this is applied for LLVM only but it may work for some compilers |
| 31 | DWORD index = __builtin_clz(__builtin_arm_rbit(value)); |
| 32 | #elif !defined(_AMD64_) |
| 33 | const unsigned PRIME = 37; |
| 34 | |
| 35 | static const char hashTable[PRIME] = |
| 36 | { |
| 37 | -1, 0, 1, 26, 2, 23, 27, -1, 3, 16, |
| 38 | 24, 30, 28, 11, -1, 13, 4, 7, 17, -1, |
| 39 | 25, 22, 31, 15, 29, 10, 12, 6, -1, 21, |
| 40 | 14, 9, 5, 20, 8, 19, 18 |
| 41 | }; |
| 42 | |
| 43 | _ASSERTE(PRIME >= 8*sizeof(value)); |
| 44 | _ASSERTE(sizeof(hashTable) == PRIME); |
| 45 | |
| 46 | |
| 47 | unsigned hash = value % PRIME; |
| 48 | unsigned index = hashTable[hash]; |
| 49 | _ASSERTE(index != (unsigned char)-1); |
| 50 | #else |
| 51 | // not enabled for x86 because BSF is extremely slow on Atom |
| 52 | // (15 clock cycles vs 1-3 on any other Intel CPU post-P4) |
| 53 | DWORD index; |
| 54 | BitScanForward(&index, value); |
| 55 | #endif |
| 56 | return index; |
| 57 | } |
| 58 | |
| 59 | #endif |
| 60 | |