• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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