diff options
Diffstat (limited to 'third_party/wasm2c/src/test-hexfloat.cc')
-rw-r--r-- | third_party/wasm2c/src/test-hexfloat.cc | 264 |
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(); +} |