mirror of
				https://git.tukaani.org/xz.git
				synced 2025-10-31 05:22:55 +00:00 
			
		
		
		
	Update tuklib_integer.h with bit scan functions.
Thanks to Joachim Henke for the original patch.
This commit is contained in:
		
							parent
							
								
									c74c132f7f
								
							
						
					
					
						commit
						7ac3985d89
					
				| @ -1,10 +1,12 @@ | |||||||
| ///////////////////////////////////////////////////////////////////////////////
 | ///////////////////////////////////////////////////////////////////////////////
 | ||||||
| //
 | //
 | ||||||
| /// \file       tuklib_integer.h
 | /// \file       tuklib_integer.h
 | ||||||
| /// \brief      Byte swapping and endianness related macros and functions
 | /// \brief      Various integer and bit operations
 | ||||||
| ///
 | ///
 | ||||||
| /// This file provides macros or functions to do basic endianness related
 | /// This file provides macros or functions to do some basic integer and bit
 | ||||||
| /// integer operations (XX = 16, 32, or 64; Y = b or l):
 | /// operations.
 | ||||||
|  | ///
 | ||||||
|  | /// Endianness related integer operations (XX = 16, 32, or 64; Y = b or l):
 | ||||||
| ///   - Byte swapping: bswapXX(num)
 | ///   - Byte swapping: bswapXX(num)
 | ||||||
| ///   - Byte order conversions to/from native: convXXYe(num)
 | ///   - Byte order conversions to/from native: convXXYe(num)
 | ||||||
| ///   - Aligned reads: readXXYe(ptr)
 | ///   - Aligned reads: readXXYe(ptr)
 | ||||||
| @ -18,8 +20,18 @@ | |||||||
| /// \todo       PowerPC and possibly some other architectures support
 | /// \todo       PowerPC and possibly some other architectures support
 | ||||||
| ///             byte swapping load and store instructions. This file
 | ///             byte swapping load and store instructions. This file
 | ||||||
| ///             doesn't take advantage of those instructions.
 | ///             doesn't take advantage of those instructions.
 | ||||||
|  | ///
 | ||||||
|  | /// Bit scan operations for non-zero 32-bit integers:
 | ||||||
|  | ///   - Bit scan reverse (find highest non-zero bit): bsr32(num)
 | ||||||
|  | ///   - Count leading zeros: clz32(num)
 | ||||||
|  | ///   - Count trailing zeros: ctz32(num)
 | ||||||
|  | ///   - Bit scan forward (simply an alias for ctz32()): bsf32(num)
 | ||||||
|  | ///
 | ||||||
|  | /// The above bit scan operations return 0-31. If num is zero,
 | ||||||
|  | /// the result is undefined.
 | ||||||
| //
 | //
 | ||||||
| //  Author:     Lasse Collin
 | //  Authors:    Lasse Collin
 | ||||||
|  | //              Joachim Henke
 | ||||||
| //
 | //
 | ||||||
| //  This file has been put into the public domain.
 | //  This file has been put into the public domain.
 | ||||||
| //  You can do whatever you want with this file.
 | //  You can do whatever you want with this file.
 | ||||||
| @ -213,8 +225,7 @@ read64le(const uint8_t *buf) | |||||||
| // to optimize byte swapping of constants when using glibc's or *BSD's
 | // to optimize byte swapping of constants when using glibc's or *BSD's
 | ||||||
| // byte swapping macros. The actual write is done in an inline function
 | // byte swapping macros. The actual write is done in an inline function
 | ||||||
| // to make type checking of the buf pointer possible similarly to readXXYe()
 | // to make type checking of the buf pointer possible similarly to readXXYe()
 | ||||||
| // functions. This also seems to silence a probably bogus GCC warning about
 | // functions.
 | ||||||
| // strict aliasing when buf points to the beginning of an uint8_t array.
 |  | ||||||
| 
 | 
 | ||||||
