make constexpr variants for SkCLZ/SkCLT and similar functions
Make a parallel constexpr set of functions for bit log and power functions. These are labeled as *_portable. Change-Id: I40cca37eb3e75c496638d8b58d622467dd692b27 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/333657 Commit-Queue: Herb Derby <herb@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
7d1153fc4c
commit
7a1928ff43
@ -143,45 +143,54 @@ constexpr int SkCLZ_portable(uint32_t x) {
|
||||
return n - x;
|
||||
}
|
||||
|
||||
#ifndef SkCLZ
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
#include <intrin.h>
|
||||
static_assert(32 == SkCLZ_portable(0));
|
||||
static_assert(31 == SkCLZ_portable(1));
|
||||
static_assert( 1 == SkCLZ_portable(1 << 30));
|
||||
static_assert( 1 == SkCLZ_portable((1 << 30) | (1 << 24) | 1));
|
||||
static_assert( 0 == SkCLZ_portable(~0U));
|
||||
|
||||
constexpr int SkCLZ(uint32_t mask) {
|
||||
if (mask) {
|
||||
unsigned long index = 0;
|
||||
_BitScanReverse(&index, mask);
|
||||
// Suppress this bogus /analyze warning. The check for non-zero
|
||||
// guarantees that _BitScanReverse will succeed.
|
||||
#pragma warning(suppress : 6102) // Using 'index' from failed function call
|
||||
return index ^ 0x1F;
|
||||
} else {
|
||||
return 32;
|
||||
}
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
#include <intrin.h>
|
||||
|
||||
static inline int SkCLZ(uint32_t mask) {
|
||||
if (mask) {
|
||||
unsigned long index = 0;
|
||||
_BitScanReverse(&index, mask);
|
||||
// Suppress this bogus /analyze warning. The check for non-zero
|
||||
// guarantees that _BitScanReverse will succeed.
|
||||
#pragma warning(suppress : 6102) // Using 'index' from failed function call
|
||||
return index ^ 0x1F;
|
||||
} else {
|
||||
return 32;
|
||||
}
|
||||
#elif defined(SK_CPU_ARM32) || defined(__GNUC__) || defined(__clang__)
|
||||
constexpr int SkCLZ(uint32_t mask) {
|
||||
// __builtin_clz(0) is undefined, so we have to detect that case.
|
||||
return mask ? __builtin_clz(mask) : 32;
|
||||
}
|
||||
#else
|
||||
constexpr int SkCLZ(uint32_t mask) {
|
||||
return SkCLZ_portable(mask);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#elif defined(SK_CPU_ARM32) || defined(__GNUC__) || defined(__clang__)
|
||||
static inline int SkCLZ(uint32_t mask) {
|
||||
// __builtin_clz(0) is undefined, so we have to detect that case.
|
||||
return mask ? __builtin_clz(mask) : 32;
|
||||
}
|
||||
#else
|
||||
static inline int SkCLZ(uint32_t mask) {
|
||||
return SkCLZ_portable(mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Returns the number of trailing zero bits (0...32)
|
||||
// From Hacker's Delight 2nd Edition
|
||||
constexpr int SkCTZ_portable(uint32_t x) {
|
||||
return 32 - SkCLZ(~x & (x - 1));
|
||||
return 32 - SkCLZ_portable(~x & (x - 1));
|
||||
}
|
||||
|
||||
#ifndef SkCTZ
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
static_assert(32 == SkCTZ_portable(0));
|
||||
static_assert( 0 == SkCTZ_portable(1));
|
||||
static_assert(30 == SkCTZ_portable(1 << 30));
|
||||
static_assert( 2 == SkCTZ_portable((1 << 30) | (1 << 24) | (1 << 2)));
|
||||
static_assert( 0 == SkCTZ_portable(~0U));
|
||||
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
#include <intrin.h>
|
||||
|
||||
constexpr int SkCTZ(uint32_t mask) {
|
||||
static inline int SkCTZ(uint32_t mask) {
|
||||
if (mask) {
|
||||
unsigned long index = 0;
|
||||
_BitScanForward(&index, mask);
|
||||
@ -194,36 +203,15 @@ constexpr int SkCTZ_portable(uint32_t x) {
|
||||
}
|
||||
}
|
||||
#elif defined(SK_CPU_ARM32) || defined(__GNUC__) || defined(__clang__)
|
||||
constexpr int SkCTZ(uint32_t mask) {
|
||||
static inline int SkCTZ(uint32_t mask) {
|
||||
// __builtin_ctz(0) is undefined, so we have to detect that case.
|
||||
return mask ? __builtin_ctz(mask) : 32;
|
||||
}
|
||||
#else
|
||||
constexpr int SkCTZ(uint32_t mask) {
|
||||
static inline int SkCTZ(uint32_t mask) {
|
||||
return SkCTZ_portable(mask);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the smallest power-of-2 that is >= the specified value. If value
|
||||
* is already a power of 2, then it is returned unchanged. It is undefined
|
||||
* if value is <= 0.
|
||||
*/
|
||||
constexpr int SkNextPow2(int value) {
|
||||
SkASSERT(value > 0);
|
||||
return 1 << (32 - SkCLZ(value - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the largest power-of-2 that is <= the specified value. If value
|
||||
* is already a power of 2, then it is returned unchanged. It is undefined
|
||||
* if value is <= 0.
|
||||
*/
|
||||
constexpr int SkPrevPow2(int value) {
|
||||
SkASSERT(value > 0);
|
||||
return 1 << (32 - SkCLZ(value >> 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the log2 of the specified value, were that value to be rounded up
|
||||
@ -234,11 +222,16 @@ constexpr int SkPrevPow2(int value) {
|
||||
* SkNextLog2(4) -> 2
|
||||
* SkNextLog2(5) -> 3
|
||||
*/
|
||||
constexpr int SkNextLog2(uint32_t value) {
|
||||
static inline int SkNextLog2(uint32_t value) {
|
||||
SkASSERT(value != 0);
|
||||
return 32 - SkCLZ(value - 1);
|
||||
}
|
||||
|
||||
constexpr int SkNextLog2_portable(uint32_t value) {
|
||||
SkASSERT(value != 0);
|
||||
return 32 - SkCLZ_portable(value - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the log2 of the specified value, were that value to be rounded down
|
||||
* to the previous power of 2. It is undefined to pass 0. Examples:
|
||||
@ -248,11 +241,46 @@ constexpr int SkNextLog2(uint32_t value) {
|
||||
* SkPrevLog2(4) -> 2
|
||||
* SkPrevLog2(5) -> 2
|
||||
*/
|
||||
constexpr int SkPrevLog2(uint32_t value) {
|
||||
static inline int SkPrevLog2(uint32_t value) {
|
||||
SkASSERT(value != 0);
|
||||
return 32 - SkCLZ(value >> 1);
|
||||
}
|
||||
|
||||
constexpr int SkPrevLog2_portable(uint32_t value) {
|
||||
SkASSERT(value != 0);
|
||||
return 32 - SkCLZ_portable(value >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest power-of-2 that is >= the specified value. If value
|
||||
* is already a power of 2, then it is returned unchanged. It is undefined
|
||||
* if value is <= 0.
|
||||
*/
|
||||
static inline int SkNextPow2(int value) {
|
||||
SkASSERT(value > 0);
|
||||
return 1 << SkNextLog2(value);
|
||||
}
|
||||
|
||||
constexpr int SkNextPow2_portable(int value) {
|
||||
SkASSERT(value > 0);
|
||||
return 1 << SkNextLog2_portable(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the largest power-of-2 that is <= the specified value. If value
|
||||
* is already a power of 2, then it is returned unchanged. It is undefined
|
||||
* if value is <= 0.
|
||||
*/
|
||||
static inline int SkPrevPow2(int value) {
|
||||
SkASSERT(value > 0);
|
||||
return 1 << SkPrevLog2(value);
|
||||
}
|
||||
|
||||
constexpr int SkPrevPow2_portable(int value) {
|
||||
SkASSERT(value > 0);
|
||||
return 1 << SkPrevLog2_portable(value);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user