1/*
2 * Copyright (c) 2016 The University of Virginia
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Alec Roelke
29 */
30
31#include <cstdint>
32#include <limits>
33
34#include "insttest.h"
35#include "rv64f.h"
36
37int main()
38{
39    using namespace std;
40    using namespace insttest;
41
42    // FLAGS
43    expect<uint64_t>(0, []{
44            F::fsflags(0);
45            return F::frflags();
46        }, "clear fsflags");
47
48    // Memory
49    expect<float>(3.14, []{return F::load(3.14);}, "flw");
50    expect<float>(1.816, []{return F::store(1.816);}, "fsw");
51
52    // FMADD.S
53    expect<float>(7.11624, []{return F::fmadd_s(3.14, 1.816, 1.414);},
54            "fmadd.s");
55    expect<bool>(true, []{
56            float fd = F::fmadd_s(numeric_limits<float>::quiet_NaN(), 3.14,
57                    1.816);
58            return F::isquietnan(fd);
59        }, "fmadd.s, quiet NaN");
60    expect<bool>(true, []{
61            float fd = F::fmadd_s(3.14, numeric_limits<float>::signaling_NaN(),
62                    1.816);
63            return F::isquietnan(fd);
64        }, "fmadd.s, signaling NaN");
65    expect<float>(numeric_limits<float>::infinity(),
66            []{return F::fmadd_s(3.14, numeric_limits<float>::infinity(),
67                    1.414);},
68            "fmadd.s, infinity");
69    expect<float>(-numeric_limits<float>::infinity(),
70            []{return F::fmadd_s(3.14, -numeric_limits<float>::infinity(),
71                    1.414);},
72            "fmadd.s, -infinity");
73
74    // FMSUB.S
75    expect<float>(4.28824, []{return F::fmsub_s(3.14, 1.816, 1.414);},
76            "fmsub.s");
77    expect<bool>(true, []{
78            float fd = F::fmsub_s(3.14, numeric_limits<float>::quiet_NaN(),
79                    1.816);
80            return F::isquietnan(fd);
81        }, "fmsub.s, quiet NaN");
82    expect<bool>(true, []{
83            float fd = F::fmsub_s(3.14, 1.816,
84                    numeric_limits<float>::signaling_NaN());
85            return F::isquietnan(fd);
86        }, "fmsub.s, signaling NaN");
87    expect<float>(numeric_limits<float>::infinity(),
88            []{return F::fmsub_s(numeric_limits<float>::infinity(), 1.816,
89                    1.414);},
90            "fmsub.s, infinity");
91    expect<float>(-numeric_limits<float>::infinity(),
92            []{return F::fmsub_s(3.14, -numeric_limits<float>::infinity(),
93                    1.414);},
94            "fmsub.s, -infinity");
95    expect<float>(-numeric_limits<float>::infinity(),
96            []{return F::fmsub_s(3.14, 1.816,
97                    numeric_limits<float>::infinity());},
98            "fmsub.s, subtract infinity");
99
100    // FNMSUB.S
101    expect<float>(-4.28824, []{return F::fnmsub_s(3.14, 1.816, 1.414);},
102            "fnmsub.s");
103    expect<bool>(true, []{
104            float fd = F::fnmsub_s(3.14, 1.816,
105                    numeric_limits<float>::quiet_NaN());
106            return F::isquietnan(fd);
107        }, "fnmsub.s, quiet NaN");
108    expect<bool>(true, []{
109            float fd = F::fnmsub_s(numeric_limits<float>::signaling_NaN(),
110                    1.816, 1.414);
111            return F::isquietnan(fd);
112        }, "fnmsub.s, signaling NaN");
113    expect<float>(-numeric_limits<float>::infinity(),
114            []{return F::fnmsub_s(numeric_limits<float>::infinity(),
115                    1.816, 1.414);},
116            "fnmsub.s, infinity");
117    expect<float>(numeric_limits<float>::infinity(),
118            []{return F::fnmsub_s(3.14, -numeric_limits<float>::infinity(),
119                    1.414);},
120            "fnmsub.s, -infinity");
121    expect<float>(numeric_limits<float>::infinity(),
122            []{return F::fnmsub_s(3.14, 1.816,
123                    numeric_limits<float>::infinity());},
124            "fnmsub.s, subtract infinity");
125
126    // FNMADD.S
127    expect<float>(-7.11624, []{return F::fnmadd_s(3.14, 1.816, 1.414);},
128            "fnmadd.s");
129    expect<bool>(true, []{
130            float fd = F::fnmadd_s(numeric_limits<float>::quiet_NaN(), 3.14,
131                    1.816);
132            return F::isquietnan(fd);
133        }, "fnmadd.s, quiet NaN");
134    expect<bool>(true, []{
135            float fd = F::fnmadd_s(3.14,numeric_limits<float>::signaling_NaN(),
136                    1.816);
137            return F::isquietnan(fd);
138        }, "fnmadd.s, signaling NaN");
139    expect<float>(-numeric_limits<float>::infinity(),
140            []{return F::fnmadd_s(3.14, numeric_limits<float>::infinity(),
141                    1.414);},
142            "fnmadd.s, infinity");
143    expect<float>(numeric_limits<float>::infinity(),
144            []{return F::fnmadd_s(3.14, -numeric_limits<float>::infinity(),
145                    1.414);},
146            "fnmadd.s, -infinity");
147
148    // FADD.S
149    expect<float>(4.554, []{return F::fadd_s(3.14, 1.414);}, "fadd.s");
150    expect<bool>(true, []{
151            float fd = F::fadd_s(numeric_limits<float>::quiet_NaN(), 1.414);
152            return F::isquietnan(fd);
153        }, "fadd.s, quiet NaN");
154    expect<bool>(true, []{
155            float fd = F::fadd_s(3.14, numeric_limits<float>::signaling_NaN());
156            return F::isquietnan(fd);
157        }, "fadd.s, signaling NaN");
158    expect<float>(numeric_limits<float>::infinity(),
159            []{return F::fadd_s(3.14, numeric_limits<float>::infinity());},
160            "fadd.s, infinity");
161    expect<float>(-numeric_limits<float>::infinity(),
162            []{return F::fadd_s(-numeric_limits<float>::infinity(), 1.816);},
163            "fadd.s, -infinity");
164
165    // FSUB.S
166    expect<float>(F::number(0xbfdced92), []{return F::fsub_s(1.414, 3.14);},
167            "fsub.s");
168    expect<bool>(true, []{
169            float fd = F::fsub_s(numeric_limits<float>::quiet_NaN(), 1.414);
170            return F::isquietnan(fd);
171        }, "fsub.s, quiet NaN");
172    expect<bool>(true, []{
173            float fd = F::fsub_s(3.14, numeric_limits<float>::signaling_NaN());
174            return F::isquietnan(fd);
175        }, "fsub.s, signaling NaN");
176    expect<float>(numeric_limits<float>::infinity(),
177            []{return F::fsub_s(numeric_limits<float>::infinity(), 3.14);},
178            "fsub.s, infinity");
179    expect<float>(-numeric_limits<float>::infinity(),
180            []{return F::fsub_s(-numeric_limits<float>::infinity(), 3.14);},
181            "fsub.s, -infinity");
182    expect<float>(-numeric_limits<float>::infinity(),
183            []{return F::fsub_s(1.414, numeric_limits<float>::infinity());},
184            "fsub.s, subtract infinity");
185
186    // FMUL.S
187    expect<float>(F::number(0x4024573b), []{return F::fmul_s(1.816, 1.414);},
188            "fmul.s");
189    expect<bool>(true, []{
190            float fd = F::fmul_s(numeric_limits<float>::quiet_NaN(), 1.414);
191            return F::isquietnan(fd);
192        }, "fmul.s, quiet NaN");
193    expect<bool>(true, []{
194            float fd = F::fmul_s(1.816,
195                    numeric_limits<float>::signaling_NaN());
196            return F::isquietnan(fd);
197        }, "fmul.s, signaling NaN");
198    expect<float>(numeric_limits<float>::infinity(),
199            []{return F::fmul_s(numeric_limits<float>::infinity(), 2.718);},
200            "fmul.s, infinity");
201    expect<float>(-numeric_limits<float>::infinity(),
202            []{return F::fmul_s(2.5966, -numeric_limits<float>::infinity());},
203            "fmul.s, -infinity");
204    expect<bool>(true, []{
205            float fd = F::fmul_s(0.0, numeric_limits<float>::infinity());
206            return F::isquietnan(fd);
207        }, "fmul.s, 0*infinity");
208    expect<float>(numeric_limits<float>::infinity(),
209            []{return F::fmul_s(numeric_limits<float>::max(), 2.0);},
210            "fmul.s, overflow");
211    expect<float>(0.0,
212            []{return F::fmul_s(numeric_limits<float>::min(),
213                    numeric_limits<float>::min());},
214            "fmul.s, underflow");
215
216    // FDIV.S
217    expect<float>(2.5, []{return F::fdiv_s(10.0, 4.0);}, "fdiv.s");
218    expect<bool>(true, []{
219            float fd = F::fdiv_s(numeric_limits<float>::quiet_NaN(), 4.0);
220            return F::isquietnan(fd);
221        }, "fdiv.s, quiet NaN");
222    expect<bool>(true, []{
223            float fd = F::fdiv_s(10.0, numeric_limits<float>::signaling_NaN());
224            return F::isquietnan(fd);
225        }, "fdiv.s, signaling NaN");
226    expect<float>(numeric_limits<float>::infinity(),
227        []{return F::fdiv_s(10.0, 0.0);}, "fdiv.s/0");
228    expect<float>(0.0,
229        []{return F::fdiv_s(10.0, numeric_limits<float>::infinity());},
230        "fdiv.s/infinity");
231    expect<bool>(true, []{
232            float fd = F::fdiv_s(numeric_limits<float>::infinity(),
233                    numeric_limits<float>::infinity());
234            return F::isquietnan(fd);
235            }, "fdiv.s, infinity/infinity");
236    expect<bool>(true, []{
237            float fd = F::fdiv_s(0.0, 0.0);
238            return F::isquietnan(fd);
239        }, "fdiv.s, 0/0");
240    expect<float>(numeric_limits<float>::infinity(),
241        []{return F::fdiv_s(numeric_limits<float>::infinity(), 0.0);},
242        "fdiv.s, infinity/0");
243    expect<float>(0.0,
244        []{return F::fdiv_s(0.0, numeric_limits<float>::infinity());},
245        "fdiv.s, 0/infinity");
246    expect<float>(0.0,
247            []{return F::fdiv_s(numeric_limits<float>::min(),
248                    numeric_limits<float>::max());},
249            "fdiv.s, underflow");
250    expect<float>(numeric_limits<float>::infinity(),
251            []{return F::fdiv_s(numeric_limits<float>::max(),
252                    numeric_limits<float>::min());},
253            "fdiv.s, overflow");
254
255    // FSQRT.S
256    expect<float>(0.3, []{return F::fsqrt_s(0.09);}, "fsqrt.s");
257    expect<bool>(true, []{
258            float fd = F::fsqrt_s(-1.0);
259            return F::isquietnan(fd);
260        }, "fsqrt.s, NaN");
261    expect<bool>(true, []{
262            float fd = F::fsqrt_s(numeric_limits<float>::quiet_NaN());
263            return F::isquietnan(fd);
264        }, "fsqrt.s, quiet NaN");
265    expect<bool>(true, []{
266            float fd = F::fsqrt_s(numeric_limits<float>::signaling_NaN());
267            return F::isquietnan(fd);
268        }, "fsqrt.s, signaling NaN");
269    expect<float>(numeric_limits<float>::infinity(),
270            []{return F::fsqrt_s(numeric_limits<float>::infinity());},
271            "fsqrt.s, infinity");
272
273    // FSGNJ.S
274    expect<float>(1.0, []{return F::fsgnj_s(1.0, 25.0);}, "fsgnj.s, ++");
275    expect<float>(-1.0, []{return F::fsgnj_s(1.0, -25.0);}, "fsgnj.s, +-");
276    expect<float>(1.0, []{return F::fsgnj_s(-1.0, 25.0);}, "fsgnj.s, -+");
277    expect<float>(-1.0, []{return F::fsgnj_s(-1.0, -25.0);}, "fsgnj.s, --");
278    expect<bool>(true, []{
279            float fd = F::fsgnj_s(numeric_limits<float>::quiet_NaN(), -4.0);
280            return F::isquietnan(fd);
281        }, "fsgnj.s, quiet NaN");
282    expect<bool>(true, []{
283            float fd = F::fsgnj_s(numeric_limits<float>::signaling_NaN(),
284                    -4.0);
285            return F::issignalingnan(fd);
286        }, "fsgnj.s, signaling NaN");
287    expect<float>(4.0, []{return F::fsgnj_s(4.0,
288                numeric_limits<float>::quiet_NaN());}, "fsgnj.s, inject NaN");
289    expect<float>(-4.0,
290            []{return F::fsgnj_s(4.0, -numeric_limits<float>::quiet_NaN());},
291            "fsgnj.s, inject -NaN");
292
293    // FSGNJN.S
294    expect<float>(-1.0, []{return F::fsgnjn_s(1.0, 25.0);}, "fsgnjn.s, ++");
295    expect<float>(1.0, []{return F::fsgnjn_s(1.0, -25.0);}, "fsgnjn.s, +-");
296    expect<float>(-1.0, []{return F::fsgnjn_s(-1.0, 25.0);}, "fsgnjn.s, -+");
297    expect<float>(1.0, []{return F::fsgnjn_s(-1.0, -25.0);}, "fsgnjn.s, --");
298    expect<bool>(true, []{
299            float fd = F::fsgnjn_s(numeric_limits<float>::quiet_NaN(), -4.0);
300            return F::isquietnan(fd);
301        }, "fsgnjn.s, quiet NaN");
302    expect<bool>(true, []{
303            float fd = F::fsgnjn_s(numeric_limits<float>::signaling_NaN(),
304                    -4.0);
305            return F::issignalingnan(fd);
306        }, "fsgnjn.s, signaling NaN");
307    expect<float>(-4.0,
308            []{return F::fsgnjn_s(4.0, numeric_limits<float>::quiet_NaN());},
309            "fsgnjn.s, inject NaN");
310    expect<float>(4.0,
311            []{return F::fsgnjn_s(4.0, -numeric_limits<float>::quiet_NaN());},
312            "fsgnjn.s, inject NaN");
313
314    // FSGNJX.S
315    expect<float>(1.0, []{return F::fsgnjx_s(1.0, 25.0);}, "fsgnjx.s, ++");
316    expect<float>(-1.0, []{return F::fsgnjx_s(1.0, -25.0);}, "fsgnjx.s, +-");
317    expect<float>(-1.0, []{return F::fsgnjx_s(-1.0, 25.0);}, "fsgnjx.s, -+");
318    expect<float>(1.0, []{return F::fsgnjx_s(-1.0, -25.0);}, "fsgnjx.s, --");
319    expect<bool>(true, []{
320            float fd = F::fsgnjx_s(numeric_limits<float>::quiet_NaN(), -4.0);
321            return F::isquietnan(fd);
322        }, "fsgnjx.s, quiet NaN");
323    expect<bool>(true, []{
324            float fd = F::fsgnjx_s(numeric_limits<float>::signaling_NaN(),
325                    -4.0);
326            return F::issignalingnan(fd);
327        }, "fsgnjx.s, signaling NaN");
328    expect<float>(4.0,
329            []{return F::fsgnjx_s(4.0, numeric_limits<float>::quiet_NaN());},
330            "fsgnjx.s, inject NaN");
331    expect<float>(-4.0,
332            []{return F::fsgnjx_s(4.0, -numeric_limits<float>::quiet_NaN());},
333            "fsgnjx.s, inject -NaN");
334
335    // FMIN.S
336    expect<float>(2.718, []{return F::fmin_s(3.14, 2.718);}, "fmin.s");
337    expect<float>(-numeric_limits<float>::infinity(),
338            []{return F::fmin_s(-numeric_limits<float>::infinity(),
339                    numeric_limits<float>::min());},
340            "fmin.s, -infinity");
341    expect<float>(numeric_limits<float>::max(),
342            []{return F::fmin_s(numeric_limits<float>::infinity(),
343                    numeric_limits<float>::max());},
344            "fmin.s, infinity");
345    expect<float>(-1.414,
346            []{return F::fmin_s(numeric_limits<float>::quiet_NaN(), -1.414);},
347            "fmin.s, quiet NaN first");
348    expect<float>(2.718,
349            []{return F::fmin_s(2.718, numeric_limits<float>::quiet_NaN());},
350            "fmin.s, quiet NaN second");
351    expect<bool>(true, []{
352            float fd = F::fmin_s(numeric_limits<float>::quiet_NaN(),
353                    numeric_limits<float>::quiet_NaN());
354            return F::isquietnan(fd);
355        }, "fmin.s, quiet NaN both");
356    expect<float>(3.14,
357            []{return F::fmin_s(numeric_limits<float>::signaling_NaN(),
358                    3.14);},
359            "fmin.s, signaling NaN first");
360    expect<float>(1.816,
361            []{return F::fmin_s(1.816,
362                    numeric_limits<float>::signaling_NaN());},
363            "fmin.s, signaling NaN second");
364    expect<bool>(true, []{
365            float fd = F::fmin_s(numeric_limits<float>::signaling_NaN(),
366                    numeric_limits<float>::signaling_NaN());
367            return F::issignalingnan(fd);
368        }, "fmin.s, signaling NaN both");
369
370    // FMAX.S
371    expect<float>(3.14, []{return F::fmax_s(3.14, 2.718);}, "fmax.s");
372    expect<float>(numeric_limits<float>::min(),
373            []{return F::fmax_s(-numeric_limits<float>::infinity(),
374                    numeric_limits<float>::min());},
375            "fmax.s, -infinity");
376    expect<float>(numeric_limits<float>::infinity(),
377            []{return F::fmax_s(numeric_limits<float>::infinity(),
378                    numeric_limits<float>::max());},
379            "fmax.s, infinity");
380    expect<float>(-1.414,
381            []{return F::fmax_s(numeric_limits<float>::quiet_NaN(), -1.414);},
382            "fmax.s, quiet NaN first");
383    expect<float>(2.718,
384            []{return F::fmax_s(2.718, numeric_limits<float>::quiet_NaN());},
385            "fmax.s, quiet NaN second");
386    expect<bool>(true, []{
387            float fd = F::fmax_s(numeric_limits<float>::quiet_NaN(),
388                    numeric_limits<float>::quiet_NaN());
389            return F::isquietnan(fd);
390        }, "fmax.s, quiet NaN both");
391    expect<float>(3.14,
392            []{return F::fmax_s(numeric_limits<float>::signaling_NaN(),
393                    3.14);},
394            "fmax.s, signaling NaN first");
395    expect<float>(1.816, []{return F::fmax_s(1.816,
396                numeric_limits<float>::signaling_NaN());},
397            "fmax.s, signaling NaN second");
398    expect<bool>(true, []{
399            float fd = F::fmax_s(numeric_limits<float>::signaling_NaN(),
400                    numeric_limits<float>::signaling_NaN());
401            return F::issignalingnan(fd);
402        }, "fmax.s, signaling NaN both");
403
404    // FCVT.W.S
405    expect<int64_t>(256, []{return F::fcvt_w_s(256.3);},
406            "fcvt.w.s, truncate positive");
407    expect<int64_t>(-256, []{return F::fcvt_w_s(-256.2);},
408            "fcvt.w.s, truncate negative");
409    expect<int64_t>(0, []{return F::fcvt_w_s(0.0);}, "fcvt.w.s, 0.0");
410    expect<int64_t>(0, []{return F::fcvt_w_s(-0.0);}, "fcvt.w.s, -0.0");
411    expect<int64_t>(numeric_limits<int32_t>::max(),
412            []{return F::fcvt_w_s(numeric_limits<float>::max());},
413            "fcvt.w.s, overflow");
414    expect<int64_t>(0, []{return F::fcvt_w_s(numeric_limits<float>::min());},
415            "fcvt.w.s, underflow");
416    expect<int64_t>(numeric_limits<int32_t>::max(),
417            []{return F::fcvt_w_s(numeric_limits<float>::infinity());},
418            "fcvt.w.s, infinity");
419    expect<int64_t>(numeric_limits<int32_t>::min(),
420            []{return F::fcvt_w_s(-numeric_limits<float>::infinity());},
421            "fcvt.w.s, -infinity");
422    expect<int64_t>(numeric_limits<int32_t>::max(),
423            []{return F::fcvt_w_s(numeric_limits<float>::quiet_NaN());},
424            "fcvt.w.s, quiet NaN");
425    expect<int64_t>(numeric_limits<int32_t>::max(),
426            []{return F::fcvt_w_s(-numeric_limits<float>::quiet_NaN());},
427            "fcvt.w.s, quiet -NaN");
428    expect<int64_t>(numeric_limits<int32_t>::max(),
429            []{return F::fcvt_w_s(numeric_limits<float>::signaling_NaN());},
430            "fcvt.w.s, signaling NaN");
431
432    // FCVT.WU.S
433    expect<uint64_t>(256, []{return F::fcvt_wu_s(256.3);},
434            "fcvt.wu.s, truncate positive");
435    expect<uint64_t>(0, []{return F::fcvt_wu_s(-256.2);},
436            "fcvt.wu.s, truncate negative");
437    expect<uint64_t>(0, []{return F::fcvt_wu_s(0.0);}, "fcvt.wu.s, 0.0");
438    expect<uint64_t>(0, []{return F::fcvt_wu_s(-0.0);}, "fcvt.wu.s, -0.0");
439    expect<uint64_t>(numeric_limits<uint64_t>::max(),
440            []{return F::fcvt_wu_s(numeric_limits<float>::max());},
441            "fcvt.wu.s, overflow");
442    expect<uint64_t>(0, []{return F::fcvt_wu_s(numeric_limits<float>::min());},
443            "fcvt.wu.s, underflow");
444    expect<uint64_t>(numeric_limits<uint64_t>::max(),
445            []{return F::fcvt_wu_s(numeric_limits<float>::infinity());},
446            "fcvt.wu.s, infinity");
447    expect<uint64_t>(0,
448            []{return F::fcvt_wu_s(-numeric_limits<float>::infinity());},
449            "fcvt.wu.s, -infinity");
450    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
451            []{return F::fcvt_wu_s(numeric_limits<float>::quiet_NaN());},
452            "fcvt.wu.s, quiet NaN");
453    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
454            []{return F::fcvt_wu_s(-numeric_limits<float>::quiet_NaN());},
455            "fcvt.wu.s, quiet -NaN");
456    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
457            []{return F::fcvt_wu_s(numeric_limits<float>::signaling_NaN());},
458            "fcvt.wu.s, signaling NaN");
459
460    // FMV.X.S
461    expect<uint64_t>(0x000000004048F5C3ULL, []{return F::fmv_x_s(3.14);},
462            "fmv.x.s, positive");
463    expect<uint64_t>(0xFFFFFFFFC048F5C3ULL, []{return F::fmv_x_s(-3.14);},
464            "fmv.x.s, negative");
465    expect<uint64_t>(0x0000000000000000ULL, []{return F::fmv_x_s(0.0);},
466            "fmv.x.s, 0.0");
467    expect<uint64_t>(0xFFFFFFFF80000000ULL, []{return F::fmv_x_s(-0.0);},
468            "fmv.x.s, -0.0");
469
470    // FEQ.S
471    expect<bool>(true, []{return F::feq_s(1.414, 1.414);}, "feq.s, equal");
472    expect<bool>(false, []{return F::feq_s(2.718, 1.816);},
473            "feq.s, not equal");
474    expect<bool>(true, []{return F::feq_s(0.0, -0.0);}, "feq.s, 0 == -0");
475    expect<bool>(false,
476            []{return F::feq_s(numeric_limits<float>::quiet_NaN(), -1.0);},
477            "feq.s, quiet NaN first");
478    expect<bool>(false,
479            []{return F::feq_s(2.0, numeric_limits<float>::quiet_NaN());},
480            "feq.s, quiet NaN second");
481    expect<bool>(false,
482            []{return F::feq_s(numeric_limits<float>::quiet_NaN(),
483                    numeric_limits<float>::quiet_NaN());},
484            "feq.s, quiet NaN both");
485    expect<bool>(false,
486            []{return F::feq_s(numeric_limits<float>::signaling_NaN(), -1.0);},
487            "feq.s, signaling NaN first");
488    expect<bool>(false,
489            []{return F::feq_s(2.0, numeric_limits<float>::signaling_NaN());},
490            "feq.s, signaling NaN second");
491    expect<bool>(false,
492            []{return F::feq_s(numeric_limits<float>::signaling_NaN(),
493                    numeric_limits<float>::signaling_NaN());},
494            "feq.s, signaling NaN both");
495
496    // FLT.S
497    expect<bool>(false, []{return F::flt_s(1.414, 1.414);}, "flt.s, equal");
498    expect<bool>(true, []{return F::flt_s(1.816, 2.718);}, "flt.s, less");
499    expect<bool>(false, []{return F::flt_s(2.718, 1.816);}, "flt.s, greater");
500    expect<bool>(false,
501            []{return F::flt_s(numeric_limits<float>::quiet_NaN(), -1.0);},
502            "flt.s, quiet NaN first");
503    expect<bool>(false,
504            []{return F::flt_s(2.0, numeric_limits<float>::quiet_NaN());},
505            "flt.s, quiet NaN second");
506    expect<bool>(false,
507            []{return F::flt_s(numeric_limits<float>::quiet_NaN(),
508                    numeric_limits<float>::quiet_NaN());},
509            "flt.s, quiet NaN both");
510    expect<bool>(false,
511            []{return F::flt_s(numeric_limits<float>::signaling_NaN(), -1.0);},
512            "flt.s, signaling NaN first");
513    expect<bool>(false,
514            []{return F::flt_s(2.0, numeric_limits<float>::signaling_NaN());},
515            "flt.s, signaling NaN second");
516    expect<bool>(false,
517            []{return F::flt_s(numeric_limits<float>::signaling_NaN(),
518                    numeric_limits<float>::signaling_NaN());},
519            "flt.s, signaling NaN both");
520
521    // FLE.S
522    expect<bool>(true, []{return F::fle_s(1.414, 1.414);}, "fle.s, equal");
523    expect<bool>(true, []{return F::fle_s(1.816, 2.718);}, "fle.s, less");
524    expect<bool>(false, []{return F::fle_s(2.718, 1.816);}, "fle.s, greater");
525    expect<bool>(true, []{return F::fle_s(0.0, -0.0);}, "fle.s, 0 == -0");
526    expect<bool>(false,
527            []{return F::fle_s(numeric_limits<float>::quiet_NaN(), -1.0);},
528            "fle.s, quiet NaN first");
529    expect<bool>(false,
530            []{return F::fle_s(2.0, numeric_limits<float>::quiet_NaN());},
531            "fle.s, quiet NaN second");
532    expect<bool>(false,
533            []{return F::fle_s(numeric_limits<float>::quiet_NaN(),
534                    numeric_limits<float>::quiet_NaN());},
535            "fle.s, quiet NaN both");
536    expect<bool>(false,
537            []{return F::fle_s(numeric_limits<float>::signaling_NaN(), -1.0);},
538            "fle.s, signaling NaN first");
539    expect<bool>(false,
540            []{return F::fle_s(2.0, numeric_limits<float>::signaling_NaN());},
541            "fle.s, signaling NaN second");
542    expect<bool>(false,
543            []{return F::fle_s(numeric_limits<float>::signaling_NaN(),
544                    numeric_limits<float>::signaling_NaN());},
545            "fle.s, signaling NaN both");
546
547    // FCLASS.S
548    expect<uint64_t>(0x1,
549            []{return F::fclass_s(-numeric_limits<float>::infinity());},
550            "fclass.s, -infinity");
551    expect<uint64_t>(0x2, []{return F::fclass_s(-3.14);}, "fclass.s, -normal");
552    expect<uint64_t>(0x4, []{return F::fclass_s(F::number(0x807FFFFF));},
553            "fclass.s, -subnormal");
554    expect<uint64_t>(0x8, []{return F::fclass_s(-0.0);}, "fclass.s, -0.0");
555    expect<uint64_t>(0x10, []{return F::fclass_s(0.0);}, "fclass.s, 0.0");
556    expect<uint64_t>(0x20, []{return F::fclass_s(F::number(0x007FFFFF));},
557            "fclass.s, subnormal");
558    expect<uint64_t>(0x40, []{return F::fclass_s(1.816);}, "fclass.s, normal");
559    expect<uint64_t>(0x80,
560            []{return F::fclass_s(numeric_limits<float>::infinity());},
561            "fclass.s, infinity");
562    expect<uint64_t>(0x100,
563            []{return F::fclass_s(numeric_limits<float>::signaling_NaN());},
564            "fclass.s, signaling NaN");
565    expect<uint64_t>(0x200,
566            []{return F::fclass_s(numeric_limits<float>::quiet_NaN());},
567            "fclass.s, quiet NaN");
568
569    // FCVT.S.W
570    expect<float>(0.0, []{return F::fcvt_s_w(0);}, "fcvt.s.w, 0");
571    expect<float>(-2147483648.0,
572            []{return F::fcvt_s_w(numeric_limits<int32_t>::min());},
573            "fcvt.s.w, negative");
574    expect<float>(255.0, []{return F::fcvt_s_w(0xFFFFFFFF000000FFLL);},
575            "fcvt.s.w, truncate");
576
577    // FCVT.S.WU
578    expect<float>(0.0, []{return F::fcvt_s_wu(0);}, "fcvt.s.wu, 0");
579    expect<float>(2147483648.0,
580            []{return F::fcvt_s_wu(numeric_limits<int32_t>::min());},
581            "fcvt.s.wu");
582    expect<float>(255.0, []{return F::fcvt_s_wu(0xFFFFFFFF000000FFLL);},
583            "fcvt.s.wu, truncate");
584
585    // FMV.S.X
586    expect<float>(numeric_limits<float>::infinity(),
587            []{return F::fmv_s_x(0x7F800000);}, "fmv.s.x");
588    expect<float>(-0.0, []{return F::fmv_s_x(0xFFFFFFFF80000000ULL);},
589            "fmv.s.x, truncate");
590
591    // FCSR functions
592    int rm = F::frrm();
593    expect<uint64_t>(0x7, []{ // FSRM
594            F::fsrm(-1);
595            return F::frrm();
596        }, "fsrm");
597    expect<uint64_t>(0x1F, []{ // FSFLAGS
598            F::fsflags(0);
599            F::fsflags(-1);
600            return F::frflags();
601        }, "fsflags");
602    expect<uint64_t>(0xFF, []{ // FSCSR
603            F::fsflags(0);
604            F::fsrm(0);
605            F::fscsr(-1);
606            return F::frcsr();
607        }, "fscsr");
608    expect<int>(rm << 5, [=]{
609            F::fscsr(0);
610            F::fsrm(rm);
611            return F::frcsr();
612        }, "restore initial round mode");
613
614    F::fsflags(0);
615
616    // FCVT.L.S
617    expect<int64_t>(256, []{return F::fcvt_l_s(256.3);},
618            "fcvt.l.s, truncate positive");
619    expect<int64_t>(-256, []{return F::fcvt_l_s(-256.2);},
620            "fcvt.l.s, truncate negative");
621    expect<int64_t>(0, []{return F::fcvt_l_s(0.0);}, "fcvt.l.s, 0.0");
622    expect<int64_t>(0, []{return F::fcvt_l_s(-0.0);}, "fcvt.l.s, -0.0");
623    expect<int64_t>(-8589934592LL, []{return F::fcvt_l_s(-8589934592.0);},
624            "fcvt.l.s, 32-bit overflow");
625    expect<int64_t>(numeric_limits<int64_t>::max(),
626            []{return F::fcvt_l_s(numeric_limits<float>::max());},
627            "fcvt.l.s, overflow");
628    expect<int64_t>(0, []{return F::fcvt_l_s(numeric_limits<float>::min());},
629            "fcvt.l.s, underflow");
630    expect<int64_t>(numeric_limits<int64_t>::max(),
631            []{return F::fcvt_l_s(numeric_limits<float>::infinity());},
632            "fcvt.l.s, infinity");
633    expect<int64_t>(numeric_limits<int64_t>::min(),
634            []{return F::fcvt_l_s(-numeric_limits<float>::infinity());},
635            "fcvt.l.s, -infinity");
636    expect<int64_t>(numeric_limits<int64_t>::max(),
637            []{return F::fcvt_l_s(numeric_limits<float>::quiet_NaN());},
638            "fcvt.l.s, quiet NaN");
639    expect<int64_t>(numeric_limits<int64_t>::max(),
640            []{return F::fcvt_l_s(-numeric_limits<float>::quiet_NaN());},
641            "fcvt.l.s, quiet -NaN");
642    expect<int64_t>(numeric_limits<int64_t>::max(),
643            []{return F::fcvt_l_s(numeric_limits<float>::signaling_NaN());},
644            "fcvt.l.s, signaling NaN");
645
646    // FCVT.LU.S
647    expect<uint64_t>(256, []{return F::fcvt_lu_s(256.3);},
648            "fcvt.lu.s, truncate positive");
649    expect<uint64_t>(0, []{return F::fcvt_lu_s(-256.2);},
650            "fcvt.lu.s, truncate negative");
651    expect<uint64_t>(0, []{return F::fcvt_lu_s(0.0);}, "fcvt.lu.s, 0.0");
652    expect<uint64_t>(0, []{return F::fcvt_lu_s(-0.0);}, "fcvt.lu.s, -0.0");
653    expect<uint64_t>(8589934592LL,
654            []{return F::fcvt_lu_s(8589934592.0);},
655            "fcvt.lu.s, 32-bit overflow");
656    expect<uint64_t>(numeric_limits<uint64_t>::max(),
657            []{return F::fcvt_lu_s(numeric_limits<float>::max());},
658            "fcvt.lu.s, overflow");
659    expect<uint64_t>(0, []{return F::fcvt_lu_s(numeric_limits<float>::min());},
660            "fcvt.lu.s, underflow");
661    expect<uint64_t>(numeric_limits<uint64_t>::max(),
662            []{return F::fcvt_lu_s(numeric_limits<float>::infinity());},
663            "fcvt.lu.s, infinity");
664    expect<uint64_t>(0,
665            []{return F::fcvt_lu_s(-numeric_limits<float>::infinity());},
666            "fcvt.lu.s, -infinity");
667    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
668            []{return F::fcvt_lu_s(numeric_limits<float>::quiet_NaN());},
669            "fcvt.lu.s, quiet NaN");
670    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
671            []{return F::fcvt_lu_s(-numeric_limits<float>::quiet_NaN());},
672            "fcvt.lu.s, quiet -NaN");
673    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
674            []{return F::fcvt_lu_s(numeric_limits<float>::signaling_NaN());},
675            "fcvt.lu.s, signaling NaN");
676
677    // FCVT.S.L
678    expect<float>(0.0, []{return F::fcvt_s_l(0);}, "fcvt.s.l, 0");
679    expect<float>(-9.223372e18,
680            []{return F::fcvt_s_l(numeric_limits<int64_t>::min());},
681            "fcvt.s.l, negative");
682    expect<float>(-4.29496704e9, []{return F::fcvt_s_l(0xFFFFFFFF000000FFLL);},
683            "fcvt.s.l, 32-bit truncate");
684
685    // FCVT.S.LU
686    expect<float>(0.0, []{return F::fcvt_s_lu(0);}, "fcvt.s.lu, 0");
687    expect<float>(9.223372e18,
688            []{return F::fcvt_s_lu(numeric_limits<int64_t>::min());},
689            "fcvt.s.lu");
690    expect<float>(1.8446744e19, []{return F::fcvt_s_lu(0xFFFFFFFF000000FFLL);},
691            "fcvt.s.lu, 32-bit truncate");
692
693    return 0;
694}
695