blob: eeb31edacd54682514a337e96d56e39361922696 [file] [log] [blame]
Ben Claytonc2eccfc2022-05-25 15:04:24 +00001// Copyright 2022 The Tint Authors.
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// http://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#include <cmath>
Ben Clayton61537d32022-05-31 13:14:29 +000016#include <tuple>
17#include <vector>
Ben Claytonc2eccfc2022-05-25 15:04:24 +000018
19#include "src/tint/program_builder.h"
Ben Clayton572eaf22022-05-27 20:22:26 +000020#include "src/tint/utils/compiler_macros.h"
Ben Claytonc2eccfc2022-05-25 15:04:24 +000021
22#include "gtest/gtest.h"
23
24using namespace tint::number_suffixes; // NOLINT
25
26namespace tint {
27namespace {
28
29constexpr int64_t kHighestI32 = static_cast<int64_t>(std::numeric_limits<int32_t>::max());
30constexpr int64_t kHighestU32 = static_cast<int64_t>(std::numeric_limits<uint32_t>::max());
31constexpr int64_t kLowestI32 = static_cast<int64_t>(std::numeric_limits<int32_t>::min());
32constexpr int64_t kLowestU32 = static_cast<int64_t>(std::numeric_limits<uint32_t>::min());
33
Ben Clayton572eaf22022-05-27 20:22:26 +000034// Highest float32 value.
35constexpr double kHighestF32 = 0x1.fffffep+127;
Ben Claytonc2eccfc2022-05-25 15:04:24 +000036
Ben Clayton572eaf22022-05-27 20:22:26 +000037// Next ULP up from kHighestF32 for a float64.
38constexpr double kHighestF32NextULP = 0x1.fffffe0000001p+127;
Ben Claytonc2eccfc2022-05-25 15:04:24 +000039
Ben Clayton572eaf22022-05-27 20:22:26 +000040// Smallest positive normal float32 value.
41constexpr double kSmallestF32 = 0x1p-126;
Ben Claytonc2eccfc2022-05-25 15:04:24 +000042
Ben Clayton572eaf22022-05-27 20:22:26 +000043// Highest subnormal value for a float32.
44constexpr double kHighestF32Subnormal = 0x0.fffffep-126;
Ben Claytonc2eccfc2022-05-25 15:04:24 +000045
Ben Clayton572eaf22022-05-27 20:22:26 +000046// Highest float16 value.
47constexpr double kHighestF16 = 0x1.ffcp+15;
Ben Claytonc2eccfc2022-05-25 15:04:24 +000048
Ben Clayton572eaf22022-05-27 20:22:26 +000049// Next ULP up from kHighestF16 for a float64.
50constexpr double kHighestF16NextULP = 0x1.ffc0000000001p+15;
Ben Claytonc2eccfc2022-05-25 15:04:24 +000051
Ben Clayton572eaf22022-05-27 20:22:26 +000052// Smallest positive normal float16 value.
53constexpr double kSmallestF16 = 0x1p-14;
Ben Claytonc2eccfc2022-05-25 15:04:24 +000054
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +000055// Highest subnormal value for a float16.
Ben Clayton572eaf22022-05-27 20:22:26 +000056constexpr double kHighestF16Subnormal = 0x0.ffcp-14;
Ben Claytonc2eccfc2022-05-25 15:04:24 +000057
58constexpr double kLowestF32 = -kHighestF32;
59constexpr double kLowestF32NextULP = -kHighestF32NextULP;
60constexpr double kLowestF16 = -kHighestF16;
61constexpr double kLowestF16NextULP = -kHighestF16NextULP;
62
Ben Clayton572eaf22022-05-27 20:22:26 +000063// MSVC (only in release builds) can grumble about some of the inlined numerical overflow /
64// underflow that's done in this file. We like to think we know what we're doing, so silence the
65// warning.
66TINT_BEGIN_DISABLE_WARNING(CONSTANT_OVERFLOW);
67
Ben Claytoncf52af72022-06-29 17:09:11 +000068TEST(NumberTest, Equality) {
69 EXPECT_TRUE(0_a == 0_a);
70 EXPECT_TRUE(10_a == 10_a);
71 EXPECT_TRUE(-10_a == -10_a);
72
73 EXPECT_TRUE(0_i == 0_i);
74 EXPECT_TRUE(10_i == 10_i);
75 EXPECT_TRUE(-10_i == -10_i);
76
77 EXPECT_TRUE(0_u == 0_u);
78 EXPECT_TRUE(10_u == 10_u);
79
80 EXPECT_TRUE(0._a == 0._a);
81 EXPECT_TRUE(-0._a == -0._a);
82 EXPECT_TRUE(10._a == 10._a);
83 EXPECT_TRUE(-10._a == -10._a);
84
85 EXPECT_TRUE(0_f == 0_f);
86 EXPECT_TRUE(-0_f == -0_f);
87 EXPECT_TRUE(10_f == 10_f);
88 EXPECT_TRUE(-10_f == -10_f);
89
90 EXPECT_TRUE(0_h == 0_h);
91 EXPECT_TRUE(-0_h == -0_h);
92 EXPECT_TRUE(10_h == 10_h);
93 EXPECT_TRUE(-10_h == -10_h);
94}
95
96TEST(NumberTest, Inequality) {
97 EXPECT_TRUE(0_a != 1_a);
98 EXPECT_TRUE(10_a != 11_a);
99 EXPECT_TRUE(11_a != 10_a);
100 EXPECT_TRUE(-10_a != -11_a);
101 EXPECT_TRUE(-11_a != -10_a);
102
103 EXPECT_TRUE(0_i != 1_i);
104 EXPECT_TRUE(1_i != 0_i);
105 EXPECT_TRUE(10_i != 11_i);
106 EXPECT_TRUE(11_i != 10_i);
107 EXPECT_TRUE(-10_i != -11_i);
108 EXPECT_TRUE(-11_i != -10_i);
109
110 EXPECT_TRUE(0_u != 1_u);
111 EXPECT_TRUE(1_u != 0_u);
112 EXPECT_TRUE(10_u != 11_u);
113 EXPECT_TRUE(11_u != 10_u);
114
115 EXPECT_TRUE(0._a != -0._a);
116 EXPECT_TRUE(-0._a != 0._a);
117 EXPECT_TRUE(10._a != 11._a);
118 EXPECT_TRUE(11._a != 10._a);
119 EXPECT_TRUE(-10._a != -11._a);
120 EXPECT_TRUE(-11._a != -10._a);
121
122 EXPECT_TRUE(0_f != -0_f);
123 EXPECT_TRUE(-0_f != 0_f);
124 EXPECT_TRUE(-0_f != -1_f);
125 EXPECT_TRUE(-1_f != -0_f);
126 EXPECT_TRUE(10_f != -10_f);
127 EXPECT_TRUE(-10_f != 10_f);
128 EXPECT_TRUE(10_f != 11_f);
129 EXPECT_TRUE(-10_f != -11_f);
130
131 EXPECT_TRUE(0_h != -0_h);
132 EXPECT_TRUE(-0_h != 0_h);
133 EXPECT_TRUE(-0_h != -1_h);
134 EXPECT_TRUE(-1_h != -0_h);
135 EXPECT_TRUE(10_h != -10_h);
136 EXPECT_TRUE(-10_h != 10_h);
137 EXPECT_TRUE(10_h != 11_h);
138 EXPECT_TRUE(-10_h != -11_h);
139}
140
Ben Claytonc2eccfc2022-05-25 15:04:24 +0000141TEST(NumberTest, CheckedConvertIdentity) {
142 EXPECT_EQ(CheckedConvert<AInt>(0_a), 0_a);
143 EXPECT_EQ(CheckedConvert<AFloat>(0_a), 0.0_a);
144 EXPECT_EQ(CheckedConvert<i32>(0_i), 0_i);
145 EXPECT_EQ(CheckedConvert<u32>(0_u), 0_u);
146 EXPECT_EQ(CheckedConvert<f32>(0_f), 0_f);
147 EXPECT_EQ(CheckedConvert<f16>(0_h), 0_h);
148
149 EXPECT_EQ(CheckedConvert<AInt>(1_a), 1_a);
150 EXPECT_EQ(CheckedConvert<AFloat>(1_a), 1.0_a);
151 EXPECT_EQ(CheckedConvert<i32>(1_i), 1_i);
152 EXPECT_EQ(CheckedConvert<u32>(1_u), 1_u);
153 EXPECT_EQ(CheckedConvert<f32>(1_f), 1_f);
154 EXPECT_EQ(CheckedConvert<f16>(1_h), 1_h);
155}
156
157TEST(NumberTest, CheckedConvertLargestValue) {
158 EXPECT_EQ(CheckedConvert<i32>(AInt(kHighestI32)), i32(kHighestI32));
159 EXPECT_EQ(CheckedConvert<u32>(AInt(kHighestU32)), u32(kHighestU32));
Ben Clayton2b4df782022-06-29 11:31:41 +0000160 EXPECT_EQ(CheckedConvert<u32>(i32(kHighestI32)), u32(kHighestI32));
Ben Claytonc2eccfc2022-05-25 15:04:24 +0000161 EXPECT_EQ(CheckedConvert<f32>(AFloat(kHighestF32)), f32(kHighestF32));
162 EXPECT_EQ(CheckedConvert<f16>(AFloat(kHighestF16)), f16(kHighestF16));
163}
164
165TEST(NumberTest, CheckedConvertLowestValue) {
166 EXPECT_EQ(CheckedConvert<i32>(AInt(kLowestI32)), i32(kLowestI32));
167 EXPECT_EQ(CheckedConvert<u32>(AInt(kLowestU32)), u32(kLowestU32));
168 EXPECT_EQ(CheckedConvert<f32>(AFloat(kLowestF32)), f32(kLowestF32));
169 EXPECT_EQ(CheckedConvert<f16>(AFloat(kLowestF16)), f16(kLowestF16));
170}
171
172TEST(NumberTest, CheckedConvertSmallestValue) {
173 EXPECT_EQ(CheckedConvert<i32>(AInt(0)), i32(0));
174 EXPECT_EQ(CheckedConvert<u32>(AInt(0)), u32(0));
175 EXPECT_EQ(CheckedConvert<f32>(AFloat(kSmallestF32)), f32(kSmallestF32));
176 EXPECT_EQ(CheckedConvert<f16>(AFloat(kSmallestF16)), f16(kSmallestF16));
177}
178
179TEST(NumberTest, CheckedConvertExceedsPositiveLimit) {
180 EXPECT_EQ(CheckedConvert<i32>(AInt(kHighestI32 + 1)), ConversionFailure::kExceedsPositiveLimit);
181 EXPECT_EQ(CheckedConvert<u32>(AInt(kHighestU32 + 1)), ConversionFailure::kExceedsPositiveLimit);
Ben Clayton2b4df782022-06-29 11:31:41 +0000182 EXPECT_EQ(CheckedConvert<i32>(u32(kHighestU32)), ConversionFailure::kExceedsPositiveLimit);
183 EXPECT_EQ(CheckedConvert<i32>(u32(0x80000000)), ConversionFailure::kExceedsPositiveLimit);
184 EXPECT_EQ(CheckedConvert<u32>(f32(f32::kHighest)), ConversionFailure::kExceedsPositiveLimit);
185 EXPECT_EQ(CheckedConvert<i32>(f32(f32::kHighest)), ConversionFailure::kExceedsPositiveLimit);
186 EXPECT_EQ(CheckedConvert<u32>(AFloat(AFloat::kHighest)),
187 ConversionFailure::kExceedsPositiveLimit);
188 EXPECT_EQ(CheckedConvert<i32>(AFloat(AFloat::kHighest)),
189 ConversionFailure::kExceedsPositiveLimit);
Ben Claytonc2eccfc2022-05-25 15:04:24 +0000190 EXPECT_EQ(CheckedConvert<f32>(AFloat(kHighestF32NextULP)),
191 ConversionFailure::kExceedsPositiveLimit);
192 EXPECT_EQ(CheckedConvert<f16>(AFloat(kHighestF16NextULP)),
193 ConversionFailure::kExceedsPositiveLimit);
194}
195
196TEST(NumberTest, CheckedConvertExceedsNegativeLimit) {
197 EXPECT_EQ(CheckedConvert<i32>(AInt(kLowestI32 - 1)), ConversionFailure::kExceedsNegativeLimit);
198 EXPECT_EQ(CheckedConvert<u32>(AInt(kLowestU32 - 1)), ConversionFailure::kExceedsNegativeLimit);
Ben Clayton2b4df782022-06-29 11:31:41 +0000199 EXPECT_EQ(CheckedConvert<u32>(i32(-1)), ConversionFailure::kExceedsNegativeLimit);
200 EXPECT_EQ(CheckedConvert<u32>(i32(kLowestI32)), ConversionFailure::kExceedsNegativeLimit);
201 EXPECT_EQ(CheckedConvert<u32>(f32(f32::kLowest)), ConversionFailure::kExceedsNegativeLimit);
202 EXPECT_EQ(CheckedConvert<i32>(f32(f32::kLowest)), ConversionFailure::kExceedsNegativeLimit);
203 EXPECT_EQ(CheckedConvert<u32>(AFloat(AFloat::kLowest)),
204 ConversionFailure::kExceedsNegativeLimit);
205 EXPECT_EQ(CheckedConvert<i32>(AFloat(AFloat::kLowest)),
206 ConversionFailure::kExceedsNegativeLimit);
Ben Claytonc2eccfc2022-05-25 15:04:24 +0000207 EXPECT_EQ(CheckedConvert<f32>(AFloat(kLowestF32NextULP)),
208 ConversionFailure::kExceedsNegativeLimit);
209 EXPECT_EQ(CheckedConvert<f16>(AFloat(kLowestF16NextULP)),
210 ConversionFailure::kExceedsNegativeLimit);
211}
212
Ben Clayton572eaf22022-05-27 20:22:26 +0000213TEST(NumberTest, CheckedConvertSubnormals) {
214 EXPECT_EQ(CheckedConvert<f32>(AFloat(kHighestF32Subnormal)), f32(kHighestF32Subnormal));
215 EXPECT_EQ(CheckedConvert<f16>(AFloat(kHighestF16Subnormal)), f16(kHighestF16Subnormal));
216 EXPECT_EQ(CheckedConvert<f32>(AFloat(-kHighestF32Subnormal)), f32(-kHighestF32Subnormal));
217 EXPECT_EQ(CheckedConvert<f16>(AFloat(-kHighestF16Subnormal)), f16(-kHighestF16Subnormal));
Ben Claytonc2eccfc2022-05-25 15:04:24 +0000218}
219
Zhaoming Jiang2c7440a2022-07-07 03:29:11 +0000220// Test cases for f16 subnormal quantization and BitsRepresentation.
221// The ULP is based on float rather than double or f16, since F16::Quantize and
222// F16::BitsRepresentation take float as input.
223constexpr float lowestPositiveNormalF16 = 0x1p-14;
224constexpr float lowestPositiveNormalF16PlusULP = 0x1.000002p-14;
225constexpr float lowestPositiveNormalF16MinusULP = 0x1.fffffep-15;
226constexpr float highestPositiveSubnormalF16 = 0x0.ffcp-14;
227constexpr float highestPositiveSubnormalF16PlusULP = 0x1.ff8002p-15;
228constexpr float highestPositiveSubnormalF16MinusULP = 0x1.ff7ffep-15;
229constexpr float lowestPositiveSubnormalF16 = 0x1.p-24;
230constexpr float lowestPositiveSubnormalF16PlusULP = 0x1.000002p-24;
231constexpr float lowestPositiveSubnormalF16MinusULP = 0x1.fffffep-25;
Ben Claytonc2eccfc2022-05-25 15:04:24 +0000232
Zhaoming Jiang2c7440a2022-07-07 03:29:11 +0000233constexpr uint16_t lowestPositiveNormalF16Bits = 0x0400u;
234constexpr uint16_t highestPositiveSubnormalF16Bits = 0x03ffu;
235constexpr uint16_t lowestPositiveSubnormalF16Bits = 0x0001u;
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000236
Zhaoming Jiang2c7440a2022-07-07 03:29:11 +0000237constexpr float highestNegativeNormalF16 = -lowestPositiveNormalF16;
238constexpr float highestNegativeNormalF16PlusULP = -lowestPositiveNormalF16MinusULP;
239constexpr float highestNegativeNormalF16MinusULP = -lowestPositiveNormalF16PlusULP;
240constexpr float lowestNegativeSubnormalF16 = -highestPositiveSubnormalF16;
241constexpr float lowestNegativeSubnormalF16PlusULP = -highestPositiveSubnormalF16MinusULP;
242constexpr float lowestNegativeSubnormalF16MinusULP = -highestPositiveSubnormalF16PlusULP;
243constexpr float highestNegativeSubnormalF16 = -lowestPositiveSubnormalF16;
244constexpr float highestNegativeSubnormalF16PlusULP = -lowestPositiveSubnormalF16MinusULP;
245constexpr float highestNegativeSubnormalF16MinusULP = -lowestPositiveSubnormalF16PlusULP;
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000246
Zhaoming Jiang2c7440a2022-07-07 03:29:11 +0000247constexpr uint16_t highestNegativeNormalF16Bits = 0x8400u;
248constexpr uint16_t lowestNegativeSubnormalF16Bits = 0x83ffu;
249constexpr uint16_t highestNegativeSubnormalF16Bits = 0x8001u;
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000250
Zhaoming Jiang2c7440a2022-07-07 03:29:11 +0000251constexpr float f32_nan = std::numeric_limits<float>::quiet_NaN();
252constexpr float f32_inf = std::numeric_limits<float>::infinity();
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000253
Zhaoming Jiang2c7440a2022-07-07 03:29:11 +0000254struct F16TestCase {
255 float input_value;
256 float quantized_value;
257 uint16_t f16_bit_pattern;
258};
259
260using NumberF16Test = testing::TestWithParam<F16TestCase>;
261
262TEST_P(NumberF16Test, QuantizeF16) {
263 float input_value = GetParam().input_value;
264 float quantized_value = GetParam().quantized_value;
265
266 std::stringstream ss;
267 ss << "input value = " << input_value << ", expected quantized value = " << quantized_value;
268 SCOPED_TRACE(ss.str());
269
270 if (std::isnan(quantized_value)) {
271 EXPECT_TRUE(std::isnan(f16(input_value)));
272 } else {
273 EXPECT_EQ(f16(input_value), quantized_value);
274 }
Ben Claytonc2eccfc2022-05-25 15:04:24 +0000275}
276
Zhaoming Jiang2c7440a2022-07-07 03:29:11 +0000277TEST_P(NumberF16Test, BitsRepresentation) {
278 float input_value = GetParam().input_value;
279 uint16_t representation = GetParam().f16_bit_pattern;
280
281 std::stringstream ss;
282 ss << "input value = " << input_value
283 << ", expected binary16 bits representation = " << std::hex << std::showbase
284 << representation;
285 SCOPED_TRACE(ss.str());
286
287 EXPECT_EQ(f16(input_value).BitsRepresentation(), representation);
288}
289
290INSTANTIATE_TEST_SUITE_P(
291 NumberF16Test,
292 NumberF16Test,
293 testing::ValuesIn(std::vector<F16TestCase>{
294 // NaN, Inf
295 {f32_inf, f32_inf, 0x7c00u},
296 {-f32_inf, -f32_inf, 0xfc00u},
297 {f32_nan, f32_nan, 0x7e00u},
298 {-f32_nan, -f32_nan, 0x7e00u},
299 // +/- zero
300 {+0.0f, 0.0f, 0x0000u},
301 {-0.0f, -0.0f, 0x8000u},
302 // Value in normal f16 range
303 {1.0f, 1.0f, 0x3c00u},
304 {-1.0f, -1.0f, 0xbc00u},
305 // 0.00006106496 quantized to 0.000061035156 = 0x1p-14
306 {0.00006106496f, 0.000061035156f, 0x0400u},
307 {-0.00006106496f, -0.000061035156f, 0x8400u},
308 // 1.0004883 quantized to 1.0 = 0x1p0
309 {1.0004883f, 1.0f, 0x3c00u},
310 {-1.0004883f, -1.0f, 0xbc00u},
311 // 8196.0 quantized to 8192.0 = 0x1p13
312 {8196.0f, 8192.f, 0x7000u},
313 {-8196.0f, -8192.f, 0xf000u},
314 // Value in subnormal f16 range
315 {0x0.034p-14f, 0x0.034p-14f, 0x000du},
316 {-0x0.034p-14f, -0x0.034p-14f, 0x800du},
317 {0x0.068p-14f, 0x0.068p-14f, 0x001au},
318 {-0x0.068p-14f, -0x0.068p-14f, 0x801au},
319 // 0x0.06b7p-14 quantized to 0x0.068p-14
320 {0x0.06b7p-14f, 0x0.068p-14f, 0x001au},
321 {-0x0.06b7p-14f, -0x0.068p-14, 0x801au},
322 // Value out of f16 range
323 {65504.003f, f32_inf, 0x7c00u},
324 {-65504.003f, -f32_inf, 0xfc00u},
325 {0x1.234p56f, f32_inf, 0x7c00u},
326 {-0x4.321p65f, -f32_inf, 0xfc00u},
327
328 // Test for subnormal quantization.
329 // Value larger than or equal to lowest positive normal f16 will be quantized to normal f16.
330 {lowestPositiveNormalF16PlusULP, lowestPositiveNormalF16, lowestPositiveNormalF16Bits},
331 {lowestPositiveNormalF16, lowestPositiveNormalF16, lowestPositiveNormalF16Bits},
332 // Positive value smaller than lowest positive normal f16 but not smaller than lowest
333 // positive
334 // subnormal f16 will be quantized to subnormal f16 or zero.
335 {lowestPositiveNormalF16MinusULP, highestPositiveSubnormalF16,
336 highestPositiveSubnormalF16Bits},
337 {highestPositiveSubnormalF16PlusULP, highestPositiveSubnormalF16,
338 highestPositiveSubnormalF16Bits},
339 {highestPositiveSubnormalF16, highestPositiveSubnormalF16, highestPositiveSubnormalF16Bits},
340 {highestPositiveSubnormalF16MinusULP, 0x0.ff8p-14, 0x03feu},
341 {lowestPositiveSubnormalF16PlusULP, lowestPositiveSubnormalF16,
342 lowestPositiveSubnormalF16Bits},
343 {lowestPositiveSubnormalF16, lowestPositiveSubnormalF16, lowestPositiveSubnormalF16Bits},
344 // Positive value smaller than lowest positive subnormal f16 will be quantized to zero.
345 {lowestPositiveSubnormalF16MinusULP, 0.0, 0x0000u},
346 // Test the mantissa discarding, the least significant mantissa bit is 0x1p-24 =
347 // 0x0.004p-14.
348 {0x0.064p-14f, 0x0.064p-14, 0x0019u},
349 {0x0.067fecp-14f, 0x0.064p-14, 0x0019u},
350 {0x0.063ffep-14f, 0x0.060p-14, 0x0018u},
351 {0x0.008p-14f, 0x0.008p-14, 0x0002u},
352 {0x0.00bffep-14f, 0x0.008p-14, 0x0002u},
353 {0x0.007ffep-14f, 0x0.004p-14, 0x0001u},
354
355 // Vice versa for negative cases.
356 {highestNegativeNormalF16MinusULP, highestNegativeNormalF16, highestNegativeNormalF16Bits},
357 {highestNegativeNormalF16, highestNegativeNormalF16, highestNegativeNormalF16Bits},
358 {highestNegativeNormalF16PlusULP, lowestNegativeSubnormalF16,
359 lowestNegativeSubnormalF16Bits},
360 {lowestNegativeSubnormalF16MinusULP, lowestNegativeSubnormalF16,
361 lowestNegativeSubnormalF16Bits},
362 {lowestNegativeSubnormalF16, lowestNegativeSubnormalF16, lowestNegativeSubnormalF16Bits},
363 {lowestNegativeSubnormalF16PlusULP, -0x0.ff8p-14, 0x83feu},
364 {highestNegativeSubnormalF16MinusULP, highestNegativeSubnormalF16,
365 highestNegativeSubnormalF16Bits},
366 {highestNegativeSubnormalF16, highestNegativeSubnormalF16, highestNegativeSubnormalF16Bits},
367 {highestNegativeSubnormalF16PlusULP, -0.0, 0x8000u},
368 // Test the mantissa discarding.
369 {-0x0.064p-14f, -0x0.064p-14, 0x8019u},
370 {-0x0.067fecp-14f, -0x0.064p-14, 0x8019u},
371 {-0x0.063ffep-14f, -0x0.060p-14, 0x8018u},
372 {-0x0.008p-14f, -0x0.008p-14, 0x8002u},
373 {-0x0.00bffep-14f, -0x0.008p-14, 0x8002u},
374 {-0x0.007ffep-14f, -0x0.004p-14, 0x8001u},
375 /////////////////////////////////////
376 }));
377
Ben Clayton61537d32022-05-31 13:14:29 +0000378using BinaryCheckedCase = std::tuple<std::optional<AInt>, AInt, AInt>;
379
380#undef OVERFLOW // corecrt_math.h :(
381#define OVERFLOW \
382 {}
383
384using CheckedAddTest = testing::TestWithParam<BinaryCheckedCase>;
385TEST_P(CheckedAddTest, Test) {
386 auto expect = std::get<0>(GetParam());
387 auto a = std::get<1>(GetParam());
388 auto b = std::get<2>(GetParam());
389 EXPECT_EQ(CheckedAdd(a, b), expect) << std::hex << "0x" << a << " * 0x" << b;
390 EXPECT_EQ(CheckedAdd(b, a), expect) << std::hex << "0x" << a << " * 0x" << b;
391}
392INSTANTIATE_TEST_SUITE_P(
393 CheckedAddTest,
394 CheckedAddTest,
395 testing::ValuesIn(std::vector<BinaryCheckedCase>{
396 {AInt(0), AInt(0), AInt(0)},
397 {AInt(1), AInt(1), AInt(0)},
398 {AInt(2), AInt(1), AInt(1)},
399 {AInt(0), AInt(-1), AInt(1)},
400 {AInt(3), AInt(2), AInt(1)},
401 {AInt(-1), AInt(-2), AInt(1)},
402 {AInt(0x300), AInt(0x100), AInt(0x200)},
403 {AInt(0x100), AInt(-0x100), AInt(0x200)},
404 {AInt(AInt::kHighest), AInt(1), AInt(AInt::kHighest - 1)},
405 {AInt(AInt::kLowest), AInt(-1), AInt(AInt::kLowest + 1)},
406 {AInt(AInt::kHighest), AInt(0x7fffffff00000000ll), AInt(0x00000000ffffffffll)},
407 {AInt(AInt::kHighest), AInt(AInt::kHighest), AInt(0)},
408 {AInt(AInt::kLowest), AInt(AInt::kLowest), AInt(0)},
409 {OVERFLOW, AInt(1), AInt(AInt::kHighest)},
410 {OVERFLOW, AInt(-1), AInt(AInt::kLowest)},
411 {OVERFLOW, AInt(2), AInt(AInt::kHighest)},
412 {OVERFLOW, AInt(-2), AInt(AInt::kLowest)},
413 {OVERFLOW, AInt(10000), AInt(AInt::kHighest)},
414 {OVERFLOW, AInt(-10000), AInt(AInt::kLowest)},
415 {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kHighest)},
416 {OVERFLOW, AInt(AInt::kLowest), AInt(AInt::kLowest)},
417 ////////////////////////////////////////////////////////////////////////
418 }));
419
420using CheckedMulTest = testing::TestWithParam<BinaryCheckedCase>;
421TEST_P(CheckedMulTest, Test) {
422 auto expect = std::get<0>(GetParam());
423 auto a = std::get<1>(GetParam());
424 auto b = std::get<2>(GetParam());
425 EXPECT_EQ(CheckedMul(a, b), expect) << std::hex << "0x" << a << " * 0x" << b;
426 EXPECT_EQ(CheckedMul(b, a), expect) << std::hex << "0x" << a << " * 0x" << b;
427}
428INSTANTIATE_TEST_SUITE_P(
429 CheckedMulTest,
430 CheckedMulTest,
431 testing::ValuesIn(std::vector<BinaryCheckedCase>{
432 {AInt(0), AInt(0), AInt(0)},
433 {AInt(0), AInt(1), AInt(0)},
434 {AInt(1), AInt(1), AInt(1)},
435 {AInt(-1), AInt(-1), AInt(1)},
436 {AInt(2), AInt(2), AInt(1)},
437 {AInt(-2), AInt(-2), AInt(1)},
438 {AInt(0x20000), AInt(0x100), AInt(0x200)},
439 {AInt(-0x20000), AInt(-0x100), AInt(0x200)},
440 {AInt(0x4000000000000000ll), AInt(0x80000000ll), AInt(0x80000000ll)},
441 {AInt(0x4000000000000000ll), AInt(-0x80000000ll), AInt(-0x80000000ll)},
442 {AInt(0x1000000000000000ll), AInt(0x40000000ll), AInt(0x40000000ll)},
443 {AInt(-0x1000000000000000ll), AInt(-0x40000000ll), AInt(0x40000000ll)},
444 {AInt(0x100000000000000ll), AInt(0x1000000), AInt(0x100000000ll)},
445 {AInt(0x2000000000000000ll), AInt(0x1000000000000000ll), AInt(2)},
446 {AInt(-0x2000000000000000ll), AInt(0x1000000000000000ll), AInt(-2)},
447 {AInt(-0x2000000000000000ll), AInt(-0x1000000000000000ll), AInt(2)},
448 {AInt(-0x2000000000000000ll), AInt(0x1000000000000000ll), AInt(-2)},
449 {AInt(0x4000000000000000ll), AInt(0x1000000000000000ll), AInt(4)},
450 {AInt(-0x4000000000000000ll), AInt(0x1000000000000000ll), AInt(-4)},
451 {AInt(-0x4000000000000000ll), AInt(-0x1000000000000000ll), AInt(4)},
452 {AInt(-0x4000000000000000ll), AInt(0x1000000000000000ll), AInt(-4)},
453 {AInt(-0x8000000000000000ll), AInt(0x1000000000000000ll), AInt(-8)},
454 {AInt(-0x8000000000000000ll), AInt(-0x1000000000000000ll), AInt(8)},
455 {AInt(0), AInt(AInt::kHighest), AInt(0)},
456 {AInt(0), AInt(AInt::kLowest), AInt(0)},
457 {OVERFLOW, AInt(0x1000000000000000ll), AInt(8)},
458 {OVERFLOW, AInt(-0x1000000000000000ll), AInt(-8)},
459 {OVERFLOW, AInt(0x800000000000000ll), AInt(0x10)},
460 {OVERFLOW, AInt(0x80000000ll), AInt(0x100000000ll)},
461 {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kHighest)},
462 {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kLowest)},
463 ////////////////////////////////////////////////////////////////////////
464 }));
465
466using TernaryCheckedCase = std::tuple<std::optional<AInt>, AInt, AInt, AInt>;
467
468using CheckedMaddTest = testing::TestWithParam<TernaryCheckedCase>;
469TEST_P(CheckedMaddTest, Test) {
470 auto expect = std::get<0>(GetParam());
471 auto a = std::get<1>(GetParam());
472 auto b = std::get<2>(GetParam());
473 auto c = std::get<3>(GetParam());
474 EXPECT_EQ(CheckedMadd(a, b, c), expect)
475 << std::hex << "0x" << a << " * 0x" << b << " + 0x" << c;
476 EXPECT_EQ(CheckedMadd(b, a, c), expect)
477 << std::hex << "0x" << a << " * 0x" << b << " + 0x" << c;
478}
479INSTANTIATE_TEST_SUITE_P(
480 CheckedMaddTest,
481 CheckedMaddTest,
482 testing::ValuesIn(std::vector<TernaryCheckedCase>{
483 {AInt(0), AInt(0), AInt(0), AInt(0)},
484 {AInt(0), AInt(1), AInt(0), AInt(0)},
485 {AInt(1), AInt(1), AInt(1), AInt(0)},
486 {AInt(2), AInt(1), AInt(1), AInt(1)},
487 {AInt(0), AInt(1), AInt(-1), AInt(1)},
488 {AInt(-1), AInt(1), AInt(-2), AInt(1)},
489 {AInt(-1), AInt(-1), AInt(1), AInt(0)},
490 {AInt(2), AInt(2), AInt(1), AInt(0)},
491 {AInt(-2), AInt(-2), AInt(1), AInt(0)},
492 {AInt(0), AInt(AInt::kHighest), AInt(0), AInt(0)},
493 {AInt(0), AInt(AInt::kLowest), AInt(0), AInt(0)},
494 {AInt(3), AInt(1), AInt(2), AInt(1)},
495 {AInt(0x300), AInt(1), AInt(0x100), AInt(0x200)},
496 {AInt(0x100), AInt(1), AInt(-0x100), AInt(0x200)},
497 {AInt(0x20000), AInt(0x100), AInt(0x200), AInt(0)},
498 {AInt(-0x20000), AInt(-0x100), AInt(0x200), AInt(0)},
499 {AInt(0x4000000000000000ll), AInt(0x80000000ll), AInt(0x80000000ll), AInt(0)},
500 {AInt(0x4000000000000000ll), AInt(-0x80000000ll), AInt(-0x80000000ll), AInt(0)},
501 {AInt(0x1000000000000000ll), AInt(0x40000000ll), AInt(0x40000000ll), AInt(0)},
502 {AInt(-0x1000000000000000ll), AInt(-0x40000000ll), AInt(0x40000000ll), AInt(0)},
503 {AInt(0x100000000000000ll), AInt(0x1000000), AInt(0x100000000ll), AInt(0)},
504 {AInt(0x2000000000000000ll), AInt(0x1000000000000000ll), AInt(2), AInt(0)},
505 {AInt(-0x2000000000000000ll), AInt(0x1000000000000000ll), AInt(-2), AInt(0)},
506 {AInt(-0x2000000000000000ll), AInt(-0x1000000000000000ll), AInt(2), AInt(0)},
507 {AInt(-0x2000000000000000ll), AInt(0x1000000000000000ll), AInt(-2), AInt(0)},
508 {AInt(0x4000000000000000ll), AInt(0x1000000000000000ll), AInt(4), AInt(0)},
509 {AInt(-0x4000000000000000ll), AInt(0x1000000000000000ll), AInt(-4), AInt(0)},
510 {AInt(-0x4000000000000000ll), AInt(-0x1000000000000000ll), AInt(4), AInt(0)},
511 {AInt(-0x4000000000000000ll), AInt(0x1000000000000000ll), AInt(-4), AInt(0)},
512 {AInt(-0x8000000000000000ll), AInt(0x1000000000000000ll), AInt(-8), AInt(0)},
513 {AInt(-0x8000000000000000ll), AInt(-0x1000000000000000ll), AInt(8), AInt(0)},
514 {AInt(AInt::kHighest), AInt(1), AInt(1), AInt(AInt::kHighest - 1)},
515 {AInt(AInt::kLowest), AInt(1), AInt(-1), AInt(AInt::kLowest + 1)},
516 {AInt(AInt::kHighest), AInt(1), AInt(0x7fffffff00000000ll), AInt(0x00000000ffffffffll)},
517 {AInt(AInt::kHighest), AInt(1), AInt(AInt::kHighest), AInt(0)},
518 {AInt(AInt::kLowest), AInt(1), AInt(AInt::kLowest), AInt(0)},
519 {OVERFLOW, AInt(0x1000000000000000ll), AInt(8), AInt(0)},
520 {OVERFLOW, AInt(-0x1000000000000000ll), AInt(-8), AInt(0)},
521 {OVERFLOW, AInt(0x800000000000000ll), AInt(0x10), AInt(0)},
522 {OVERFLOW, AInt(0x80000000ll), AInt(0x100000000ll), AInt(0)},
523 {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kHighest), AInt(0)},
524 {OVERFLOW, AInt(AInt::kHighest), AInt(AInt::kLowest), AInt(0)},
525 {OVERFLOW, AInt(1), AInt(1), AInt(AInt::kHighest)},
526 {OVERFLOW, AInt(1), AInt(-1), AInt(AInt::kLowest)},
527 {OVERFLOW, AInt(1), AInt(2), AInt(AInt::kHighest)},
528 {OVERFLOW, AInt(1), AInt(-2), AInt(AInt::kLowest)},
529 {OVERFLOW, AInt(1), AInt(10000), AInt(AInt::kHighest)},
530 {OVERFLOW, AInt(1), AInt(-10000), AInt(AInt::kLowest)},
531 {OVERFLOW, AInt(1), AInt(AInt::kHighest), AInt(AInt::kHighest)},
532 {OVERFLOW, AInt(1), AInt(AInt::kLowest), AInt(AInt::kLowest)},
533 {OVERFLOW, AInt(1), AInt(AInt::kHighest), AInt(1)},
534 {OVERFLOW, AInt(1), AInt(AInt::kLowest), AInt(-1)},
535 }));
536
Ben Clayton572eaf22022-05-27 20:22:26 +0000537TINT_END_DISABLE_WARNING(CONSTANT_OVERFLOW);
538
Ben Claytonc2eccfc2022-05-25 15:04:24 +0000539} // namespace
540} // namespace tint