| #define write16be(buf, num) write16ne((buf), conv16be(num)) | #define write16be(buf, num) write16ne((buf), conv16be(num)) | ||||||
| #define write16le(buf, num) write16ne((buf), conv16le(num)) | #define write16le(buf, num) write16ne((buf), conv16le(num)) | ||||||
| @ -272,7 +283,7 @@ write64ne(uint8_t *buf, uint64_t num) | |||||||
| static inline uint16_t | static inline uint16_t | ||||||
| unaligned_read16be(const uint8_t *buf) | unaligned_read16be(const uint8_t *buf) | ||||||
| { | { | ||||||
| 	uint16_t num = ((uint16_t)buf[0] << 8) | buf[1]; | 	uint16_t num = ((uint16_t)buf[0] << 8) | (uint16_t)buf[1]; | ||||||
| 	return num; | 	return num; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -280,7 +291,7 @@ unaligned_read16be(const uint8_t *buf) | |||||||
| static inline uint16_t | static inline uint16_t | ||||||
| unaligned_read16le(const uint8_t *buf) | unaligned_read16le(const uint8_t *buf) | ||||||
| { | { | ||||||
| 	uint16_t num = ((uint32_t)buf[0]) | ((uint16_t)buf[1] << 8); | 	uint16_t num = ((uint16_t)buf[0]) | ((uint16_t)buf[1] << 8); | ||||||
| 	return num; | 	return num; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -347,4 +358,166 @@ unaligned_write32le(uint8_t *buf, uint32_t num) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static inline uint32_t | ||||||
|  | bsr32(uint32_t n) | ||||||
|  | { | ||||||
|  | 	// Check for ICC first, since it tends to define __GNUC__ too.
 | ||||||
|  | #if defined(__INTEL_COMPILER) | ||||||
|  | 	return _bit_scan_reverse(n); | ||||||
|  | 
 | ||||||
|  | #elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX == UINT32_MAX | ||||||
|  | 	// GCC >= 3.4 has __builtin_clz(), which gives good results on
 | ||||||
|  | 	// multiple architectures. On x86, __builtin_clz() ^ 31U becomes
 | ||||||
|  | 	// either plain BSR (so the XOR gets optimized away) or LZCNT and
 | ||||||
|  | 	// XOR (if -march indicates that SSE4a instructions are supported).
 | ||||||
|  | 	return __builtin_clz(n) ^ 31U; | ||||||
|  | 
 | ||||||
|  | #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | ||||||
|  | 	uint32_t i; | ||||||
|  | 	__asm__("bsrl %1, %0" : "=r" (i) : "rm" (n)); | ||||||
|  | 	return i; | ||||||
|  | 
 | ||||||
|  | #elif defined(_MSC_VER) && _MSC_VER >= 1400 | ||||||
|  | 	// MSVC isn't supported by tuklib, but since this code exists,
 | ||||||
|  | 	// it doesn't hurt to have it here anyway.
 | ||||||
|  | 	uint32_t i; | ||||||
|  | 	_BitScanReverse((DWORD *)&i, n); | ||||||
|  | 	return i; | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | 	uint32_t i = 31; | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0xFFFF0000)) == 0) { | ||||||
|  | 		n <<= 16; | ||||||
|  | 		i = 15; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0xFF000000)) == 0) { | ||||||
|  | 		n <<= 8; | ||||||
|  | 		i -= 8; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0xF0000000)) == 0) { | ||||||
|  | 		n <<= 4; | ||||||
|  | 		i -= 4; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0xC0000000)) == 0) { | ||||||
|  | 		n <<= 2; | ||||||
|  | 		i -= 2; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0x80000000)) == 0) | ||||||
|  | 		--i; | ||||||
|  | 
 | ||||||
|  | 	return i; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static inline uint32_t | ||||||
|  | clz32(uint32_t n) | ||||||
|  | { | ||||||
|  | #if defined(__INTEL_COMPILER) | ||||||
|  | 	return _bit_scan_reverse(n) ^ 31U; | ||||||
|  | 
 | ||||||
|  | #elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX == UINT32_MAX | ||||||
|  | 	return __builtin_clz(n); | ||||||
|  | 
 | ||||||
|  | #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | ||||||
|  | 	uint32_t i; | ||||||
|  | 	__asm__("bsrl %1, %0\n\t" | ||||||
|  | 		"xorl $31, %0" | ||||||
|  | 		: "=r" (i) : "rm" (n)); | ||||||
|  | 	return i; | ||||||
|  | 
 | ||||||
|  | #elif defined(_MSC_VER) && _MSC_VER >= 1400 | ||||||
|  | 	uint32_t i; | ||||||
|  | 	_BitScanReverse((DWORD *)&i, n); | ||||||
|  | 	return i ^ 31U; | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | 	uint32_t i = 0; | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0xFFFF0000)) == 0) { | ||||||
|  | 		n <<= 16; | ||||||
|  | 		i = 16; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0xFF000000)) == 0) { | ||||||
|  | 		n <<= 8; | ||||||
|  | 		i += 8; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0xF0000000)) == 0) { | ||||||
|  | 		n <<= 4; | ||||||
|  | 		i += 4; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0xC0000000)) == 0) { | ||||||
|  | 		n <<= 2; | ||||||
|  | 		i += 2; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0x80000000)) == 0) | ||||||
|  | 		++i; | ||||||
|  | 
 | ||||||
|  | 	return i; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static inline uint32_t | ||||||
|  | ctz32(uint32_t n) | ||||||
|  | { | ||||||
|  | #if defined(__INTEL_COMPILER) | ||||||
|  | 	return _bit_scan_forward(n); | ||||||
|  | 
 | ||||||
|  | #elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX >= UINT32_MAX | ||||||
|  | 	return __builtin_ctz(n); | ||||||
|  | 
 | ||||||
|  | #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | ||||||
|  | 	uint32_t i; | ||||||
|  | 	__asm__("bsfl %1, %0" : "=r" (i) : "rm" (n)); | ||||||
|  | 	return i; | ||||||
|  | 
 | ||||||
|  | #elif defined(_MSC_VER) && _MSC_VER >= 1400 | ||||||
|  | 	uint32_t i; | ||||||
|  | 	_BitScanForward((DWORD *)&i, n); | ||||||
|  | 	return i; | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | 	uint32_t i = 0; | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0x0000FFFF)) == 0) { | ||||||
|  | 		n >>= 16; | ||||||
|  | 		i = 16; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0x000000FF)) == 0) { | ||||||
|  | 		n >>= 8; | ||||||
|  | 		i += 8; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0x0000000F)) == 0) { | ||||||
|  | 		n >>= 4; | ||||||
|  | 		i += 4; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0x00000003)) == 0) { | ||||||
|  | 		n >>= 2; | ||||||
|  | 		i += 2; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((n & UINT32_C(0x00000001)) == 0) | ||||||
|  | 		++i; | ||||||
|  | 
 | ||||||
|  | 	return i; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define bsf32 ctz32 | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user