summaryrefslogtreecommitdiff
path: root/src/support/bits.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/support/bits.cpp')
-rw-r--r--src/support/bits.cpp24
1 files changed, 24 insertions, 0 deletions
diff --git a/src/support/bits.cpp b/src/support/bits.cpp
index 03fb66252..8a81a7e83 100644
--- a/src/support/bits.cpp
+++ b/src/support/bits.cpp
@@ -157,6 +157,30 @@ int ceilLog2(uint32_t v) { return 32 - countLeadingZeroes(v - 1); }
int ceilLog2(uint64_t v) { return 64 - countLeadingZeroes(v - 1); }
+bool isPowerOf2Float(float v) {
+ // Power of two floating points should have zero as their significands,
+ // so here we just mask the exponent range of "v" and compare it with the
+ // unmasked input value. If they are equal, our value is a power of
+ // two. Also, we reject all values which are less than the minimal possible
+ // power of two or greater than the maximum possible power of two.
+ const uint32_t MIN_POT = 0x01U << 23; // 0x1p-126
+ const uint32_t MAX_POT = 0xFDU << 23; // 0x1p+126
+ const uint32_t EXP_MASK = 0xFFU << 23; // mask only exponent
+ const uint32_t SIGN_MASK = ~0U >> 1; // mask everything except sign
+ auto u = bit_cast<uint32_t>(v) & SIGN_MASK;
+ return u >= MIN_POT && u <= MAX_POT && (u & EXP_MASK) == u;
+}
+
+bool isPowerOf2Float(double v) {
+ // See isPowerOf2Float(float)
+ const uint64_t MIN_POT = 0x001ULL << 52; // 0x1p-1022
+ const uint64_t MAX_POT = 0x7FDULL << 52; // 0x1p+1022
+ const uint64_t EXP_MASK = 0x7FFULL << 52; // mask only exponent
+ const uint64_t SIGN_MASK = ~0ULL >> 1; // mask everything except sign
+ auto u = bit_cast<uint64_t>(v) & SIGN_MASK;
+ return u >= MIN_POT && u <= MAX_POT && (u & EXP_MASK) == u;
+}
+
uint32_t log2(uint32_t v) {
if (!isPowerOf2(v)) {
WASM_UNREACHABLE("value should be a power of two");