1 | //===-- Unittests for strtold ---------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "src/__support/FPUtil/FPBits.h" |
10 | #include "src/__support/libc_errno.h" |
11 | #include "src/__support/uint128.h" |
12 | #include "src/stdlib/strtold.h" |
13 | |
14 | #include "test/UnitTest/ErrnoCheckingTest.h" |
15 | #include "test/UnitTest/Test.h" |
16 | |
17 | #include <stddef.h> |
18 | |
19 | #if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) |
20 | #define SELECT_CONST(val, _, __) val |
21 | #elif defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) |
22 | #define SELECT_CONST(_, val, __) val |
23 | #elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) |
24 | #define SELECT_CONST(_, __, val) val |
25 | #else |
26 | #error "Unknown long double type" |
27 | #endif |
28 | |
29 | class LlvmLibcStrToLDTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { |
30 | public: |
31 | #if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) |
32 | void run_test(const char *inputString, const ptrdiff_t expectedStrLen, |
33 | const uint64_t expectedRawData, const int expectedErrno = 0) |
34 | #else |
35 | void run_test(const char *inputString, const ptrdiff_t expectedStrLen, |
36 | const UInt128 expectedRawData, const int expectedErrno = 0) |
37 | #endif |
38 | { |
39 | // expectedRawData64 is the expected long double result as a uint64_t, |
40 | // organized according to the IEEE754 double precision format: |
41 | // |
42 | // +-- 1 Sign Bit +-- 52 Mantissa bits |
43 | // | | |
44 | // | +-------------------------+------------------------+ |
45 | // | | | |
46 | // SEEEEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM |
47 | // | | |
48 | // +----+----+ |
49 | // | |
50 | // +-- 11 Exponent Bits |
51 | |
52 | // expectedRawData80 is the expected long double result as a UInt128, |
53 | // organized according to the x86 extended precision format: |
54 | // |
55 | // +-- 1 Sign Bit |
56 | // | |
57 | // | +-- 1 Integer part bit (1 unless this is a subnormal) |
58 | // | | |
59 | // SEEEEEEEEEEEEEEEIMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM...M |
60 | // | | | | |
61 | // +------+------+ +---------------------------+--------------------------+ |
62 | // | | |
63 | // +-- 15 Exponent Bits +-- 63 Mantissa bits |
64 | |
65 | // expectedRawData128 is the expected long double result as a UInt128, |
66 | // organized according to IEEE754 quadruple precision format: |
67 | // |
68 | // +-- 1 Sign Bit +-- 112 Mantissa bits |
69 | // | | |
70 | // | +----------------------------+--------------------------+ |
71 | // | | | |
72 | // SEEEEEEEEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM...M |
73 | // | | |
74 | // +------+------+ |
75 | // | |
76 | // +-- 15 Exponent Bits |
77 | char *str_end = nullptr; |
78 | |
79 | using FPBits = LIBC_NAMESPACE::fputil::FPBits<long double>; |
80 | FPBits expected_fp = |
81 | FPBits(static_cast<FPBits::StorageType>(expectedRawData)); |
82 | const int expected_errno = expectedErrno; |
83 | |
84 | long double result = LIBC_NAMESPACE::strtold(inputString, &str_end); |
85 | |
86 | LIBC_NAMESPACE::fputil::FPBits<long double> actual_fp = |
87 | LIBC_NAMESPACE::fputil::FPBits<long double>(); |
88 | actual_fp = LIBC_NAMESPACE::fputil::FPBits<long double>(result); |
89 | |
90 | EXPECT_EQ(str_end - inputString, expectedStrLen); |
91 | |
92 | EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval()); |
93 | EXPECT_EQ(actual_fp.is_neg(), expected_fp.is_neg()); |
94 | EXPECT_EQ(actual_fp.get_exponent(), expected_fp.get_exponent()); |
95 | EXPECT_EQ(actual_fp.get_mantissa(), expected_fp.get_mantissa()); |
96 | ASSERT_ERRNO_EQ(expected_errno); |
97 | } |
98 | }; |
99 | |
100 | TEST_F(LlvmLibcStrToLDTest, SimpleTest) { |
101 | run_test("123" , 3, |
102 | SELECT_CONST(uint64_t(0x405ec00000000000), |
103 | UInt128(0x4005f60000) << 40, |
104 | UInt128(0x4005ec0000000000) << 64)); |
105 | |
106 | // This should fail on Eisel-Lemire, forcing a fallback to simple decimal |
107 | // conversion. |
108 | run_test("12345678901234549760" , 20, |
109 | SELECT_CONST(uint64_t(0x43e56a95319d63d8), |
110 | (UInt128(0x403eab54a9) << 40) + UInt128(0x8ceb1ec400), |
111 | (UInt128(0x403e56a95319d63d) << 64) + |
112 | UInt128(0x8800000000000000))); |
113 | |
114 | // Found while looking for difficult test cases here: |
115 | // https://github.com/nigeltao/parse-number-fxx-test-data/blob/main/more-test-cases/golang-org-issue-36657.txt |
116 | run_test("1090544144181609348835077142190" , 31, |
117 | SELECT_CONST(uint64_t(0x462b8779f2474dfb), |
118 | (UInt128(0x4062dc3bcf) << 40) + UInt128(0x923a6fd402), |
119 | (UInt128(0x4062b8779f2474df) << 64) + |
120 | UInt128(0xa804bfd8c6d5c000))); |
121 | |
122 | run_test("0x123" , 5, |
123 | SELECT_CONST(uint64_t(0x4072300000000000), |
124 | (UInt128(0x4007918000) << 40), |
125 | (UInt128(0x4007230000000000) << 64))); |
126 | } |
127 | |
128 | // These are tests that have caused problems for doubles in the past. |
129 | TEST_F(LlvmLibcStrToLDTest, Float64SpecificFailures) { |
130 | run_test("3E70000000000000" , 16, |
131 | SELECT_CONST(uint64_t(0x7FF0000000000000), |
132 | (UInt128(0x7fff800000) << 40), |
133 | (UInt128(0x7fff000000000000) << 64)), |
134 | ERANGE); |
135 | run_test("358416272e-33" , 13, |
136 | SELECT_CONST(uint64_t(0x3adbbb2a68c9d0b9), |
137 | (UInt128(0x3fadddd953) << 40) + UInt128(0x464e85c400), |
138 | (UInt128(0x3fadbbb2a68c9d0b) << 64) + |
139 | UInt128(0x8800e7969e1c5fc8))); |
140 | run_test("2.16656806400000023841857910156251e9" , 36, |
141 | SELECT_CONST(uint64_t(0x41e0246690000001), |
142 | (UInt128(0x401e812334) << 40) + UInt128(0x8000000400), |
143 | (UInt128(0x401e024669000000) << 64) + |
144 | UInt128(0x800000000000018))); |
145 | run_test("27949676547093071875" , 20, |
146 | SELECT_CONST(uint64_t(0x43f83e132bc608c9), |
147 | (UInt128(0x403fc1f099) << 40) + UInt128(0x5e30464402), |
148 | (UInt128(0x403f83e132bc608c) << 64) + |
149 | UInt128(0x8803000000000000))); |
150 | } |
151 | |
152 | TEST_F(LlvmLibcStrToLDTest, Float80SpecificFailures) { |
153 | run_test("7777777777777777777777777777777777777777777777777777777777777777777" |
154 | "777777777777777777777777777777777" , |
155 | 100, |
156 | SELECT_CONST(uint64_t(0x54ac729b8fcaf734), |
157 | (UInt128(0x414ae394dc) << 40) + UInt128(0x7e57b9a0c2), |
158 | (UInt128(0x414ac729b8fcaf73) << 64) + |
159 | UInt128(0x4184a3d793224129))); |
160 | } |
161 | |
162 | TEST_F(LlvmLibcStrToLDTest, MaxSizeNumbers) { |
163 | run_test("1.1897314953572317650e4932" , 26, |
164 | SELECT_CONST(uint64_t(0x7FF0000000000000), |
165 | (UInt128(0x7ffeffffff) << 40) + UInt128(0xffffffffff), |
166 | (UInt128(0x7ffeffffffffffff) << 64) + |
167 | UInt128(0xfffd57322e3f8675)), |
168 | SELECT_CONST(ERANGE, 0, 0)); |
169 | run_test("1.18973149535723176508e4932" , 27, |
170 | SELECT_CONST(uint64_t(0x7FF0000000000000), |
171 | (UInt128(0x7fff800000) << 40), |
172 | (UInt128(0x7ffeffffffffffff) << 64) + |
173 | UInt128(0xffffd2478338036c)), |
174 | SELECT_CONST(ERANGE, ERANGE, 0)); |
175 | } |
176 | |
177 | // These tests check subnormal behavior for 80 bit and 128 bit floats. They will |
178 | // be too small for 64 bit floats. |
179 | TEST_F(LlvmLibcStrToLDTest, SubnormalTests) { |
180 | run_test("1e-4950" , 7, |
181 | SELECT_CONST(uint64_t(0), (UInt128(0x00000000000000000003)), |
182 | (UInt128(0x000000000000000000057c9647e1a018))), |
183 | ERANGE); |
184 | run_test("1.89e-4951" , 10, |
185 | SELECT_CONST(uint64_t(0), (UInt128(0x00000000000000000001)), |
186 | (UInt128(0x0000000000000000000109778a006738))), |
187 | ERANGE); |
188 | run_test("4e-4966" , 7, |
189 | SELECT_CONST(uint64_t(0), (UInt128(0)), |
190 | (UInt128(0x00000000000000000000000000000001))), |
191 | ERANGE); |
192 | } |
193 | |
194 | TEST_F(LlvmLibcStrToLDTest, SmallNormalTests) { |
195 | run_test("3.37e-4932" , 10, |
196 | SELECT_CONST( |
197 | uint64_t(0), (UInt128(0x1804cf7) << 40) + UInt128(0x908850712), |
198 | (UInt128(0x10099ee12110a) << 64) + UInt128(0xe24b75c0f50dc0c)), |
199 | SELECT_CONST(ERANGE, 0, 0)); |
200 | } |
201 | |
202 | TEST_F(LlvmLibcStrToLDTest, ComplexHexadecimalTests) { |
203 | run_test("0x1p16383" , 9, |
204 | SELECT_CONST(0x7ff0000000000000, (UInt128(0x7ffe800000) << 40), |
205 | (UInt128(0x7ffe000000000000) << 64)), |
206 | SELECT_CONST(ERANGE, 0, 0)); |
207 | run_test("0x123456789abcdef" , 17, |
208 | SELECT_CONST(0x43723456789abcdf, |
209 | (UInt128(0x403791a2b3) << 40) + UInt128(0xc4d5e6f780), |
210 | (UInt128(0x403723456789abcd) << 64) + |
211 | UInt128(0xef00000000000000))); |
212 | run_test("0x123456789abcdef0123456789ABCDEF" , 33, |
213 | SELECT_CONST(0x47723456789abcdf, |
214 | (UInt128(0x407791a2b3) << 40) + UInt128(0xc4d5e6f781), |
215 | (UInt128(0x407723456789abcd) << 64) + |
216 | UInt128(0xef0123456789abce))); |
217 | } |
218 | |
219 | TEST_F(LlvmLibcStrToLDTest, InfTests) { |
220 | run_test("INF" , 3, |
221 | SELECT_CONST(0x7ff0000000000000, (UInt128(0x7fff800000) << 40), |
222 | (UInt128(0x7fff000000000000) << 64))); |
223 | run_test("INFinity" , 8, |
224 | SELECT_CONST(0x7ff0000000000000, (UInt128(0x7fff800000) << 40), |
225 | (UInt128(0x7fff000000000000) << 64))); |
226 | run_test("-inf" , 4, |
227 | SELECT_CONST(0xfff0000000000000, (UInt128(0xffff800000) << 40), |
228 | (UInt128(0xffff000000000000) << 64))); |
229 | } |
230 | |
231 | TEST_F(LlvmLibcStrToLDTest, NaNTests) { |
232 | run_test("NaN" , 3, |
233 | SELECT_CONST(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), |
234 | (UInt128(0x7fff800000000000) << 64))); |
235 | run_test("-nAn" , 4, |
236 | SELECT_CONST(0xfff8000000000000, (UInt128(0xffffc00000) << 40), |
237 | (UInt128(0xffff800000000000) << 64))); |
238 | run_test("NaN()" , 5, |
239 | SELECT_CONST(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), |
240 | (UInt128(0x7fff800000000000) << 64))); |
241 | run_test("NaN(1234)" , 9, |
242 | SELECT_CONST(0x7ff80000000004d2, |
243 | (UInt128(0x7fffc00000) << 40) + UInt128(0x4d2), |
244 | (UInt128(0x7fff800000000000) << 64) + UInt128(0x4d2))); |
245 | run_test("NaN(0xffffffffffff)" , 19, |
246 | SELECT_CONST(0x7ff8ffffffffffff, |
247 | (UInt128(0x7fffc000ff) << 40) + UInt128(0xffffffffff), |
248 | (UInt128(0x7fff800000000000) << 64) + |
249 | UInt128(0xffffffffffff))); |
250 | run_test("NaN(0xfffffffffffff)" , 20, |
251 | SELECT_CONST(0x7fffffffffffffff, |
252 | (UInt128(0x7fffc00fff) << 40) + UInt128(0xffffffffff), |
253 | (UInt128(0x7fff800000000000) << 64) + |
254 | UInt128(0xfffffffffffff))); |
255 | run_test("NaN(0xffffffffffffffff)" , 23, |
256 | SELECT_CONST(0x7fffffffffffffff, |
257 | (UInt128(0x7fffffffff) << 40) + UInt128(0xffffffffff), |
258 | (UInt128(0x7fff800000000000) << 64) + |
259 | UInt128(0xffffffffffffffff))); |
260 | run_test("NaN( 1234)" , 3, |
261 | SELECT_CONST(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), |
262 | (UInt128(0x7fff800000000000) << 64))); |
263 | } |
264 | |