xref: /aosp_15_r20/external/emboss/compiler/back_end/cpp/testcode/float_test.cc (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Tests for Emboss floating-point support.
16 
17 #include <stdint.h>
18 
19 #include <cmath>
20 #include <vector>
21 
22 #include "gtest/gtest.h"
23 #include "testdata/float.emb.h"
24 
25 namespace emboss {
26 namespace test {
27 namespace {
28 
MakeFloats(::std::uint32_t bits)29 ::std::array<char, 8> MakeFloats(::std::uint32_t bits) {
30   return ::std::array<char, 8>({{
31       // Little endian version
32       static_cast<char>(bits & 0xff),          //
33       static_cast<char>((bits >> 8) & 0xff),   //
34       static_cast<char>((bits >> 16) & 0xff),  //
35       static_cast<char>((bits >> 24) & 0xff),  //
36 
37       // Big endian version
38       static_cast<char>((bits >> 24) & 0xff),  //
39       static_cast<char>((bits >> 16) & 0xff),  //
40       static_cast<char>((bits >> 8) & 0xff),   //
41       static_cast<char>(bits & 0xff),          //
42   }});
43 }
44 
MakeDoubles(::std::uint64_t bits)45 ::std::array<char, 16> MakeDoubles(::std::uint64_t bits) {
46   return ::std::array<char, 16>({{
47       // Little endian version
48       static_cast<char>(bits & 0xff),          //
49       static_cast<char>((bits >> 8) & 0xff),   //
50       static_cast<char>((bits >> 16) & 0xff),  //
51       static_cast<char>((bits >> 24) & 0xff),  //
52       static_cast<char>((bits >> 32) & 0xff),  //
53       static_cast<char>((bits >> 40) & 0xff),  //
54       static_cast<char>((bits >> 48) & 0xff),  //
55       static_cast<char>((bits >> 56) & 0xff),  //
56 
57       // Big endian version
58       static_cast<char>((bits >> 56) & 0xff),  //
59       static_cast<char>((bits >> 48) & 0xff),  //
60       static_cast<char>((bits >> 40) & 0xff),  //
61       static_cast<char>((bits >> 32) & 0xff),  //
62       static_cast<char>((bits >> 24) & 0xff),  //
63       static_cast<char>((bits >> 16) & 0xff),  //
64       static_cast<char>((bits >> 8) & 0xff),   //
65       static_cast<char>(bits & 0xff),          //
66   }});
67 }
68 
69 // This is used separately for tests where !(a == a).
TestFloatWrite(float value,::std::uint32_t bits)70 void TestFloatWrite(float value, ::std::uint32_t bits) {
71   const auto floats = MakeFloats(bits);
72 
73   ::std::array<char, 8> buffer = {};
74   auto writer = MakeFloatsView(&buffer);
75   EXPECT_TRUE(writer.float_little_endian().CouldWriteValue(value));
76   EXPECT_TRUE(writer.float_big_endian().CouldWriteValue(value));
77   writer.float_little_endian().Write(value);
78   writer.float_big_endian().Write(value);
79   EXPECT_EQ(floats, buffer);
80 }
81 
TestFloatValue(float value,::std::uint32_t bits)82 ::std::array<char, 8> TestFloatValue(float value, ::std::uint32_t bits) {
83   const auto floats = MakeFloats(bits);
84 
85   auto view = MakeFloatsView(&floats);
86   EXPECT_EQ(value, view.float_little_endian().Read());
87   EXPECT_EQ(value, view.float_big_endian().Read());
88 
89   TestFloatWrite(value, bits);
90 
91   return floats;
92 }
93 
94 // This is used separately for tests where !(a == a).
TestDoubleWrite(double value,::std::uint64_t bits)95 void TestDoubleWrite(double value, ::std::uint64_t bits) {
96   const auto doubles = MakeDoubles(bits);
97 
98   ::std::array<char, 16> buffer = {};
99   auto writer = MakeDoublesView(&buffer);
100   EXPECT_TRUE(writer.double_little_endian().CouldWriteValue(value));
101   EXPECT_TRUE(writer.double_big_endian().CouldWriteValue(value));
102   writer.double_little_endian().Write(value);
103   writer.double_big_endian().Write(value);
104   EXPECT_EQ(doubles, buffer);
105 }
106 
TestDoubleValue(double value,::std::uint64_t bits)107 ::std::array<char, 16> TestDoubleValue(double value, ::std::uint64_t bits) {
108   const auto doubles = MakeDoubles(bits);
109 
110   auto view = MakeDoublesView(&doubles);
111   EXPECT_EQ(value, view.double_little_endian().Read());
112   EXPECT_EQ(value, view.double_big_endian().Read());
113 
114   TestDoubleWrite(value, bits);
115 
116   return doubles;
117 }
118 
TEST(Floats,One)119 TEST(Floats, One) { TestFloatValue(+1.0f, 0x3f800000); }
TEST(Floats,Fraction)120 TEST(Floats, Fraction) { TestFloatValue(-0.375f, 0xbec00000); }
TEST(Floats,MinimumDenorm)121 TEST(Floats, MinimumDenorm) {
122   TestFloatValue(::std::exp2(-149.0f), 0x00000001);
123 }
124 
TEST(Floats,PlusZero)125 TEST(Floats, PlusZero) {
126   auto floats = TestFloatValue(+0.0f, 0x00000000);
127   auto view = MakeFloatsView(&floats);
128   EXPECT_FALSE(::std::signbit(view.float_little_endian().Read()));
129   EXPECT_FALSE(::std::signbit(view.float_big_endian().Read()));
130 }
131 
TEST(Floats,MinusZero)132 TEST(Floats, MinusZero) {
133   auto floats = TestFloatValue(-0.0f, 0x80000000);
134   auto view = MakeFloatsView(&floats);
135   EXPECT_TRUE(::std::signbit(view.float_little_endian().Read()));
136   EXPECT_TRUE(::std::signbit(view.float_big_endian().Read()));
137 }
138 
TEST(Floats,PlusInfinity)139 TEST(Floats, PlusInfinity) {
140   auto floats = MakeFloats(0x7f800000);
141   auto view = MakeFloatsView(&floats);
142   EXPECT_TRUE(::std::isinf(view.float_little_endian().Read()));
143   EXPECT_TRUE(::std::isinf(view.float_big_endian().Read()));
144   EXPECT_FALSE(::std::signbit(view.float_little_endian().Read()));
145   EXPECT_FALSE(::std::signbit(view.float_big_endian().Read()));
146   TestFloatWrite(view.float_little_endian().Read(), 0x7f800000);
147 }
148 
TEST(Floats,MinusInfinity)149 TEST(Floats, MinusInfinity) {
150   auto floats = MakeFloats(0xff800000);
151   auto view = MakeFloatsView(&floats);
152   EXPECT_TRUE(::std::isinf(view.float_little_endian().Read()));
153   EXPECT_TRUE(::std::isinf(view.float_big_endian().Read()));
154   EXPECT_TRUE(::std::signbit(view.float_little_endian().Read()));
155   EXPECT_TRUE(::std::signbit(view.float_big_endian().Read()));
156   TestFloatWrite(view.float_little_endian().Read(), 0xff800000);
157 }
158 
TEST(Floats,Nan)159 TEST(Floats, Nan) {
160   // TODO(bolms): IEEE 754 does not specify the difference between quiet and
161   // signalling NaN, and there are two completely incompatible definitions in
162   // use by modern processors.  Ideally, Emboss should provide some way to
163   // specify which convention is in use, but in practice it probably doesn't
164   // matter when dealing with hardware devices.
165   //
166   // Note that the above bit patterns are signalling NaNs on some processors,
167   // and thus any operation on them other than 'std::isnan' should be avoided.
168 
169   auto floats = MakeFloats(0x7f800001);
170   auto view = MakeFloatsView(&floats);
171   EXPECT_TRUE(::std::isnan(view.float_little_endian().Read()));
172   EXPECT_TRUE(::std::isnan(view.float_big_endian().Read()));
173   TestFloatWrite(view.float_little_endian().Read(), 0x7f800001);
174 }
175 
TEST(FloatView,Equals)176 TEST(FloatView, Equals) {
177   auto buf_x = MakeFloats(64);
178   auto buf_y = MakeFloats(64);
179   EXPECT_EQ(buf_x, buf_y);
180 
181   auto x = MakeFloatsView(&buf_x);
182   auto x_const =
183       MakeFloatsView(static_cast</**/ ::std::array<char, 8>*>(&buf_x));
184   auto y = MakeFloatsView(&buf_y);
185 
186   EXPECT_TRUE(x.Equals(x));
187   EXPECT_TRUE(x.UncheckedEquals(x));
188   EXPECT_TRUE(y.Equals(y));
189   EXPECT_TRUE(y.UncheckedEquals(y));
190 
191   EXPECT_TRUE(x.Equals(y));
192   EXPECT_TRUE(x.UncheckedEquals(y));
193   EXPECT_TRUE(y.Equals(x));
194   EXPECT_TRUE(y.UncheckedEquals(x));
195 
196   EXPECT_TRUE(x_const.Equals(y));
197   EXPECT_TRUE(x_const.UncheckedEquals(y));
198   EXPECT_TRUE(y.Equals(x_const));
199   EXPECT_TRUE(y.UncheckedEquals(x_const));
200 
201   ++buf_y[1];
202   EXPECT_FALSE(x.Equals(y));
203   EXPECT_FALSE(x.UncheckedEquals(y));
204   EXPECT_FALSE(y.Equals(x));
205   EXPECT_FALSE(y.UncheckedEquals(x));
206 }
207 
TEST(FloatView,EqualsNaN)208 TEST(FloatView, EqualsNaN) {
209   auto buf_x = MakeFloats(0x7f800001);
210   auto buf_y = MakeFloats(0x7f800001);
211   EXPECT_EQ(buf_x, buf_y);
212 
213   auto x = MakeFloatsView(&buf_x);
214   auto y = MakeFloatsView(&buf_y);
215 
216   EXPECT_TRUE(::std::isnan(x.float_little_endian().Read()));
217   EXPECT_TRUE(::std::isnan(x.float_big_endian().Read()));
218   EXPECT_TRUE(::std::isnan(y.float_little_endian().Read()));
219   EXPECT_TRUE(::std::isnan(y.float_big_endian().Read()));
220 
221   EXPECT_FALSE(x.Equals(x));
222   EXPECT_FALSE(y.Equals(y));
223   EXPECT_FALSE(x.Equals(y));
224   EXPECT_FALSE(y.Equals(x));
225 }
226 
TEST(Doubles,One)227 TEST(Doubles, One) { TestDoubleValue(+1.0, 0x3ff0000000000000UL); }
TEST(Doubles,Fraction)228 TEST(Doubles, Fraction) { TestDoubleValue(-0.375, 0xbfd8000000000000UL); }
TEST(Doubles,MinimumDenorm)229 TEST(Doubles, MinimumDenorm) {
230   TestDoubleValue(::std::exp2(-1074.0), 0x0000000000000001UL);
231 }
232 
TEST(Doubles,PlusZero)233 TEST(Doubles, PlusZero) {
234   auto doubles = TestDoubleValue(+0.0, 0x0000000000000000UL);
235   auto view = MakeDoublesView(&doubles);
236   EXPECT_FALSE(::std::signbit(view.double_little_endian().Read()));
237   EXPECT_FALSE(::std::signbit(view.double_big_endian().Read()));
238 }
239 
TEST(Doubles,MinusZero)240 TEST(Doubles, MinusZero) {
241   auto doubles = TestDoubleValue(-0.0, 0x8000000000000000UL);
242   auto view = MakeDoublesView(&doubles);
243   EXPECT_TRUE(::std::signbit(view.double_little_endian().Read()));
244   EXPECT_TRUE(::std::signbit(view.double_big_endian().Read()));
245 }
246 
TEST(Doubles,PlusInfinity)247 TEST(Doubles, PlusInfinity) {
248   auto doubles = MakeDoubles(0x7ff0000000000000UL);
249   auto view = MakeDoublesView(&doubles);
250   EXPECT_TRUE(::std::isinf(view.double_little_endian().Read()));
251   EXPECT_TRUE(::std::isinf(view.double_big_endian().Read()));
252   EXPECT_FALSE(::std::signbit(view.double_little_endian().Read()));
253   EXPECT_FALSE(::std::signbit(view.double_big_endian().Read()));
254   TestDoubleWrite(view.double_little_endian().Read(), 0x7ff0000000000000UL);
255 }
256 
TEST(Doubles,MinusInfinity)257 TEST(Doubles, MinusInfinity) {
258   auto doubles = MakeDoubles(0xfff0000000000000UL);
259   auto view = MakeDoublesView(&doubles);
260   EXPECT_TRUE(::std::isinf(view.double_little_endian().Read()));
261   EXPECT_TRUE(::std::isinf(view.double_big_endian().Read()));
262   EXPECT_TRUE(::std::signbit(view.double_little_endian().Read()));
263   EXPECT_TRUE(::std::signbit(view.double_big_endian().Read()));
264   TestDoubleWrite(view.double_little_endian().Read(), 0xfff0000000000000UL);
265 }
266 
TEST(Doubles,Nan)267 TEST(Doubles, Nan) {
268   auto doubles = MakeDoubles(0x7ff0000000000001UL);
269   auto view = MakeDoublesView(&doubles);
270   EXPECT_TRUE(::std::isnan(view.double_little_endian().Read()));
271   EXPECT_TRUE(::std::isnan(view.double_big_endian().Read()));
272   TestDoubleWrite(view.double_little_endian().Read(), 0x7ff0000000000001UL);
273 }
274 
TEST(Doubles,CopyFrom)275 TEST(Doubles, CopyFrom) {
276   auto doubles_x = MakeDoubles(0x7ff0000000000001UL);
277   auto doubles_y = MakeDoubles(0x0000000000000000UL);
278 
279   auto x = MakeDoublesView(&doubles_x);
280   auto y = MakeDoublesView(&doubles_y);
281 
282   EXPECT_NE(x.double_little_endian().Read(), y.double_little_endian().Read());
283   EXPECT_NE(x.double_big_endian().Read(), y.double_big_endian().Read());
284   x.double_little_endian().CopyFrom(y.double_little_endian());
285   x.double_big_endian().CopyFrom(y.double_big_endian());
286   EXPECT_EQ(x.double_little_endian().Read(), y.double_little_endian().Read());
287   EXPECT_EQ(x.double_big_endian().Read(), y.double_big_endian().Read());
288 }
289 
TEST(Doubles,TryToCopyFrom)290 TEST(Doubles, TryToCopyFrom) {
291   auto doubles_x = MakeDoubles(0x7ff0000000000001UL);
292   auto doubles_y = MakeDoubles(0x0000000000000000UL);
293 
294   auto x = MakeDoublesView(&doubles_x);
295   auto y = MakeDoublesView(&doubles_y);
296 
297   EXPECT_NE(x.double_little_endian().Read(), y.double_little_endian().Read());
298   EXPECT_NE(x.double_big_endian().Read(), y.double_big_endian().Read());
299   EXPECT_TRUE(x.double_little_endian().TryToCopyFrom(y.double_little_endian()));
300   EXPECT_TRUE(x.double_big_endian().TryToCopyFrom(y.double_big_endian()));
301   EXPECT_EQ(x.double_little_endian().Read(), y.double_little_endian().Read());
302   EXPECT_EQ(x.double_big_endian().Read(), y.double_big_endian().Read());
303 }
304 
TEST(DoubleView,Equals)305 TEST(DoubleView, Equals) {
306   auto buf_x = MakeDoubles(64);
307   auto buf_y = MakeDoubles(64);
308   EXPECT_EQ(buf_x, buf_y);
309 
310   auto x = MakeDoublesView(&buf_x);
311   auto y = MakeDoublesView(&buf_y);
312 
313   EXPECT_TRUE(x.Equals(x));
314   EXPECT_TRUE(y.Equals(y));
315 
316   EXPECT_TRUE(x.Equals(y));
317   EXPECT_TRUE(y.Equals(x));
318 
319   ++buf_y[1];
320   EXPECT_FALSE(x.Equals(y));
321   EXPECT_FALSE(y.Equals(x));
322 }
323 
TEST(DoubleView,EqualsNaN)324 TEST(DoubleView, EqualsNaN) {
325   auto buf_x = MakeDoubles(0x7ff0000000000001UL);
326   auto buf_y = MakeDoubles(0x7ff0000000000001UL);
327   EXPECT_EQ(buf_x, buf_y);
328 
329   auto x = MakeDoublesView(&buf_x);
330   auto y = MakeDoublesView(&buf_y);
331 
332   EXPECT_TRUE(::std::isnan(x.double_little_endian().Read()));
333   EXPECT_TRUE(::std::isnan(x.double_big_endian().Read()));
334   EXPECT_TRUE(::std::isnan(y.double_little_endian().Read()));
335   EXPECT_TRUE(::std::isnan(y.double_big_endian().Read()));
336 
337   EXPECT_FALSE(x.Equals(x));
338   EXPECT_FALSE(y.Equals(y));
339 
340   EXPECT_FALSE(x.Equals(y));
341   EXPECT_FALSE(y.Equals(x));
342 }
343 
TEST(DoubleView,WriteTextFormat)344 TEST(DoubleView, WriteTextFormat) {
345   auto buf_x = MakeDoubles(0x4050000000000000UL);
346   auto x = MakeDoublesView(&buf_x);
347   EXPECT_EQ("{ double_little_endian: 64, double_big_endian: 64 }",
348             ::emboss::WriteToString(x));
349   EXPECT_EQ(
350       "{\n"
351       "  double_little_endian: 64\n"
352       "  double_big_endian: 64\n"
353       "}",
354       ::emboss::WriteToString(x, ::emboss::MultilineText()));
355 }
356 
TEST(DoubleView,ReadTextFormat)357 TEST(DoubleView, ReadTextFormat) {
358   auto buf_x = MakeDoubles(0UL);
359   auto x = MakeDoublesView(&buf_x);
360   EXPECT_TRUE(::emboss::UpdateFromText(x,
361                                        "{\n"
362                                        "  double_little_endian: 64\n"
363                                        "  double_big_endian: 64\n"
364                                        "}"));
365   EXPECT_EQ(64, x.double_little_endian().Read());
366   EXPECT_EQ(64, x.double_big_endian().Read());
367 }
368 
369 }  // namespace
370 }  // namespace test
371 }  // namespace emboss
372