1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #include "gtest/gtest.h"
18
19 #include <cmath>
20 #include <cstdint>
21
22 #include "utility.h"
23
24 namespace {
25
TEST(Arm64InsnTest,AddFp32PreciseNaN)26 TEST(Arm64InsnTest, AddFp32PreciseNaN) {
27 // Verify that FADD canonicalizes a qNaN to the default NaN.
28 constexpr auto AsmFadd = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fadd %s0, %s1, %s2");
29 ASSERT_EQ(AsmFadd(kQuietNaN32AsInteger, kOneF32AsInteger, kFpcrDnBit), kDefaultNaN32AsInteger);
30 }
31
TEST(Arm64InsnTest,AddFp64PreciseNaN)32 TEST(Arm64InsnTest, AddFp64PreciseNaN) {
33 // Verify that FADD canonicalizes a qNaN to the default NaN.
34 constexpr auto AsmFadd = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fadd %d0, %d1, %d2");
35 ASSERT_EQ(AsmFadd(kQuietNaN64AsInteger, kOneF64AsInteger, kFpcrDnBit), kDefaultNaN64AsInteger);
36 }
37
TEST(Arm64InsnTest,SubFp32PreciseNaN)38 TEST(Arm64InsnTest, SubFp32PreciseNaN) {
39 // Verify that FSUB canonicalizes a qNaN to the default NaN.
40 constexpr auto AsmFsub = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fsub %s0, %s1, %s2");
41 ASSERT_EQ(AsmFsub(kQuietNaN32AsInteger, kOneF32AsInteger, kFpcrDnBit), kDefaultNaN32AsInteger);
42 }
43
TEST(Arm64InsnTest,SubFp64PreciseNaN)44 TEST(Arm64InsnTest, SubFp64PreciseNaN) {
45 // Verify that FSUB canonicalizes a qNaN to the default NaN.
46 constexpr auto AsmFsub = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fsub %d0, %d1, %d2");
47 ASSERT_EQ(AsmFsub(kQuietNaN64AsInteger, kOneF64AsInteger, kFpcrDnBit), kDefaultNaN64AsInteger);
48 }
49
TEST(Arm64InsnTest,MulFp32PreciseNaN)50 TEST(Arm64InsnTest, MulFp32PreciseNaN) {
51 // Verify that FMUL canonicalizes a qNaN to the default NaN.
52 constexpr auto AsmFmul = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fmul %s0, %s1, %s2");
53 ASSERT_EQ(AsmFmul(kQuietNaN32AsInteger, kOneF32AsInteger, kFpcrDnBit), kDefaultNaN32AsInteger);
54 }
55
TEST(Arm64InsnTest,MulFp64PreciseNaN)56 TEST(Arm64InsnTest, MulFp64PreciseNaN) {
57 // Verify that FMUL canonicalizes a qNaN to the default NaN.
58 constexpr auto AsmFmul = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fmul %d0, %d1, %d2");
59 ASSERT_EQ(AsmFmul(kQuietNaN64AsInteger, kOneF64AsInteger, kFpcrDnBit), kDefaultNaN64AsInteger);
60 }
61
TEST(Arm64InsnTest,DivFp32PreciseNaN)62 TEST(Arm64InsnTest, DivFp32PreciseNaN) {
63 constexpr auto AsmFdiv = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fdiv %s0, %s1, %s2");
64
65 // Verify that FDIV canonicalizes a qNaN to the default NaN.
66 __uint128_t arg1 = kDefaultNaN32AsInteger | (1U << 31); // A qNaN
67 __uint128_t arg2 = bit_cast<uint32_t>(1.0f);
68 ASSERT_EQ(AsmFdiv(arg1, arg2, kFpcrDnBit), kDefaultNaN32AsInteger);
69 }
70
TEST(Arm64InsnTest,DivFp64PreciseNaN)71 TEST(Arm64InsnTest, DivFp64PreciseNaN) {
72 constexpr auto AsmFdiv = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fdiv %d0, %d1, %d2");
73
74 // Verify that FDIV canonicalizes a qNaN to the default NaN.
75 __uint128_t arg1 = kDefaultNaN64AsInteger | (1ULL << 63); // A qNaN
76 __uint128_t arg2 = bit_cast<uint64_t>(1.0);
77 ASSERT_EQ(AsmFdiv(arg1, arg2, kFpcrDnBit), kDefaultNaN64AsInteger);
78 }
79
TEST(Arm64InsnTest,DivFp64x2PreciseNaN)80 TEST(Arm64InsnTest, DivFp64x2PreciseNaN) {
81 constexpr auto AsmFdiv = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fdiv %0.2d, %1.2d, %2.2d");
82
83 // Verify that FDIV canonicalizes a qNaN to the default NaN.
84 __uint128_t arg1 = MakeUInt128(bit_cast<uint64_t>(2.0), kDefaultNaN64AsInteger | (1ULL << 63));
85 __uint128_t arg2 = MakeF64x2(1.0, 1.0);
86 __uint128_t res = AsmFdiv(arg1, arg2, kFpcrDnBit);
87 ASSERT_EQ(res, MakeUInt128(bit_cast<uint64_t>(2.0), kDefaultNaN64AsInteger));
88 }
89
TEST(Arm64InsnTest,MaxFp32PreciseNaN)90 TEST(Arm64InsnTest, MaxFp32PreciseNaN) {
91 constexpr auto AsmFmax = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmax %s0, %s1, %s2");
92 uint32_t fp_arg_two = bit_cast<uint32_t>(2.0f);
93 uint32_t fp_arg_minus_two = bit_cast<uint32_t>(-2.0f);
94
95 ASSERT_EQ(AsmFmax(fp_arg_two, kQuietNaN32AsInteger), MakeU32x4(kQuietNaN32AsInteger, 0, 0, 0));
96 ASSERT_EQ(AsmFmax(fp_arg_minus_two, kQuietNaN32AsInteger),
97 MakeU32x4(kQuietNaN32AsInteger, 0, 0, 0));
98 ASSERT_EQ(AsmFmax(kQuietNaN32AsInteger, fp_arg_two), MakeU32x4(kQuietNaN32AsInteger, 0, 0, 0));
99 ASSERT_EQ(AsmFmax(kQuietNaN32AsInteger, fp_arg_minus_two),
100 MakeU32x4(kQuietNaN32AsInteger, 0, 0, 0));
101 ASSERT_EQ(AsmFmax(kSignalingNaN32AsInteger_1, fp_arg_two),
102 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
103 ASSERT_EQ(AsmFmax(kSignalingNaN32AsInteger_1, fp_arg_minus_two),
104 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
105 ASSERT_EQ(AsmFmax(kQuietNaN32AsInteger, kSignalingNaN32AsInteger_1),
106 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
107 }
108
TEST(Arm64InsnTest,MaxFp64PreciseNaN)109 TEST(Arm64InsnTest, MaxFp64PreciseNaN) {
110 constexpr auto AsmFmax = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmax %d0, %d1, %d2");
111 uint64_t fp_arg_two = bit_cast<uint64_t>(2.0);
112 uint64_t fp_arg_minus_two = bit_cast<uint64_t>(-2.0);
113
114 ASSERT_EQ(AsmFmax(fp_arg_two, kQuietNaN64AsInteger), MakeUInt128(kQuietNaN64AsInteger, 0U));
115 ASSERT_EQ(AsmFmax(fp_arg_minus_two, kQuietNaN64AsInteger), MakeUInt128(kQuietNaN64AsInteger, 0));
116 ASSERT_EQ(AsmFmax(kQuietNaN64AsInteger, fp_arg_two), MakeUInt128(kQuietNaN64AsInteger, 0));
117 ASSERT_EQ(AsmFmax(kQuietNaN64AsInteger, fp_arg_minus_two), MakeUInt128(kQuietNaN64AsInteger, 0));
118 ASSERT_EQ(AsmFmax(kSignalingNaN64AsInteger_1, fp_arg_two),
119 MakeUInt128(kQuietNaN64AsInteger_1, 0));
120 ASSERT_EQ(AsmFmax(kSignalingNaN64AsInteger_1, fp_arg_minus_two),
121 MakeUInt128(kQuietNaN64AsInteger_1, 0));
122 ASSERT_EQ(AsmFmax(kQuietNaN64AsInteger, kSignalingNaN64AsInteger_1),
123 MakeUInt128(kQuietNaN64AsInteger_1, 0));
124 }
125
TEST(Arm64InsnTest,MaxNumberFp32PreciseNaN)126 TEST(Arm64InsnTest, MaxNumberFp32PreciseNaN) {
127 constexpr auto AsmFmaxnm = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmaxnm %s0, %s1, %s2");
128 uint32_t fp_arg_two = bit_cast<uint32_t>(2.0f);
129 uint64_t fp_arg_minus_two = bit_cast<uint64_t>(-2.0);
130
131 ASSERT_EQ(AsmFmaxnm(kSignalingNaN32AsInteger_1, fp_arg_two),
132 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
133 ASSERT_EQ(AsmFmaxnm(fp_arg_two, kSignalingNaN32AsInteger_1),
134 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
135 ASSERT_EQ(AsmFmaxnm(kSignalingNaN32AsInteger_1, fp_arg_minus_two),
136 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
137 ASSERT_EQ(AsmFmaxnm(kQuietNaN32AsInteger, kSignalingNaN32AsInteger_1),
138 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
139 }
140
TEST(Arm64InsnTest,MaxNumberFp64PreciseNaN)141 TEST(Arm64InsnTest, MaxNumberFp64PreciseNaN) {
142 constexpr auto AsmFmaxnm = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmaxnm %d0, %d1, %d2");
143 uint64_t fp_arg_two = bit_cast<uint64_t>(2.0);
144 uint64_t fp_arg_minus_two = bit_cast<uint64_t>(-2.0);
145
146 ASSERT_EQ(AsmFmaxnm(kSignalingNaN64AsInteger_1, fp_arg_two),
147 MakeUInt128(kQuietNaN64AsInteger_1, 0));
148 ASSERT_EQ(AsmFmaxnm(fp_arg_two, kSignalingNaN64AsInteger_1),
149 MakeUInt128(kQuietNaN64AsInteger_1, 0));
150 ASSERT_EQ(AsmFmaxnm(kSignalingNaN64AsInteger_1, fp_arg_minus_two),
151 MakeUInt128(kQuietNaN64AsInteger_1, 0));
152 ASSERT_EQ(AsmFmaxnm(kQuietNaN64AsInteger, kSignalingNaN64AsInteger_1),
153 MakeUInt128(kQuietNaN64AsInteger_1, 0));
154 }
155
TEST(Arm64InsnTest,MinFp32PreciseNaN)156 TEST(Arm64InsnTest, MinFp32PreciseNaN) {
157 constexpr auto AsmFmin = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmin %s0, %s1, %s2");
158 uint32_t fp_arg_two = bit_cast<uint32_t>(2.0f);
159 uint32_t fp_arg_minus_two = bit_cast<uint32_t>(-2.0f);
160
161 ASSERT_EQ(AsmFmin(fp_arg_two, kQuietNaN32AsInteger), MakeU32x4(kQuietNaN32AsInteger, 0, 0, 0));
162 ASSERT_EQ(AsmFmin(fp_arg_minus_two, kQuietNaN32AsInteger),
163 MakeU32x4(kQuietNaN32AsInteger, 0, 0, 0));
164 ASSERT_EQ(AsmFmin(kQuietNaN32AsInteger, fp_arg_two), MakeU32x4(kQuietNaN32AsInteger, 0, 0, 0));
165 ASSERT_EQ(AsmFmin(kQuietNaN32AsInteger, fp_arg_minus_two),
166 MakeU32x4(kQuietNaN32AsInteger, 0, 0, 0));
167 ASSERT_EQ(AsmFmin(kSignalingNaN32AsInteger_1, fp_arg_two),
168 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
169 ASSERT_EQ(AsmFmin(kSignalingNaN32AsInteger_1, fp_arg_minus_two),
170 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
171 ASSERT_EQ(AsmFmin(kQuietNaN32AsInteger, kSignalingNaN32AsInteger_1),
172 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
173 }
174
TEST(Arm64InsnTest,MinFp64PreciseNaN)175 TEST(Arm64InsnTest, MinFp64PreciseNaN) {
176 constexpr auto AsmFmin = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmin %d0, %d1, %d2");
177 uint64_t fp_arg_two = bit_cast<uint64_t>(2.0);
178 uint64_t fp_arg_minus_two = bit_cast<uint64_t>(-2.0);
179
180 ASSERT_EQ(AsmFmin(fp_arg_two, kQuietNaN64AsInteger), MakeUInt128(kQuietNaN64AsInteger, 0U));
181 ASSERT_EQ(AsmFmin(fp_arg_minus_two, kQuietNaN64AsInteger), MakeUInt128(kQuietNaN64AsInteger, 0));
182 ASSERT_EQ(AsmFmin(kQuietNaN64AsInteger, fp_arg_two), MakeUInt128(kQuietNaN64AsInteger, 0));
183 ASSERT_EQ(AsmFmin(kQuietNaN64AsInteger, fp_arg_minus_two), MakeUInt128(kQuietNaN64AsInteger, 0));
184 ASSERT_EQ(AsmFmin(kSignalingNaN64AsInteger_1, fp_arg_two),
185 MakeUInt128(kQuietNaN64AsInteger_1, 0));
186 ASSERT_EQ(AsmFmin(kSignalingNaN64AsInteger_1, fp_arg_minus_two),
187 MakeUInt128(kQuietNaN64AsInteger_1, 0));
188 ASSERT_EQ(AsmFmin(kQuietNaN64AsInteger, kSignalingNaN64AsInteger_1),
189 MakeUInt128(kQuietNaN64AsInteger_1, 0));
190 }
191
TEST(Arm64InsnTest,MinNumberFp32PreciseNaN)192 TEST(Arm64InsnTest, MinNumberFp32PreciseNaN) {
193 constexpr auto AsmFminnm = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fminnm %s0, %s1, %s2");
194 uint32_t fp_arg_two = bit_cast<uint32_t>(2.0f);
195 uint32_t fp_arg_minus_two = bit_cast<uint32_t>(-2.0f);
196
197 ASSERT_EQ(AsmFminnm(kSignalingNaN32AsInteger_1, fp_arg_two),
198 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
199 ASSERT_EQ(AsmFminnm(fp_arg_two, kSignalingNaN32AsInteger_1),
200 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
201 ASSERT_EQ(AsmFminnm(kSignalingNaN32AsInteger_1, fp_arg_minus_two),
202 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
203 ASSERT_EQ(AsmFminnm(kQuietNaN32AsInteger, kSignalingNaN32AsInteger_1),
204 MakeU32x4(kQuietNaN32AsInteger_1, 0, 0, 0));
205 }
206
TEST(Arm64InsnTest,MinNumberFp64PreciseNaN)207 TEST(Arm64InsnTest, MinNumberFp64PreciseNaN) {
208 constexpr auto AsmFminnm = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fminnm %d0, %d1, %d2");
209 uint64_t fp_arg_two = bit_cast<uint64_t>(2.0);
210 uint64_t fp_arg_minus_two = bit_cast<uint64_t>(-2.0);
211
212 ASSERT_EQ(AsmFminnm(kSignalingNaN64AsInteger_1, fp_arg_two),
213 MakeUInt128(kQuietNaN64AsInteger_1, 0));
214 ASSERT_EQ(AsmFminnm(fp_arg_two, kSignalingNaN64AsInteger_1),
215 MakeUInt128(kQuietNaN64AsInteger_1, 0));
216 ASSERT_EQ(AsmFminnm(kSignalingNaN64AsInteger_1, fp_arg_minus_two),
217 MakeUInt128(kQuietNaN64AsInteger_1, 0));
218 ASSERT_EQ(AsmFminnm(kQuietNaN64AsInteger, kSignalingNaN64AsInteger_1),
219 MakeUInt128(kQuietNaN64AsInteger_1, 0));
220 }
221
TEST(Arm64InsnTest,MaxNumberF32x4PreciseNaN)222 TEST(Arm64InsnTest, MaxNumberF32x4PreciseNaN) {
223 constexpr auto AsmFmaxnm = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmaxnm %0.4s, %1.4s, %2.4s");
224 __uint128_t arg1 = MakeU32x4(bit_cast<uint32_t>(1.0f),
225 bit_cast<uint32_t>(-1.0f),
226 kSignalingNaN32AsInteger_1,
227 kQuietNaN32AsInteger);
228 __uint128_t arg2 = MakeU32x4(kSignalingNaN32AsInteger_1,
229 kQuietNaN32AsInteger,
230 bit_cast<uint32_t>(1.0f),
231 bit_cast<uint32_t>(-1.0f));
232 ASSERT_EQ(AsmFmaxnm(arg1, arg2),
233 MakeU32x4(kQuietNaN32AsInteger_1,
234 bit_cast<uint32_t>(-1.0f),
235 kQuietNaN32AsInteger_1,
236 bit_cast<uint32_t>(-1.0f)));
237 }
238
TEST(Arm64InsnTest,MaxNumberF64x2PreciseNaN)239 TEST(Arm64InsnTest, MaxNumberF64x2PreciseNaN) {
240 constexpr auto AsmFmaxnm = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmaxnm %0.2d, %1.2d, %2.2d");
241 __uint128_t arg1 = MakeUInt128(bit_cast<uint64_t>(1.0), kSignalingNaN64AsInteger_1);
242 __uint128_t arg2 = MakeUInt128(kSignalingNaN64AsInteger_1, bit_cast<uint64_t>(-1.0));
243 ASSERT_EQ(AsmFmaxnm(arg1, arg2), MakeUInt128(kQuietNaN64AsInteger_1, kQuietNaN64AsInteger_1));
244 }
245
TEST(Arm64InsnTest,MinNumberF32x4PreciseNaN)246 TEST(Arm64InsnTest, MinNumberF32x4PreciseNaN) {
247 constexpr auto AsmFminnm = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fminnm %0.4s, %1.4s, %2.4s");
248 __uint128_t arg1 = MakeU32x4(bit_cast<uint32_t>(1.0f),
249 bit_cast<uint32_t>(-1.0f),
250 kSignalingNaN32AsInteger_1,
251 kQuietNaN32AsInteger);
252 __uint128_t arg2 = MakeU32x4(kSignalingNaN32AsInteger_1,
253 kQuietNaN32AsInteger,
254 bit_cast<uint32_t>(1.0f),
255 bit_cast<uint32_t>(-1.0f));
256 ASSERT_EQ(AsmFminnm(arg1, arg2),
257 MakeU32x4(kQuietNaN32AsInteger_1,
258 bit_cast<uint32_t>(-1.0f),
259 kQuietNaN32AsInteger_1,
260 bit_cast<uint32_t>(-1.0f)));
261 }
262
TEST(Arm64InsnTest,MinNumberF64x2PreciseNaN)263 TEST(Arm64InsnTest, MinNumberF64x2PreciseNaN) {
264 constexpr auto AsmFminnm = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fminnm %0.2d, %1.2d, %2.2d");
265 __uint128_t arg1 = MakeUInt128(bit_cast<uint64_t>(1.0), kSignalingNaN64AsInteger_1);
266 __uint128_t arg2 = MakeUInt128(kSignalingNaN64AsInteger_1, bit_cast<uint64_t>(-1.0));
267 ASSERT_EQ(AsmFminnm(arg1, arg2), MakeUInt128(kQuietNaN64AsInteger_1, kQuietNaN64AsInteger_1));
268 }
269
TEST(Arm64InsnTest,MaxPairwiseNumberF32ScalarPreciseNaN)270 TEST(Arm64InsnTest, MaxPairwiseNumberF32ScalarPreciseNaN) {
271 constexpr auto AsmFmaxnmp = ASM_INSN_WRAP_FUNC_W_RES_W_ARG("fmaxnmp %s0, %1.2s");
272 __uint128_t arg = MakeF32x4(bit_cast<float>(kSignalingNaN32AsInteger_1), 2.0f, 7.0f, -0.0f);
273 ASSERT_EQ(AsmFmaxnmp(arg), kQuietNaN32AsInteger_1);
274 }
275
TEST(Arm64InsnTest,MaxPairwiseNumberF32x4PreciseNaN)276 TEST(Arm64InsnTest, MaxPairwiseNumberF32x4PreciseNaN) {
277 constexpr auto AsmFmaxnmp = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fmaxnmp %0.4s, %1.4s, %2.4s");
278 __uint128_t arg1 = MakeF32x4(bit_cast<float>(kSignalingNaN32AsInteger_1),
279 2.0f,
280 7.0f,
281 bit_cast<float>(kSignalingNaN32AsInteger_1));
282 __uint128_t arg2 = MakeF32x4(6.0f, 1.0f, -8.0f, 5.0f);
283 ASSERT_EQ(AsmFmaxnmp(arg1, arg2),
284 MakeF32x4(bit_cast<float>(kQuietNaN32AsInteger_1),
285 bit_cast<float>(kQuietNaN32AsInteger_1),
286 6.0f,
287 5.0f));
288 }
289
TEST(Arm64InsnTest,MinPairwiseNumberF32ScalarPreciseNaN)290 TEST(Arm64InsnTest, MinPairwiseNumberF32ScalarPreciseNaN) {
291 constexpr auto AsmFminnmp = ASM_INSN_WRAP_FUNC_W_RES_W_ARG("fminnmp %s0, %1.2s");
292 __uint128_t arg = MakeF32x4(bit_cast<float>(kSignalingNaN32AsInteger_1), 2.0f, 7.0f, -0.0f);
293 ASSERT_EQ(AsmFminnmp(arg), kQuietNaN32AsInteger_1);
294 }
295
TEST(Arm64InsnTest,MinPairwiseNumberF32x4PreciseNaN)296 TEST(Arm64InsnTest, MinPairwiseNumberF32x4PreciseNaN) {
297 constexpr auto AsmFminnmp = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fminnmp %0.4s, %1.4s, %2.4s");
298 __uint128_t arg1 = MakeF32x4(bit_cast<float>(kSignalingNaN32AsInteger_1),
299 2.0f,
300 7.0f,
301 bit_cast<float>(kSignalingNaN32AsInteger_1));
302 __uint128_t arg2 = MakeF32x4(6.0f, 1.0f, -8.0f, 5.0f);
303 ASSERT_EQ(AsmFminnmp(arg1, arg2),
304 MakeF32x4(bit_cast<float>(kQuietNaN32AsInteger_1),
305 bit_cast<float>(kQuietNaN32AsInteger_1),
306 1.0f,
307 -8.0f));
308 }
309
TEST(Arm64InsnTest,MaxNumberAcrossF32x4PreciseNaN)310 TEST(Arm64InsnTest, MaxNumberAcrossF32x4PreciseNaN) {
311 constexpr auto AsmFmaxnmv = ASM_INSN_WRAP_FUNC_W_RES_W_ARG("fmaxnmv %s0, %1.4s");
312 __uint128_t arg = MakeF32x4(0.0f, 2.0f, 3.0f, bit_cast<float>(kSignalingNaN32AsInteger_1));
313 ASSERT_EQ(AsmFmaxnmv(arg), bit_cast<uint32_t>(2.0f));
314 }
315
TEST(Arm64InsnTest,MinNumberAcrossF32x4PreciseNaN)316 TEST(Arm64InsnTest, MinNumberAcrossF32x4PreciseNaN) {
317 constexpr auto AsmFminnmv = ASM_INSN_WRAP_FUNC_W_RES_W_ARG("fminnmv %s0, %1.4s");
318 __uint128_t arg = MakeF32x4(0.0f, 2.0f, 3.0f, bit_cast<float>(kSignalingNaN32AsInteger_1));
319 ASSERT_EQ(AsmFminnmv(arg), bit_cast<uint32_t>(0.0f));
320 }
321
TEST(Arm64InsnTest,AbdF64PreciseNaN)322 TEST(Arm64InsnTest, AbdF64PreciseNaN) {
323 constexpr auto AsmFabd = ASM_INSN_WRAP_FUNC_W_RES_WW_ARG("fabd %d0, %d1, %d2");
324 // FABD computes the difference while propagating NaNs and then drops the sign
325 // bit. This means that if the difference is a "negative" NaN, then FABD
326 // produces the positive one. That is, a NaN input doesn't necessarily
327 // propagate to the result as is even with the Default NaN mode turned off.
328 uint64_t arg1 = kDefaultNaN64AsInteger | (1ULL << 63); // A "negative" qNaN
329 uint64_t arg2 = bit_cast<uint32_t>(1.0f);
330 ASSERT_EQ(AsmFabd(arg1, arg2), kDefaultNaN64AsInteger);
331 }
332
TEST(Arm64InsnTest,DivFp32FlushToZero)333 TEST(Arm64InsnTest, DivFp32FlushToZero) {
334 constexpr auto AsmFdiv = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fdiv %s0, %s1, %s2");
335
336 // Verify that 0.0 / denormal yields a NaN.
337 __uint128_t arg1 = bit_cast<uint32_t>(0.0f);
338 __uint128_t arg2 = 0x80008000ULL; // denormal
339 __uint128_t res = AsmFdiv(arg1, arg2, kFpcrFzBit);
340 ASSERT_TRUE(isnan(bit_cast<float>(static_cast<uint32_t>(res))));
341 ASSERT_EQ(res >> 32, 0ULL);
342 }
343
TEST(Arm64InsnTest,DivFp64FlushToZero)344 TEST(Arm64InsnTest, DivFp64FlushToZero) {
345 constexpr auto AsmFdiv = ASM_INSN_WRAP_FUNC_W_RES_WWC_ARG("fdiv %d0, %d1, %d2");
346
347 // Verify that 0.0 / denormal yields a NaN.
348 __uint128_t arg1 = bit_cast<uint64_t>(0.0);
349 __uint128_t arg2 = 0x8000000080000000ULL; // denormal
350 __uint128_t res = AsmFdiv(arg1, arg2, kFpcrFzBit);
351 ASSERT_TRUE(isnan(bit_cast<double>(static_cast<uint64_t>(res))));
352 ASSERT_EQ(res >> 64, 0ULL);
353 }
354
TEST(Arm64InsnTest,AddFp64FpStatusIdcWhenFzOn)355 TEST(Arm64InsnTest, AddFp64FpStatusIdcWhenFzOn) {
356 __uint128_t arg1 = 0x8000000080000000ULL; // Denormal
357 __uint128_t arg2 = bit_cast<uint64_t>(0.0);
358
359 uint64_t fpcr = kFpcrFzBit;
360 uint64_t fpsr;
361 __uint128_t res;
362 asm("msr fpsr, xzr\n\t"
363 "msr fpcr, %x2\n\t"
364 "fadd %d0, %d3, %d4\n\t"
365 "mrs %1, fpsr"
366 : "=w"(res), "=r"(fpsr)
367 : "r"(fpcr), "w"(arg1), "w"(arg2));
368 ASSERT_EQ(fpsr, kFpsrIdcBit);
369 }
370
TEST(Arm64InsnTest,AddFp64FpStatusIoc)371 TEST(Arm64InsnTest, AddFp64FpStatusIoc) {
372 constexpr auto AsmFadd = ASM_INSN_WRAP_FUNC_WQ_RES_WW_ARG("fadd %d0, %d2, %d3");
373
374 uint64_t fp_arg1 = 0x7ff4000000000000ULL; // Nan
375 uint64_t fp_arg2 = kOneF64AsInteger;
376 auto [res, fpsr] = AsmFadd(fp_arg1, fp_arg2);
377 ASSERT_EQ(res, MakeUInt128(0x7ffc000000000000ULL, 0x0000000000000000ULL));
378 ASSERT_EQ(fpsr, kFpsrIocBit);
379 }
380
TEST(Arm64InsnTest,AddFp64FpStatusIxc)381 TEST(Arm64InsnTest, AddFp64FpStatusIxc) {
382 constexpr auto AsmFadd = ASM_INSN_WRAP_FUNC_WQ_RES_WW_ARG("fadd %s0, %s2, %s3");
383
384 uint32_t fp_arg1 = 0x97876b0f; // 8.7511959e-25
385 uint32_t fp_arg2 = 0x904e5f47; // -4.0699736e-29
386
387 auto [res, fpsr] = AsmFadd(fp_arg1, fp_arg2);
388 ASSERT_EQ(fpsr, kFpsrIxcBit);
389 ASSERT_EQ(res, MakeUInt128(0x0000000097876cacULL, 0x0000000000000000ULL));
390 }
391
TEST(Arm64InsnTest,AddFp64FpStatusDzc)392 TEST(Arm64InsnTest, AddFp64FpStatusDzc) {
393 constexpr auto AsmFDiv = ASM_INSN_WRAP_FUNC_WQ_RES_WW0_ARG("fdiv %d0, %d2, %d3");
394 auto num = MakeUInt128(bit_cast<uint64_t>(2.0), 0ULL);
395 auto den = MakeUInt128(bit_cast<uint64_t>(0.0), 0ULL);
396
397 auto [res, fpsr] = AsmFDiv(num, den, 0);
398 ASSERT_EQ(fpsr, kFpsrDzcBit);
399 }
400
TEST(Arm64InsnTest,AddFp64FpStatusOfe)401 TEST(Arm64InsnTest, AddFp64FpStatusOfe) {
402 __uint128_t res;
403 uint64_t fpsr;
404 asm("msr fpsr, xzr\n\t"
405 "msr fpcr, xzr\n\t"
406 "fmul %d0, %d2, %d2\n\t"
407 "mrs %1, fpsr"
408 : "=w"(res), "=r"(fpsr)
409 : "w"(std::numeric_limits<double>::max()));
410 ASSERT_EQ(fpsr, kFpsrOfcBit | kFpsrIxcBit) << "OFE should be set upon overflow (as well as IXC).";
411 }
412
TEST(Arm64InsnTest,AddFp64FpStatusUfe)413 TEST(Arm64InsnTest, AddFp64FpStatusUfe) {
414 __uint128_t res;
415 uint64_t fpsr;
416 asm("msr fpsr, xzr\n\t"
417 "msr fpcr, xzr\n\t"
418 "fdiv %d0, %d2, %d3\n\t"
419 "mrs %1, fpsr"
420 : "=w"(res), "=r"(fpsr)
421 : "w"(std::numeric_limits<double>::min()), "w"(std::numeric_limits<double>::max()));
422 ASSERT_EQ(fpsr, kFpsrUfcBit | kFpsrIxcBit)
423 << "UFE should be set upon underflow (as well as IXC).";
424 }
425
426 } // namespace
427