summaryrefslogtreecommitdiffstats
path: root/third_party/wasm2c/src/test-hexfloat.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/wasm2c/src/test-hexfloat.cc
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/wasm2c/src/test-hexfloat.cc')
-rw-r--r--third_party/wasm2c/src/test-hexfloat.cc264
1 files changed, 264 insertions, 0 deletions
diff --git a/third_party/wasm2c/src/test-hexfloat.cc b/third_party/wasm2c/src/test-hexfloat.cc
new file mode 100644
index 0000000000..d732c99202
--- /dev/null
+++ b/third_party/wasm2c/src/test-hexfloat.cc
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdio>
+#include <thread>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+#include "wabt/literal.h"
+
+#define FOREACH_UINT32_MULTIPLIER 1
+
+#define FOREACH_UINT32(bits) \
+ uint32_t last_bits = 0; \
+ uint32_t bits = shard; \
+ int last_top_byte = -1; \
+ for (; bits >= last_bits; \
+ last_bits = bits, bits += num_threads_ * FOREACH_UINT32_MULTIPLIER)
+
+#define LOG_COMPLETION(bits) \
+ if (shard == 0) { \
+ int top_byte = bits >> 24; \
+ if (top_byte != last_top_byte) { \
+ printf("value: 0x%08x (%d%%)\r", bits, \
+ static_cast<int>(static_cast<double>(bits) * 100 / UINT32_MAX)); \
+ fflush(stdout); \
+ last_top_byte = top_byte; \
+ } \
+ }
+
+#define LOG_DONE() \
+ if (shard == 0) { \
+ printf("done.\n"); \
+ fflush(stdout); \
+ }
+
+using namespace wabt;
+
+template <typename T, typename F>
+T bit_cast(F value) {
+ T result;
+ memcpy(&result, &value, sizeof(result));
+ return result;
+}
+
+static bool is_infinity_or_nan(uint32_t float_bits) {
+ return ((float_bits >> 23) & 0xff) == 0xff;
+}
+
+static bool is_infinity_or_nan(uint64_t double_bits) {
+ return ((double_bits >> 52) & 0x7ff) == 0x7ff;
+}
+
+class ThreadedTest : public ::testing::Test {
+ protected:
+ static constexpr int kDefaultNumThreads = 2;
+
+ virtual void SetUp() {
+ num_threads_ = std::thread::hardware_concurrency();
+ if (num_threads_ == 0)
+ num_threads_ = kDefaultNumThreads;
+ }
+
+ virtual void RunShard(int shard) = 0;
+
+ void RunThreads() {
+ std::vector<std::thread> threads;
+
+ for (int i = 0; i < num_threads_; ++i) {
+ threads.emplace_back(&ThreadedTest::RunShard, this, i);
+ }
+
+ for (std::thread& thread : threads) {
+ thread.join();
+ }
+ }
+
+ int num_threads_;
+};
+
+/* floats */
+class AllFloatsParseTest : public ThreadedTest {
+ protected:
+ virtual void RunShard(int shard) {
+ char buffer[100];
+ FOREACH_UINT32(bits) {
+ LOG_COMPLETION(bits);
+ if (is_infinity_or_nan(bits))
+ continue;
+
+ float value = bit_cast<float>(bits);
+ int len = snprintf(buffer, sizeof(buffer), "%a", value);
+
+ uint32_t me;
+ ASSERT_EQ(Result::Ok,
+ ParseFloat(LiteralType::Hexfloat, buffer, buffer + len, &me));
+ ASSERT_EQ(me, bits);
+ }
+ LOG_DONE();
+ }
+};
+
+TEST_F(AllFloatsParseTest, Run) {
+ RunThreads();
+}
+
+class AllFloatsWriteTest : public ThreadedTest {
+ protected:
+ virtual void RunShard(int shard) {
+ char buffer[100];
+ FOREACH_UINT32(bits) {
+ LOG_COMPLETION(bits);
+ if (is_infinity_or_nan(bits))
+ continue;
+
+ WriteFloatHex(buffer, sizeof(buffer), bits);
+
+ char* endptr;
+ float them_float = strtof(buffer, &endptr);
+ uint32_t them_bits = bit_cast<uint32_t>(them_float);
+ ASSERT_EQ(bits, them_bits);
+ }
+ LOG_DONE();
+ }
+};
+
+TEST_F(AllFloatsWriteTest, Run) {
+ RunThreads();
+}
+
+class AllFloatsRoundtripTest : public ThreadedTest {
+ protected:
+ static LiteralType ClassifyFloat(uint32_t float_bits) {
+ if (is_infinity_or_nan(float_bits)) {
+ if (float_bits & 0x7fffff) {
+ return LiteralType::Nan;
+ } else {
+ return LiteralType::Infinity;
+ }
+ } else {
+ return LiteralType::Hexfloat;
+ }
+ }
+
+ virtual void RunShard(int shard) {
+ char buffer[100];
+ FOREACH_UINT32(bits) {
+ LOG_COMPLETION(bits);
+ WriteFloatHex(buffer, sizeof(buffer), bits);
+ int len = strlen(buffer);
+
+ uint32_t new_bits;
+ ASSERT_EQ(Result::Ok, ParseFloat(ClassifyFloat(bits), buffer,
+ buffer + len, &new_bits));
+ ASSERT_EQ(new_bits, bits);
+ }
+ LOG_DONE();
+ }
+};
+
+TEST_F(AllFloatsRoundtripTest, Run) {
+ RunThreads();
+}
+
+/* doubles */
+class ManyDoublesParseTest : public ThreadedTest {
+ protected:
+ virtual void RunShard(int shard) {
+ char buffer[100];
+ FOREACH_UINT32(halfbits) {
+ LOG_COMPLETION(halfbits);
+ uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
+ if (is_infinity_or_nan(bits))
+ continue;
+
+ double value = bit_cast<double>(bits);
+ int len = snprintf(buffer, sizeof(buffer), "%a", value);
+
+ uint64_t me;
+ ASSERT_EQ(Result::Ok,
+ ParseDouble(LiteralType::Hexfloat, buffer, buffer + len, &me));
+ ASSERT_EQ(me, bits);
+ }
+ LOG_DONE();
+ }
+};
+
+TEST_F(ManyDoublesParseTest, Run) {
+ RunThreads();
+}
+
+class ManyDoublesWriteTest : public ThreadedTest {
+ protected:
+ virtual void RunShard(int shard) {
+ char buffer[100];
+ FOREACH_UINT32(halfbits) {
+ LOG_COMPLETION(halfbits);
+ uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
+ if (is_infinity_or_nan(bits))
+ continue;
+
+ WriteDoubleHex(buffer, sizeof(buffer), bits);
+
+ char* endptr;
+ double them_double = strtod(buffer, &endptr);
+ uint64_t them_bits = bit_cast<uint64_t>(them_double);
+ ASSERT_EQ(bits, them_bits);
+ }
+ LOG_DONE();
+ }
+};
+
+TEST_F(ManyDoublesWriteTest, Run) {
+ RunThreads();
+}
+
+class ManyDoublesRoundtripTest : public ThreadedTest {
+ protected:
+ static LiteralType ClassifyDouble(uint64_t double_bits) {
+ if (is_infinity_or_nan(double_bits)) {
+ if (double_bits & 0xfffffffffffffULL) {
+ return LiteralType::Nan;
+ } else {
+ return LiteralType::Infinity;
+ }
+ } else {
+ return LiteralType::Hexfloat;
+ }
+ }
+
+ virtual void RunShard(int shard) {
+ char buffer[100];
+ FOREACH_UINT32(halfbits) {
+ LOG_COMPLETION(halfbits);
+ uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
+ WriteDoubleHex(buffer, sizeof(buffer), bits);
+ int len = strlen(buffer);
+
+ uint64_t new_bits;
+ ASSERT_EQ(Result::Ok, ParseDouble(ClassifyDouble(bits), buffer,
+ buffer + len, &new_bits));
+ ASSERT_EQ(new_bits, bits);
+ }
+ LOG_DONE();
+ }
+};
+
+TEST_F(ManyDoublesRoundtripTest, Run) {
+ RunThreads();
+}