2 * Copyright 2016 WebAssembly Community Group participants
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include "gtest/gtest.h"
23 #include "wabt/literal.h"
25 #define FOREACH_UINT32_MULTIPLIER 1
27 #define FOREACH_UINT32(bits) \
28 uint32_t last_bits = 0; \
29 uint32_t bits = shard; \
30 int last_top_byte = -1; \
31 for (; bits >= last_bits; \
32 last_bits = bits, bits += num_threads_ * FOREACH_UINT32_MULTIPLIER)
34 #define LOG_COMPLETION(bits) \
36 int top_byte = bits >> 24; \
37 if (top_byte != last_top_byte) { \
38 printf("value: 0x%08x (%d%%)\r", bits, \
39 static_cast<int>(static_cast<double>(bits) * 100 / UINT32_MAX)); \
41 last_top_byte = top_byte; \
53 template <typename T
, typename F
>
56 memcpy(&result
, &value
, sizeof(result
));
60 static bool is_infinity_or_nan(uint32_t float_bits
) {
61 return ((float_bits
>> 23) & 0xff) == 0xff;
64 static bool is_infinity_or_nan(uint64_t double_bits
) {
65 return ((double_bits
>> 52) & 0x7ff) == 0x7ff;
68 class ThreadedTest
: public ::testing::Test
{
70 static constexpr int kDefaultNumThreads
= 2;
72 virtual void SetUp() {
73 num_threads_
= std::thread::hardware_concurrency();
74 if (num_threads_
== 0)
75 num_threads_
= kDefaultNumThreads
;
78 virtual void RunShard(int shard
) = 0;
81 std::vector
<std::thread
> threads
;
83 for (int i
= 0; i
< num_threads_
; ++i
) {
84 threads
.emplace_back(&ThreadedTest::RunShard
, this, i
);
87 for (std::thread
& thread
: threads
) {
96 class AllFloatsParseTest
: public ThreadedTest
{
98 virtual void RunShard(int shard
) {
100 FOREACH_UINT32(bits
) {
101 LOG_COMPLETION(bits
);
102 if (is_infinity_or_nan(bits
))
105 float value
= bit_cast
<float>(bits
);
106 int len
= snprintf(buffer
, sizeof(buffer
), "%a", value
);
109 ASSERT_EQ(Result::Ok
,
110 ParseFloat(LiteralType::Hexfloat
, buffer
, buffer
+ len
, &me
));
117 TEST_F(AllFloatsParseTest
, Run
) {
121 class AllFloatsWriteTest
: public ThreadedTest
{
123 virtual void RunShard(int shard
) {
125 FOREACH_UINT32(bits
) {
126 LOG_COMPLETION(bits
);
127 if (is_infinity_or_nan(bits
))
130 WriteFloatHex(buffer
, sizeof(buffer
), bits
);
133 float them_float
= strtof(buffer
, &endptr
);
134 uint32_t them_bits
= bit_cast
<uint32_t>(them_float
);
135 ASSERT_EQ(bits
, them_bits
);
141 TEST_F(AllFloatsWriteTest
, Run
) {
145 class AllFloatsRoundtripTest
: public ThreadedTest
{
147 static LiteralType
ClassifyFloat(uint32_t float_bits
) {
148 if (is_infinity_or_nan(float_bits
)) {
149 if (float_bits
& 0x7fffff) {
150 return LiteralType::Nan
;
152 return LiteralType::Infinity
;
155 return LiteralType::Hexfloat
;
159 virtual void RunShard(int shard
) {
161 FOREACH_UINT32(bits
) {
162 LOG_COMPLETION(bits
);
163 WriteFloatHex(buffer
, sizeof(buffer
), bits
);
164 int len
= strlen(buffer
);
167 ASSERT_EQ(Result::Ok
, ParseFloat(ClassifyFloat(bits
), buffer
,
168 buffer
+ len
, &new_bits
));
169 ASSERT_EQ(new_bits
, bits
);
175 TEST_F(AllFloatsRoundtripTest
, Run
) {
180 class ManyDoublesParseTest
: public ThreadedTest
{
182 virtual void RunShard(int shard
) {
184 FOREACH_UINT32(halfbits
) {
185 LOG_COMPLETION(halfbits
);
186 uint64_t bits
= (static_cast<uint64_t>(halfbits
) << 32) | halfbits
;
187 if (is_infinity_or_nan(bits
))
190 double value
= bit_cast
<double>(bits
);
191 int len
= snprintf(buffer
, sizeof(buffer
), "%a", value
);
194 ASSERT_EQ(Result::Ok
,
195 ParseDouble(LiteralType::Hexfloat
, buffer
, buffer
+ len
, &me
));
202 TEST_F(ManyDoublesParseTest
, Run
) {
206 class ManyDoublesWriteTest
: public ThreadedTest
{
208 virtual void RunShard(int shard
) {
210 FOREACH_UINT32(halfbits
) {
211 LOG_COMPLETION(halfbits
);
212 uint64_t bits
= (static_cast<uint64_t>(halfbits
) << 32) | halfbits
;
213 if (is_infinity_or_nan(bits
))
216 WriteDoubleHex(buffer
, sizeof(buffer
), bits
);
219 double them_double
= strtod(buffer
, &endptr
);
220 uint64_t them_bits
= bit_cast
<uint64_t>(them_double
);
221 ASSERT_EQ(bits
, them_bits
);
227 TEST_F(ManyDoublesWriteTest
, Run
) {
231 class ManyDoublesRoundtripTest
: public ThreadedTest
{
233 static LiteralType
ClassifyDouble(uint64_t double_bits
) {
234 if (is_infinity_or_nan(double_bits
)) {
235 if (double_bits
& 0xfffffffffffffULL
) {
236 return LiteralType::Nan
;
238 return LiteralType::Infinity
;
241 return LiteralType::Hexfloat
;
245 virtual void RunShard(int shard
) {
247 FOREACH_UINT32(halfbits
) {
248 LOG_COMPLETION(halfbits
);
249 uint64_t bits
= (static_cast<uint64_t>(halfbits
) << 32) | halfbits
;
250 WriteDoubleHex(buffer
, sizeof(buffer
), bits
);
251 int len
= strlen(buffer
);
254 ASSERT_EQ(Result::Ok
, ParseDouble(ClassifyDouble(bits
), buffer
,
255 buffer
+ len
, &new_bits
));
256 ASSERT_EQ(new_bits
, bits
);
262 TEST_F(ManyDoublesRoundtripTest
, Run
) {