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