All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat
@ 2018-09-08 19:17 Emilio G. Cota
  2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 1/2] gitmodules: add berkeley's softfloat + testfloat version 3 Emilio G. Cota
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Emilio G. Cota @ 2018-09-08 19:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Aurelien Jarno, Richard Henderson,
	Alex Bennée, Laurent Vivier

A few fixes since yesterday's v1:
  https://lists.gnu.org/archive/html/qemu-devel/2018-09/msg00884.html

- Convert copy_qemu_to_soft80 to qemu_to_soft80, just like the other
  conversion functions
- Set fp-test as the program name as reported by itself
- Fix Makefile to include .d files so that dependencies are
  properly tracked
- Update commit log

Grab this from:
  https://github.com/cota/qemu/tree/fp-test-v2

Thanks,

		Emilio

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 1/2] gitmodules: add berkeley's softfloat + testfloat version 3
  2018-09-08 19:17 [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat Emilio G. Cota
@ 2018-09-08 19:17 ` Emilio G. Cota
  2018-09-10  9:29   ` Alex Bennée
  2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 2/2] tests: add floating point tests Emilio G. Cota
  2018-09-10 11:26 ` [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat Alex Bennée
  2 siblings, 1 reply; 10+ messages in thread
From: Emilio G. Cota @ 2018-09-08 19:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Aurelien Jarno, Richard Henderson,
	Alex Bennée, Laurent Vivier

These are BSD-licensed so we can add them as submodules.

Signed-off-by: Emilio G. Cota <cota@braap.org>
---
 .gitmodules                   | 6 ++++++
 tests/fp/berkeley-softfloat-3 | 1 +
 tests/fp/berkeley-testfloat-3 | 1 +
 3 files changed, 8 insertions(+)
 create mode 160000 tests/fp/berkeley-softfloat-3
 create mode 160000 tests/fp/berkeley-testfloat-3

diff --git a/.gitmodules b/.gitmodules
index d108478e0a..165c7c5286 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -43,3 +43,9 @@
 [submodule "roms/u-boot-sam460ex"]
 	path = roms/u-boot-sam460ex
 	url = git://git.qemu.org/u-boot-sam460ex.git
+[submodule "tests/fp/testfloat"]
+	path = tests/fp/berkeley-testfloat-3
+	url = git://github.com/ucb-bar/berkeley-testfloat-3
+[submodule "tests/fp/berkeley-softfloat-3"]
+	path = tests/fp/berkeley-softfloat-3
+	url = git://github.com/ucb-bar/berkeley-softfloat-3
diff --git a/tests/fp/berkeley-softfloat-3 b/tests/fp/berkeley-softfloat-3
new file mode 160000
index 0000000000..b64af41c32
--- /dev/null
+++ b/tests/fp/berkeley-softfloat-3
@@ -0,0 +1 @@
+Subproject commit b64af41c3276f97f0e181920400ee056b9c88037
diff --git a/tests/fp/berkeley-testfloat-3 b/tests/fp/berkeley-testfloat-3
new file mode 160000
index 0000000000..06b20075dd
--- /dev/null
+++ b/tests/fp/berkeley-testfloat-3
@@ -0,0 +1 @@
+Subproject commit 06b20075dd3c1a5d0dd007a93643282832221612
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 2/2] tests: add floating point tests
  2018-09-08 19:17 [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat Emilio G. Cota
  2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 1/2] gitmodules: add berkeley's softfloat + testfloat version 3 Emilio G. Cota
@ 2018-09-08 19:17 ` Emilio G. Cota
  2018-09-10 11:00   ` Alex Bennée
  2018-09-10 11:26 ` [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat Alex Bennée
  2 siblings, 1 reply; 10+ messages in thread
From: Emilio G. Cota @ 2018-09-08 19:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Aurelien Jarno, Richard Henderson,
	Alex Bennée, Laurent Vivier

By leveraging berkeley's softfloat and testfloat.

fp-test.c is derived from testfloat's testsoftfloat.c. To ease
the tracking of upstream changes to the latter file, fp-test.c
keeps the original camel-case variable naming, and includes
most new code via wrap.inc.c.

Most changes to the original code are simple style changes,
although a couple of not-so-subtle modifications have been
made (noted with XXX in the code), namely:

- We do not test ROUND_ODD, since not all of our primitives
  support it (e.g. fp16)

- Do not test !exact in round-to-integer, since it is not
  implemented in QEMU (this flag was added to softfloat v3).

Signed-off-by: Emilio G. Cota <cota@braap.org>
---
 configure              |    2 +
 tests/fp/platform.h    |   41 ++
 tests/fp/fp-test.c     | 1052 ++++++++++++++++++++++++++++++++++++++++
 tests/fp/wrap.inc.c    |  600 +++++++++++++++++++++++
 tests/Makefile.include |    3 +
 tests/fp/.gitignore    |    1 +
 tests/fp/Makefile      |  591 ++++++++++++++++++++++
 7 files changed, 2290 insertions(+)
 create mode 100644 tests/fp/platform.h
 create mode 100644 tests/fp/fp-test.c
 create mode 100644 tests/fp/wrap.inc.c
 create mode 100644 tests/fp/.gitignore
 create mode 100644 tests/fp/Makefile

diff --git a/configure b/configure
index 58862d2ae8..b02da8c0b4 100755
--- a/configure
+++ b/configure
@@ -7451,12 +7451,14 @@ fi
 
 # build tree in object directory in case the source is not in the current directory
 DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm"
+DIRS="$DIRS tests/fp"
 DIRS="$DIRS docs docs/interop fsdev scsi"
 DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
 DIRS="$DIRS roms/seabios roms/vgabios"
 FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
 FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
 FILES="$FILES tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makefile"
+FILES="$FILES tests/fp/Makefile"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
 FILES="$FILES pc-bios/spapr-rtas/Makefile"
 FILES="$FILES pc-bios/s390-ccw/Makefile"
diff --git a/tests/fp/platform.h b/tests/fp/platform.h
new file mode 100644
index 0000000000..80af8a94b6
--- /dev/null
+++ b/tests/fp/platform.h
@@ -0,0 +1,41 @@
+#ifndef QEMU_TESTFLOAT_PLATFORM_H
+#define QEMU_TESTFLOAT_PLATFORM_H
+/*
+ * Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of
+ * California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions, and the following disclaimer.
+ *
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions, and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *
+ *  3. Neither the name of the University nor the names of its contributors may
+ *     be used to endorse or promote products derived from this software without
+ *     specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config-host.h"
+
+#ifndef HOST_WORDS_BIGENDIAN
+#define LITTLEENDIAN 1
+/* otherwise do not define it */
+#endif
+
+#define INLINE static inline
+
+#endif /* QEMU_TESTFLOAT_PLATFORM_H */
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
new file mode 100644
index 0000000000..43da4e43c5
--- /dev/null
+++ b/tests/fp/fp-test.c
@@ -0,0 +1,1052 @@
+/*
+ * fp-test.c - test QEMU's softfloat implementation using Berkeley's Testfloat
+ *
+ * Derived from testfloat/source/testsoftfloat.c.
+ *
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ * Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the
+ * University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions, and the following disclaimer.
+ *
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions, and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *  3. Neither the name of the University nor the names of its contributors may
+ *     be used to endorse or promote products derived from this software without
+ *     specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef HW_POISON_H
+#error Must define HW_POISON_H to work around TARGET_* poisoning
+#endif
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include <math.h>
+#include "fpu/softfloat.h"
+#include "platform.h"
+
+#include "fail.h"
+#include "slowfloat.h"
+#include "functions.h"
+#include "genCases.h"
+#include "verCases.h"
+#include "writeCase.h"
+#include "testLoops.h"
+
+/* keep most code separate to make tracking upstream changes more easily */
+#include "wrap.inc.c"
+
+enum {
+    EXACT_FALSE = 1,
+    EXACT_TRUE
+};
+
+static void catchSIGINT(int signalCode)
+{
+    if (verCases_stop) {
+        exit(EXIT_FAILURE);
+    }
+    verCases_stop = true;
+}
+
+static void
+testFunctionInstance(int functionCode, uint_fast8_t roundingMode, bool exact)
+{
+    float16_t (*trueFunction_abz_f16)(float16_t, float16_t);
+    float16_t (*subjFunction_abz_f16)(float16_t, float16_t);
+    bool (*trueFunction_ab_f16_z_bool)(float16_t, float16_t);
+    bool (*subjFunction_ab_f16_z_bool)(float16_t, float16_t);
+    float32_t (*trueFunction_abz_f32)(float32_t, float32_t);
+    float32_t (*subjFunction_abz_f32)(float32_t, float32_t);
+    bool (*trueFunction_ab_f32_z_bool)(float32_t, float32_t);
+    bool (*subjFunction_ab_f32_z_bool)(float32_t, float32_t);
+    float64_t (*trueFunction_abz_f64)(float64_t, float64_t);
+    float64_t (*subjFunction_abz_f64)(float64_t, float64_t);
+    bool (*trueFunction_ab_f64_z_bool)(float64_t, float64_t);
+    bool (*subjFunction_ab_f64_z_bool)(float64_t, float64_t);
+    void (*trueFunction_abz_extF80M)(
+        const extFloat80_t *, const extFloat80_t *, extFloat80_t *);
+    void (*subjFunction_abz_extF80M)(
+        const extFloat80_t *, const extFloat80_t *, extFloat80_t *);
+    bool (*trueFunction_ab_extF80M_z_bool)(
+        const extFloat80_t *, const extFloat80_t *);
+    bool (*subjFunction_ab_extF80M_z_bool)(
+        const extFloat80_t *, const extFloat80_t *);
+    void (*trueFunction_abz_f128M)(
+        const float128_t *, const float128_t *, float128_t *);
+    void (*subjFunction_abz_f128M)(
+        const float128_t *, const float128_t *, float128_t *);
+    bool (*trueFunction_ab_f128M_z_bool)(
+        const float128_t *, const float128_t *);
+    bool (*subjFunction_ab_f128M_z_bool)(
+        const float128_t *, const float128_t *);
+
+    fputs("Testing ", stderr);
+    verCases_writeFunctionName(stderr);
+    fputs(".\n", stderr);
+
+    switch (functionCode) {
+        /*--------------------------------------------------------------------
+         *--------------------------------------------------------------------*/
+    case UI32_TO_F16:
+        test_a_ui32_z_f16(slow_ui32_to_f16, qemu_ui32_to_f16);
+        break;
+    case UI32_TO_F32:
+        test_a_ui32_z_f32(slow_ui32_to_f32, qemu_ui32_to_f32);
+        break;
+    case UI32_TO_F64:
+        test_a_ui32_z_f64(slow_ui32_to_f64, qemu_ui32_to_f64);
+        break;
+    case UI32_TO_EXTF80:
+        /* not implemented */
+        break;
+    case UI32_TO_F128:
+        /* not implemented */
+        break;
+    case UI64_TO_F16:
+        test_a_ui64_z_f16(slow_ui64_to_f16, qemu_ui64_to_f16);
+        break;
+    case UI64_TO_F32:
+        test_a_ui64_z_f32(slow_ui64_to_f32, qemu_ui64_to_f32);
+        break;
+    case UI64_TO_F64:
+        test_a_ui64_z_f64(slow_ui64_to_f64, qemu_ui64_to_f64);
+        break;
+    case UI64_TO_EXTF80:
+        /* not implemented */
+        break;
+    case UI64_TO_F128:
+        test_a_ui64_z_f128(slow_ui64_to_f128M, qemu_ui64_to_f128M);
+        break;
+    case I32_TO_F16:
+        test_a_i32_z_f16(slow_i32_to_f16, qemu_i32_to_f16);
+        break;
+    case I32_TO_F32:
+        test_a_i32_z_f32(slow_i32_to_f32, qemu_i32_to_f32);
+        break;
+    case I32_TO_F64:
+        test_a_i32_z_f64(slow_i32_to_f64, qemu_i32_to_f64);
+        break;
+    case I32_TO_EXTF80:
+        test_a_i32_z_extF80(slow_i32_to_extF80M, qemu_i32_to_extF80M);
+        break;
+    case I32_TO_F128:
+        test_a_i32_z_f128(slow_i32_to_f128M, qemu_i32_to_f128M);
+        break;
+    case I64_TO_F16:
+        test_a_i64_z_f16(slow_i64_to_f16, qemu_i64_to_f16);
+        break;
+    case I64_TO_F32:
+        test_a_i64_z_f32(slow_i64_to_f32, qemu_i64_to_f32);
+        break;
+    case I64_TO_F64:
+        test_a_i64_z_f64(slow_i64_to_f64, qemu_i64_to_f64);
+        break;
+    case I64_TO_EXTF80:
+        test_a_i64_z_extF80(slow_i64_to_extF80M, qemu_i64_to_extF80M);
+        break;
+    case I64_TO_F128:
+        test_a_i64_z_f128(slow_i64_to_f128M, qemu_i64_to_f128M);
+        break;
+        /*--------------------------------------------------------------------
+         *--------------------------------------------------------------------*/
+    case F16_TO_UI32:
+        test_a_f16_z_ui32_rx(
+        slow_f16_to_ui32, qemu_f16_to_ui32, roundingMode, exact);
+        break;
+    case F16_TO_UI64:
+        test_a_f16_z_ui64_rx(
+        slow_f16_to_ui64, qemu_f16_to_ui64, roundingMode, exact);
+        break;
+    case F16_TO_I32:
+        test_a_f16_z_i32_rx(
+        slow_f16_to_i32, qemu_f16_to_i32, roundingMode, exact);
+        break;
+    case F16_TO_I64:
+        test_a_f16_z_i64_rx(
+        slow_f16_to_i64, qemu_f16_to_i64, roundingMode, exact);
+        break;
+    case F16_TO_UI32_R_MINMAG:
+        /* not implemented */
+        break;
+    case F16_TO_UI64_R_MINMAG:
+        /* not implemented */
+        break;
+    case F16_TO_I32_R_MINMAG:
+        /* not implemented */
+        break;
+    case F16_TO_I64_R_MINMAG:
+        /* not implemented */
+        break;
+    case F16_TO_F32:
+        test_a_f16_z_f32(slow_f16_to_f32, qemu_f16_to_f32);
+        break;
+    case F16_TO_F64:
+        test_a_f16_z_f64(slow_f16_to_f64, qemu_f16_to_f64);
+        break;
+    case F16_TO_EXTF80:
+        /* not implemented */
+        break;
+    case F16_TO_F128:
+        /* not implemented */
+        break;
+    case F16_ROUNDTOINT:
+        test_az_f16_rx(
+        slow_f16_roundToInt, qemu_f16_roundToInt, roundingMode, exact);
+        break;
+    case F16_ADD:
+        trueFunction_abz_f16 = slow_f16_add;
+        subjFunction_abz_f16 = qemu_f16_add;
+        goto test_abz_f16;
+    case F16_SUB:
+        trueFunction_abz_f16 = slow_f16_sub;
+        subjFunction_abz_f16 = qemu_f16_sub;
+        goto test_abz_f16;
+    case F16_MUL:
+        trueFunction_abz_f16 = slow_f16_mul;
+        subjFunction_abz_f16 = qemu_f16_mul;
+        goto test_abz_f16;
+    case F16_DIV:
+        trueFunction_abz_f16 = slow_f16_div;
+        subjFunction_abz_f16 = qemu_f16_div;
+        goto test_abz_f16;
+    case F16_REM:
+        /* not implemented */
+        break;
+    test_abz_f16:
+        test_abz_f16(trueFunction_abz_f16, subjFunction_abz_f16);
+        break;
+    case F16_MULADD:
+        test_abcz_f16(slow_f16_mulAdd, qemu_f16_mulAdd);
+        break;
+    case F16_SQRT:
+        test_az_f16(slow_f16_sqrt, qemu_f16_sqrt);
+        break;
+    case F16_EQ:
+        trueFunction_ab_f16_z_bool = slow_f16_eq;
+        subjFunction_ab_f16_z_bool = qemu_f16_eq;
+        goto test_ab_f16_z_bool;
+    case F16_LE:
+        trueFunction_ab_f16_z_bool = slow_f16_le;
+        subjFunction_ab_f16_z_bool = qemu_f16_le;
+        goto test_ab_f16_z_bool;
+    case F16_LT:
+        trueFunction_ab_f16_z_bool = slow_f16_lt;
+        subjFunction_ab_f16_z_bool = qemu_f16_lt;
+        goto test_ab_f16_z_bool;
+    case F16_EQ_SIGNALING:
+        trueFunction_ab_f16_z_bool = slow_f16_eq_signaling;
+        subjFunction_ab_f16_z_bool = qemu_f16_eq_signaling;
+        goto test_ab_f16_z_bool;
+    case F16_LE_QUIET:
+        trueFunction_ab_f16_z_bool = slow_f16_le_quiet;
+        subjFunction_ab_f16_z_bool = qemu_f16_le_quiet;
+        goto test_ab_f16_z_bool;
+    case F16_LT_QUIET:
+        trueFunction_ab_f16_z_bool = slow_f16_lt_quiet;
+        subjFunction_ab_f16_z_bool = qemu_f16_lt_quiet;
+    test_ab_f16_z_bool:
+        test_ab_f16_z_bool(
+        trueFunction_ab_f16_z_bool, subjFunction_ab_f16_z_bool);
+        break;
+        /*--------------------------------------------------------------------
+         *--------------------------------------------------------------------*/
+    case F32_TO_UI32:
+        test_a_f32_z_ui32_rx(
+        slow_f32_to_ui32, qemu_f32_to_ui32, roundingMode, exact);
+        break;
+    case F32_TO_UI64:
+        test_a_f32_z_ui64_rx(
+        slow_f32_to_ui64, qemu_f32_to_ui64, roundingMode, exact);
+        break;
+    case F32_TO_I32:
+        test_a_f32_z_i32_rx(
+        slow_f32_to_i32, qemu_f32_to_i32, roundingMode, exact);
+        break;
+    case F32_TO_I64:
+        test_a_f32_z_i64_rx(
+        slow_f32_to_i64, qemu_f32_to_i64, roundingMode, exact);
+        break;
+    case F32_TO_UI32_R_MINMAG:
+        /* not implemented */
+        break;
+    case F32_TO_UI64_R_MINMAG:
+        /* not implemented */
+        break;
+    case F32_TO_I32_R_MINMAG:
+        /* not implemented */
+        break;
+    case F32_TO_I64_R_MINMAG:
+        /* not implemented */
+        break;
+    case F32_TO_F16:
+        test_a_f32_z_f16(slow_f32_to_f16, qemu_f32_to_f16);
+        break;
+    case F32_TO_F64:
+        test_a_f32_z_f64(slow_f32_to_f64, qemu_f32_to_f64);
+        break;
+    case F32_TO_EXTF80:
+        test_a_f32_z_extF80(slow_f32_to_extF80M, qemu_f32_to_extF80M);
+        break;
+    case F32_TO_F128:
+        test_a_f32_z_f128(slow_f32_to_f128M, qemu_f32_to_f128M);
+        break;
+    case F32_ROUNDTOINT:
+        test_az_f32_rx(
+        slow_f32_roundToInt, qemu_f32_roundToInt, roundingMode, exact);
+        break;
+    case F32_ADD:
+        trueFunction_abz_f32 = slow_f32_add;
+        subjFunction_abz_f32 = qemu_f32_add;
+        goto test_abz_f32;
+    case F32_SUB:
+        trueFunction_abz_f32 = slow_f32_sub;
+        subjFunction_abz_f32 = qemu_f32_sub;
+        goto test_abz_f32;
+    case F32_MUL:
+        trueFunction_abz_f32 = slow_f32_mul;
+        subjFunction_abz_f32 = qemu_f32_mul;
+        goto test_abz_f32;
+    case F32_DIV:
+        trueFunction_abz_f32 = slow_f32_div;
+        subjFunction_abz_f32 = qemu_f32_div;
+        goto test_abz_f32;
+    case F32_REM:
+        trueFunction_abz_f32 = slow_f32_rem;
+        subjFunction_abz_f32 = qemu_f32_rem;
+    test_abz_f32:
+        test_abz_f32(trueFunction_abz_f32, subjFunction_abz_f32);
+        break;
+    case F32_MULADD:
+        test_abcz_f32(slow_f32_mulAdd, qemu_f32_mulAdd);
+        break;
+    case F32_SQRT:
+        test_az_f32(slow_f32_sqrt, qemu_f32_sqrt);
+        break;
+    case F32_EQ:
+        trueFunction_ab_f32_z_bool = slow_f32_eq;
+        subjFunction_ab_f32_z_bool = qemu_f32_eq;
+        goto test_ab_f32_z_bool;
+    case F32_LE:
+        trueFunction_ab_f32_z_bool = slow_f32_le;
+        subjFunction_ab_f32_z_bool = qemu_f32_le;
+        goto test_ab_f32_z_bool;
+    case F32_LT:
+        trueFunction_ab_f32_z_bool = slow_f32_lt;
+        subjFunction_ab_f32_z_bool = qemu_f32_lt;
+        goto test_ab_f32_z_bool;
+    case F32_EQ_SIGNALING:
+        trueFunction_ab_f32_z_bool = slow_f32_eq_signaling;
+        subjFunction_ab_f32_z_bool = qemu_f32_eq_signaling;
+        goto test_ab_f32_z_bool;
+    case F32_LE_QUIET:
+        trueFunction_ab_f32_z_bool = slow_f32_le_quiet;
+        subjFunction_ab_f32_z_bool = qemu_f32_le_quiet;
+        goto test_ab_f32_z_bool;
+    case F32_LT_QUIET:
+        trueFunction_ab_f32_z_bool = slow_f32_lt_quiet;
+        subjFunction_ab_f32_z_bool = qemu_f32_lt_quiet;
+    test_ab_f32_z_bool:
+        test_ab_f32_z_bool(
+        trueFunction_ab_f32_z_bool, subjFunction_ab_f32_z_bool);
+        break;
+        /*--------------------------------------------------------------------
+         *--------------------------------------------------------------------*/
+    case F64_TO_UI32:
+        test_a_f64_z_ui32_rx(
+        slow_f64_to_ui32, qemu_f64_to_ui32, roundingMode, exact);
+        break;
+    case F64_TO_UI64:
+        test_a_f64_z_ui64_rx(
+        slow_f64_to_ui64, qemu_f64_to_ui64, roundingMode, exact);
+        break;
+    case F64_TO_I32:
+        test_a_f64_z_i32_rx(
+        slow_f64_to_i32, qemu_f64_to_i32, roundingMode, exact);
+        break;
+    case F64_TO_I64:
+        test_a_f64_z_i64_rx(
+        slow_f64_to_i64, qemu_f64_to_i64, roundingMode, exact);
+        break;
+    case F64_TO_UI32_R_MINMAG:
+        /* not implemented */
+        break;
+    case F64_TO_UI64_R_MINMAG:
+        /* not implemented */
+        break;
+    case F64_TO_I32_R_MINMAG:
+        /* not implemented */
+        break;
+    case F64_TO_I64_R_MINMAG:
+        /* not implemented */
+        break;
+    case F64_TO_F16:
+        test_a_f64_z_f16(slow_f64_to_f16, qemu_f64_to_f16);
+        break;
+    case F64_TO_F32:
+        test_a_f64_z_f32(slow_f64_to_f32, qemu_f64_to_f32);
+        break;
+    case F64_TO_EXTF80:
+        test_a_f64_z_extF80(slow_f64_to_extF80M, qemu_f64_to_extF80M);
+        break;
+    case F64_TO_F128:
+        test_a_f64_z_f128(slow_f64_to_f128M, qemu_f64_to_f128M);
+        break;
+    case F64_ROUNDTOINT:
+        test_az_f64_rx(
+        slow_f64_roundToInt, qemu_f64_roundToInt, roundingMode, exact);
+        break;
+    case F64_ADD:
+        trueFunction_abz_f64 = slow_f64_add;
+        subjFunction_abz_f64 = qemu_f64_add;
+        goto test_abz_f64;
+    case F64_SUB:
+        trueFunction_abz_f64 = slow_f64_sub;
+        subjFunction_abz_f64 = qemu_f64_sub;
+        goto test_abz_f64;
+    case F64_MUL:
+        trueFunction_abz_f64 = slow_f64_mul;
+        subjFunction_abz_f64 = qemu_f64_mul;
+        goto test_abz_f64;
+    case F64_DIV:
+        trueFunction_abz_f64 = slow_f64_div;
+        subjFunction_abz_f64 = qemu_f64_div;
+        goto test_abz_f64;
+    case F64_REM:
+        trueFunction_abz_f64 = slow_f64_rem;
+        subjFunction_abz_f64 = qemu_f64_rem;
+    test_abz_f64:
+        test_abz_f64(trueFunction_abz_f64, subjFunction_abz_f64);
+        break;
+    case F64_MULADD:
+        test_abcz_f64(slow_f64_mulAdd, qemu_f64_mulAdd);
+        break;
+    case F64_SQRT:
+        test_az_f64(slow_f64_sqrt, qemu_f64_sqrt);
+        break;
+    case F64_EQ:
+        trueFunction_ab_f64_z_bool = slow_f64_eq;
+        subjFunction_ab_f64_z_bool = qemu_f64_eq;
+        goto test_ab_f64_z_bool;
+    case F64_LE:
+        trueFunction_ab_f64_z_bool = slow_f64_le;
+        subjFunction_ab_f64_z_bool = qemu_f64_le;
+        goto test_ab_f64_z_bool;
+    case F64_LT:
+        trueFunction_ab_f64_z_bool = slow_f64_lt;
+        subjFunction_ab_f64_z_bool = qemu_f64_lt;
+        goto test_ab_f64_z_bool;
+    case F64_EQ_SIGNALING:
+        trueFunction_ab_f64_z_bool = slow_f64_eq_signaling;
+        subjFunction_ab_f64_z_bool = qemu_f64_eq_signaling;
+        goto test_ab_f64_z_bool;
+    case F64_LE_QUIET:
+        trueFunction_ab_f64_z_bool = slow_f64_le_quiet;
+        subjFunction_ab_f64_z_bool = qemu_f64_le_quiet;
+        goto test_ab_f64_z_bool;
+    case F64_LT_QUIET:
+        trueFunction_ab_f64_z_bool = slow_f64_lt_quiet;
+        subjFunction_ab_f64_z_bool = qemu_f64_lt_quiet;
+    test_ab_f64_z_bool:
+        test_ab_f64_z_bool(
+        trueFunction_ab_f64_z_bool, subjFunction_ab_f64_z_bool);
+        break;
+        /*--------------------------------------------------------------------
+         *--------------------------------------------------------------------*/
+    case EXTF80_TO_UI32:
+        /* not implemented */
+        break;
+    case EXTF80_TO_UI64:
+        /* not implemented */
+        break;
+    case EXTF80_TO_I32:
+        test_a_extF80_z_i32_rx(
+        slow_extF80M_to_i32, qemu_extF80M_to_i32, roundingMode, exact);
+        break;
+    case EXTF80_TO_I64:
+        test_a_extF80_z_i64_rx(
+        slow_extF80M_to_i64, qemu_extF80M_to_i64, roundingMode, exact);
+        break;
+    case EXTF80_TO_UI32_R_MINMAG:
+        /* not implemented */
+        break;
+    case EXTF80_TO_UI64_R_MINMAG:
+        /* not implemented */
+        break;
+    case EXTF80_TO_I32_R_MINMAG:
+        /* not implemented */
+        break;
+    case EXTF80_TO_I64_R_MINMAG:
+        /* not implemented */
+        break;
+    case EXTF80_TO_F16:
+        /* not implemented */
+        break;
+    case EXTF80_TO_F32:
+        test_a_extF80_z_f32(slow_extF80M_to_f32, qemu_extF80M_to_f32);
+        break;
+    case EXTF80_TO_F64:
+        test_a_extF80_z_f64(slow_extF80M_to_f64, qemu_extF80M_to_f64);
+        break;
+    case EXTF80_TO_F128:
+        test_a_extF80_z_f128(slow_extF80M_to_f128M, qemu_extF80M_to_f128M);
+        break;
+    case EXTF80_ROUNDTOINT:
+        test_az_extF80_rx(
+        slow_extF80M_roundToInt, qemu_extF80M_roundToInt, roundingMode, exact);
+        break;
+    case EXTF80_ADD:
+        trueFunction_abz_extF80M = slow_extF80M_add;
+        subjFunction_abz_extF80M = qemu_extF80M_add;
+        goto test_abz_extF80;
+    case EXTF80_SUB:
+        trueFunction_abz_extF80M = slow_extF80M_sub;
+        subjFunction_abz_extF80M = qemu_extF80M_sub;
+        goto test_abz_extF80;
+    case EXTF80_MUL:
+        trueFunction_abz_extF80M = slow_extF80M_mul;
+        subjFunction_abz_extF80M = qemu_extF80M_mul;
+        goto test_abz_extF80;
+    case EXTF80_DIV:
+        trueFunction_abz_extF80M = slow_extF80M_div;
+        subjFunction_abz_extF80M = qemu_extF80M_div;
+        goto test_abz_extF80;
+    case EXTF80_REM:
+        trueFunction_abz_extF80M = slow_extF80M_rem;
+        subjFunction_abz_extF80M = qemu_extF80M_rem;
+    test_abz_extF80:
+        test_abz_extF80(trueFunction_abz_extF80M, subjFunction_abz_extF80M);
+        break;
+    case EXTF80_SQRT:
+        test_az_extF80(slow_extF80M_sqrt, qemu_extF80M_sqrt);
+        break;
+    case EXTF80_EQ:
+        trueFunction_ab_extF80M_z_bool = slow_extF80M_eq;
+        subjFunction_ab_extF80M_z_bool = qemu_extF80M_eq;
+        goto test_ab_extF80_z_bool;
+    case EXTF80_LE:
+        trueFunction_ab_extF80M_z_bool = slow_extF80M_le;
+        subjFunction_ab_extF80M_z_bool = qemu_extF80M_le;
+        goto test_ab_extF80_z_bool;
+    case EXTF80_LT:
+        trueFunction_ab_extF80M_z_bool = slow_extF80M_lt;
+        subjFunction_ab_extF80M_z_bool = qemu_extF80M_lt;
+        goto test_ab_extF80_z_bool;
+    case EXTF80_EQ_SIGNALING:
+        trueFunction_ab_extF80M_z_bool = slow_extF80M_eq_signaling;
+        subjFunction_ab_extF80M_z_bool = qemu_extF80M_eq_signaling;
+        goto test_ab_extF80_z_bool;
+    case EXTF80_LE_QUIET:
+        trueFunction_ab_extF80M_z_bool = slow_extF80M_le_quiet;
+        subjFunction_ab_extF80M_z_bool = qemu_extF80M_le_quiet;
+        goto test_ab_extF80_z_bool;
+    case EXTF80_LT_QUIET:
+        trueFunction_ab_extF80M_z_bool = slow_extF80M_lt_quiet;
+        subjFunction_ab_extF80M_z_bool = qemu_extF80M_lt_quiet;
+    test_ab_extF80_z_bool:
+        test_ab_extF80_z_bool(
+        trueFunction_ab_extF80M_z_bool, subjFunction_ab_extF80M_z_bool);
+        break;
+        /*--------------------------------------------------------------------
+         *--------------------------------------------------------------------*/
+    case F128_TO_UI32:
+        /* not implemented */
+        break;
+    case F128_TO_UI64:
+        test_a_f128_z_ui64_rx(
+        slow_f128M_to_ui64, qemu_f128M_to_ui64, roundingMode, exact);
+        break;
+    case F128_TO_I32:
+        test_a_f128_z_i32_rx(
+        slow_f128M_to_i32, qemu_f128M_to_i32, roundingMode, exact);
+        break;
+    case F128_TO_I64:
+        test_a_f128_z_i64_rx(
+        slow_f128M_to_i64, qemu_f128M_to_i64, roundingMode, exact);
+        break;
+    case F128_TO_UI32_R_MINMAG:
+        /* not implemented */
+        break;
+    case F128_TO_UI64_R_MINMAG:
+        /* not implemented */
+        break;
+    case F128_TO_I32_R_MINMAG:
+        /* not implemented */
+        break;
+    case F128_TO_I64_R_MINMAG:
+        /* not implemented */
+        break;
+    case F128_TO_F16:
+        /* not implemented */
+        break;
+    case F128_TO_F32:
+        test_a_f128_z_f32(slow_f128M_to_f32, qemu_f128M_to_f32);
+        break;
+    case F128_TO_F64:
+        test_a_f128_z_f64(slow_f128M_to_f64, qemu_f128M_to_f64);
+        break;
+    case F128_TO_EXTF80:
+        test_a_f128_z_extF80(slow_f128M_to_extF80M, qemu_f128M_to_extF80M);
+        break;
+    case F128_ROUNDTOINT:
+        test_az_f128_rx(
+        slow_f128M_roundToInt, qemu_f128M_roundToInt, roundingMode, exact);
+        break;
+    case F128_ADD:
+        trueFunction_abz_f128M = slow_f128M_add;
+        subjFunction_abz_f128M = qemu_f128M_add;
+        goto test_abz_f128;
+    case F128_SUB:
+        trueFunction_abz_f128M = slow_f128M_sub;
+        subjFunction_abz_f128M = qemu_f128M_sub;
+        goto test_abz_f128;
+    case F128_MUL:
+        trueFunction_abz_f128M = slow_f128M_mul;
+        subjFunction_abz_f128M = qemu_f128M_mul;
+        goto test_abz_f128;
+    case F128_DIV:
+        trueFunction_abz_f128M = slow_f128M_div;
+        subjFunction_abz_f128M = qemu_f128M_div;
+        goto test_abz_f128;
+    case F128_REM:
+        trueFunction_abz_f128M = slow_f128M_rem;
+        subjFunction_abz_f128M = qemu_f128M_rem;
+    test_abz_f128:
+        test_abz_f128(trueFunction_abz_f128M, subjFunction_abz_f128M);
+        break;
+    case F128_MULADD:
+        /* not implemented */
+        break;
+    case F128_SQRT:
+        test_az_f128(slow_f128M_sqrt, qemu_f128M_sqrt);
+        break;
+    case F128_EQ:
+        trueFunction_ab_f128M_z_bool = slow_f128M_eq;
+        subjFunction_ab_f128M_z_bool = qemu_f128M_eq;
+        goto test_ab_f128_z_bool;
+    case F128_LE:
+        trueFunction_ab_f128M_z_bool = slow_f128M_le;
+        subjFunction_ab_f128M_z_bool = qemu_f128M_le;
+        goto test_ab_f128_z_bool;
+    case F128_LT:
+        trueFunction_ab_f128M_z_bool = slow_f128M_lt;
+        subjFunction_ab_f128M_z_bool = qemu_f128M_lt;
+        goto test_ab_f128_z_bool;
+    case F128_EQ_SIGNALING:
+        trueFunction_ab_f128M_z_bool = slow_f128M_eq_signaling;
+        subjFunction_ab_f128M_z_bool = qemu_f128M_eq_signaling;
+        goto test_ab_f128_z_bool;
+    case F128_LE_QUIET:
+        trueFunction_ab_f128M_z_bool = slow_f128M_le_quiet;
+        subjFunction_ab_f128M_z_bool = qemu_f128M_le_quiet;
+        goto test_ab_f128_z_bool;
+    case F128_LT_QUIET:
+        trueFunction_ab_f128M_z_bool = slow_f128M_lt_quiet;
+        subjFunction_ab_f128M_z_bool = qemu_f128M_lt_quiet;
+    test_ab_f128_z_bool:
+        test_ab_f128_z_bool(
+        trueFunction_ab_f128M_z_bool, subjFunction_ab_f128M_z_bool);
+        break;
+    }
+    if ((verCases_errorStop && verCases_anyErrors) || verCases_stop) {
+        verCases_exitWithStatus();
+    }
+}
+
+static void
+testFunction(int functionCode, uint_fast8_t roundingPrecisionIn,
+             int roundingCodeIn, int tininessCodeIn, int exactCodeIn)
+{
+    int functionAttribs;
+    uint_fast8_t roundingPrecision;
+    int roundingCode;
+    uint_fast8_t roundingMode = { 0 };
+    int exactCode;
+    bool exact;
+    int tininessCode;
+    uint_fast8_t tininessMode;
+
+    functionAttribs = functionInfos[functionCode].attribs;
+    verCases_functionNamePtr = functionInfos[functionCode].namePtr;
+    roundingPrecision = 32;
+    for (;;) {
+        if (functionAttribs & FUNC_EFF_ROUNDINGPRECISION) {
+            if (roundingPrecisionIn) {
+                roundingPrecision = roundingPrecisionIn;
+            }
+        } else {
+            roundingPrecision = 0;
+        }
+        verCases_roundingPrecision = roundingPrecision;
+        if (roundingPrecision) {
+            slow_extF80_roundingPrecision = roundingPrecision;
+            qsf.floatx80_rounding_precision = roundingPrecision;
+        }
+        /* XXX: not testing ROUND_ODD */
+        for (roundingCode = 1; roundingCode < NUM_ROUNDINGMODES - 1;
+             ++roundingCode) {
+            if (
+                functionAttribs
+                & (FUNC_ARG_ROUNDINGMODE | FUNC_EFF_ROUNDINGMODE)
+                ) {
+                if (roundingCodeIn) {
+                    roundingCode = roundingCodeIn;
+                }
+            } else {
+                roundingCode = 0;
+            }
+            verCases_roundingCode = roundingCode;
+            if (roundingCode) {
+                roundingMode = roundingModes[roundingCode];
+                if (functionAttribs & FUNC_EFF_ROUNDINGMODE) {
+                    slowfloat_roundingMode = roundingMode;
+                    qsf.float_rounding_mode =
+                        softfloat_rounding_to_qemu(roundingMode);
+                }
+            }
+            /*
+             * XXX not testing EXACT_FALSE
+             *   for (exactCode = EXACT_FALSE; exactCode <= EXACT_TRUE;
+             *   ++exactCode)
+             */
+            exactCode = EXACT_TRUE;
+            {
+                if (functionAttribs & FUNC_ARG_EXACT) {
+                    if (exactCodeIn) {
+                        exactCode = exactCodeIn;
+                    }
+                } else {
+                    exactCode = 0;
+                }
+                exact = (exactCode == EXACT_TRUE);
+                verCases_usesExact = (exactCode != 0);
+                verCases_exact = exact;
+                for (
+                    tininessCode = 1;
+                    tininessCode < NUM_TININESSMODES;
+                    ++tininessCode
+                    ) {
+                    if (
+                        (functionAttribs & FUNC_EFF_TININESSMODE)
+                        || ((functionAttribs
+                             & FUNC_EFF_TININESSMODE_REDUCEDPREC)
+                            && roundingPrecision
+                            && (roundingPrecision < 80))
+                        ) {
+                        if (tininessCodeIn) {
+                            tininessCode = tininessCodeIn;
+                        }
+                    } else {
+                        tininessCode = 0;
+                    }
+                    verCases_tininessCode = tininessCode;
+                    if (tininessCode) {
+                        tininessMode = tininessModes[tininessCode];
+                        slowfloat_detectTininess = tininessMode;
+                        qsf.float_detect_tininess =
+                            softfloat_tininess_to_qemu(tininessMode);
+                    }
+                    testFunctionInstance(functionCode, roundingMode, exact);
+                    if (tininessCodeIn || !tininessCode) {
+                        break;
+                    }
+                }
+                if (exactCodeIn || !exactCode) {
+                    break;
+                }
+            }
+            if (roundingCodeIn || !roundingCode) {
+                break;
+            }
+        }
+        if (roundingPrecisionIn || !roundingPrecision) {
+            break;
+        }
+        if (roundingPrecision == 80) {
+            break;
+        } else if (roundingPrecision == 64) {
+            roundingPrecision = 80;
+        } else if (roundingPrecision == 32) {
+            roundingPrecision = 64;
+        }
+    }
+
+}
+
+int main(int argc, char *argv[])
+{
+    bool haveFunctionArg;
+    int functionCode, numOperands;
+    uint_fast8_t roundingPrecision;
+    int roundingCode, tininessCode, exactCode;
+    const char *argPtr;
+    unsigned long ui;
+    long i;
+    int functionMatchAttrib;
+    struct sigaction sigact;
+
+    /*------------------------------------------------------------------------
+     *------------------------------------------------------------------------*/
+    fail_programName = (char *)"fp-test";
+    if (argc <= 1) {
+        goto writeHelpMessage;
+    }
+    genCases_setLevel(1);
+    verCases_maxErrorCount = 20;
+    testLoops_trueFlagsPtr = &slowfloat_exceptionFlags;
+    testLoops_subjFlagsFunction = qemu_softfloat_clearExceptionFlags;
+    haveFunctionArg = false;
+    functionCode = 0;
+    numOperands = 0;
+    roundingPrecision = 0;
+    roundingCode = 0;
+    tininessCode = 0;
+    exactCode = 0;
+    for (;;) {
+        --argc;
+        if (!argc) {
+            break;
+        }
+        argPtr = *++argv;
+        if (!argPtr) {
+            break;
+        }
+        if (argPtr[0] == '-') {
+            ++argPtr;
+        }
+        if (
+            !strcmp(argPtr, "help") || !strcmp(argPtr, "-help")
+            || !strcmp(argPtr, "h")
+            ) {
+        writeHelpMessage:
+            fputs(
+                "fp-test [<option>...] <function>\n"
+                "  <option>:  (* is default)\n"
+                "    -help            --Write this message and exit.\n"
+                "    -seed <num>      --Set pseudo-random number generator seed to <num>.\n"
+                " *  -seed 1\n"
+                "    -level <num>     --Testing level <num> (1 or 2).\n"
+                " *  -level 1\n"
+                "    -errors <num>    --Stop each function test after <num> errors.\n"
+                " *  -errors 20\n"
+                "    -errorstop       --Exit after first function with any error.\n"
+                "    -forever         --Test one function repeatedly (implies '-level 2').\n"
+                "    -precision32     --For extF80, test only 32-bit rounding precision.\n"
+                "    -precision64     --For extF80, test only 64-bit rounding precision.\n"
+                "    -precision80     --For extF80, test only 80-bit rounding precision.\n"
+                "    -rnear_even      --Test only rounding to nearest/even.\n"
+                "    -rminMag         --Test only rounding to minimum magnitude (toward zero).\n"
+                "    -rmin            --Test only rounding to minimum (down).\n"
+                "    -rmax            --Test only rounding to maximum (up).\n"
+                "    -rnear_maxMag    --Test only rounding to nearest/maximum magnitude\n"
+                "                         (nearest/away).\n"
+                "    -rodd            --Test only rounding to odd (jamming).  (For rounding to\n"
+                "                         an integer value, 'minMag' rounding is done instead.)\n"
+                "    -tininessbefore  --Test only underflow tininess detected before rounding.\n"
+                "    -tininessafter   --Test only underflow tininess detected after rounding.\n"
+                "    -notexact        --Test only non-exact rounding to integer (no inexact\n"
+                "                         exceptions).\n"
+                "    -exact           --Test only exact rounding to integer (raising inexact\n"
+                "                         exceptions).\n"
+                "  <function>:\n"
+                "    <int>_to_<float>            <float>_add      <float>_eq\n"
+                "    <float>_to_<int>            <float>_sub      <float>_le\n"
+                "    <float>_to_<int>_r_minMag   <float>_mul      <float>_lt\n"
+                "    <float>_to_<float>          <float>_mulAdd   <float>_eq_signaling\n"
+                "    <float>_roundToInt          <float>_div      <float>_le_quiet\n"
+                "                                <float>_rem      <float>_lt_quiet\n"
+                "                                <float>_sqrt\n"
+                "    -all1            --All unary functions.\n"
+                "    -all2            --All binary functions.\n"
+                "  <int>:\n"
+                "    ui32             --Unsigned 32-bit integer.\n"
+                "    ui64             --Unsigned 64-bit integer.\n"
+                "    i32              --Signed 32-bit integer.\n"
+                "    i64              --Signed 64-bit integer.\n"
+                "  <float>:\n"
+                "    f16              --Binary 16-bit floating-point (half-precision).\n"
+                "    f32              --Binary 32-bit floating-point (single-precision).\n"
+                "    f64              --Binary 64-bit floating-point (double-precision).\n"
+                "    extF80           --Binary 80-bit extended floating-point.\n"
+                "    f128             --Binary 128-bit floating-point (quadruple-precision).\n"
+                ,
+                stdout
+                );
+            return EXIT_SUCCESS;
+        } else if (!strcmp(argPtr, "seed")) {
+            if (argc < 2) {
+                goto optionError;
+            }
+            if (qemu_strtoul(argv[1], &argPtr, 10, &ui)) {
+                goto optionError;
+            }
+            if (*argPtr) {
+                goto optionError;
+            }
+            srand(ui);
+            --argc;
+            ++argv;
+        } else if (!strcmp(argPtr, "level")) {
+            if (argc < 2) {
+                goto optionError;
+            }
+            if (qemu_strtol(argv[1], &argPtr, 10, &i)) {
+                goto optionError;
+            }
+            if (*argPtr) {
+                goto optionError;
+            }
+            genCases_setLevel(i);
+            --argc;
+            ++argv;
+        } else if (!strcmp(argPtr, "level1")) {
+            genCases_setLevel(1);
+        } else if (!strcmp(argPtr, "level2")) {
+            genCases_setLevel(2);
+        } else if (!strcmp(argPtr, "errors")) {
+            if (argc < 2) {
+                goto optionError;
+            }
+            if (qemu_strtol(argv[1], &argPtr, 10, &i)) {
+                goto optionError;
+            }
+            if (*argPtr) {
+                goto optionError;
+            }
+            verCases_maxErrorCount = i;
+            --argc;
+            ++argv;
+        } else if (!strcmp(argPtr, "errorstop")) {
+            verCases_errorStop = true;
+        } else if (!strcmp(argPtr, "forever")) {
+            genCases_setLevel(2);
+            testLoops_forever = true;
+        } else if (!strcmp(argPtr, "precision32")) {
+            roundingPrecision = 32;
+        } else if (!strcmp(argPtr, "precision64")) {
+            roundingPrecision = 64;
+        } else if (!strcmp(argPtr, "precision80")) {
+            roundingPrecision = 80;
+        } else if (
+            !strcmp(argPtr, "rnear_even")
+            || !strcmp(argPtr, "rneareven")
+            || !strcmp(argPtr, "rnearest_even")
+            ) {
+            roundingCode = ROUND_NEAR_EVEN;
+        } else if (
+            !strcmp(argPtr, "rminmag") || !strcmp(argPtr, "rminMag")
+            ) {
+            roundingCode = ROUND_MINMAG;
+        } else if (!strcmp(argPtr, "rmin")) {
+            roundingCode = ROUND_MIN;
+        } else if (!strcmp(argPtr, "rmax")) {
+            roundingCode = ROUND_MAX;
+        } else if (
+            !strcmp(argPtr, "rnear_maxmag")
+            || !strcmp(argPtr, "rnear_maxMag")
+            || !strcmp(argPtr, "rnearmaxmag")
+            || !strcmp(argPtr, "rnearest_maxmag")
+            || !strcmp(argPtr, "rnearest_maxMag")
+            ) {
+            roundingCode = ROUND_NEAR_MAXMAG;
+        } else if (!strcmp(argPtr, "rodd")) {
+            roundingCode = ROUND_ODD;
+        } else if (!strcmp(argPtr, "tininessbefore")) {
+            tininessCode = TININESS_BEFORE_ROUNDING;
+        } else if (!strcmp(argPtr, "tininessafter")) {
+            tininessCode = TININESS_AFTER_ROUNDING;
+        } else if (!strcmp(argPtr, "notexact")) {
+            exactCode = EXACT_FALSE;
+        } else if (!strcmp(argPtr, "exact")) {
+            exactCode = EXACT_TRUE;
+        } else if (!strcmp(argPtr, "all1")) {
+            haveFunctionArg = true;
+            functionCode = 0;
+            numOperands = 1;
+        } else if (!strcmp(argPtr, "all2")) {
+            haveFunctionArg = true;
+            functionCode = 0;
+            numOperands = 2;
+        } else {
+            functionCode = 1;
+            while (strcmp(argPtr, functionInfos[functionCode].namePtr)) {
+                ++functionCode;
+                if (functionCode == NUM_FUNCTIONS) {
+                    fail("Invalid argument '%s'", *argv);
+                }
+            }
+            haveFunctionArg = true;
+        }
+    }
+    if (!haveFunctionArg) {
+        fail("Function argument required");
+    }
+    /*------------------------------------------------------------------------
+     *------------------------------------------------------------------------*/
+    sigact = (struct sigaction) {
+        .sa_handler = catchSIGINT,
+        .sa_flags = SA_RESETHAND | SA_NODEFER,
+    };
+    sigemptyset(&sigact.sa_mask);
+    sigaction(SIGINT, &sigact, NULL);
+    sigaction(SIGTERM, &sigact, NULL);
+    if (functionCode) {
+        if (testLoops_forever) {
+            if (!roundingPrecision) {
+                roundingPrecision = 80;
+            }
+            if (!roundingCode) {
+                roundingCode = ROUND_NEAR_EVEN;
+            }
+        }
+        testFunction(
+            functionCode,
+            roundingPrecision,
+            roundingCode,
+            tininessCode,
+            exactCode
+            );
+    } else {
+        if (testLoops_forever) {
+            fail("Can test only one function with '-forever' option");
+        }
+        functionMatchAttrib =
+            (numOperands == 1) ? FUNC_ARG_UNARY : FUNC_ARG_BINARY;
+        for (
+            functionCode = 1; functionCode < NUM_FUNCTIONS; ++functionCode
+            ) {
+            if (functionInfos[functionCode].attribs & functionMatchAttrib) {
+                testFunction(
+                    functionCode,
+                    roundingPrecision,
+                    roundingCode,
+                    tininessCode,
+                    exactCode
+                    );
+            }
+        }
+    }
+    verCases_exitWithStatus();
+    /*------------------------------------------------------------------------
+     *------------------------------------------------------------------------*/
+ optionError:
+    fail("'%s' option requires numeric argument", *argv);
+    return 1;
+}
diff --git a/tests/fp/wrap.inc.c b/tests/fp/wrap.inc.c
new file mode 100644
index 0000000000..5d1edc96c9
--- /dev/null
+++ b/tests/fp/wrap.inc.c
@@ -0,0 +1,600 @@
+/* wrap QEMU softfloat functions to mimic those in upstream softfloat */
+
+/* qemu softfloat status */
+static float_status qsf;
+
+static signed char softfloat_tininess_to_qemu(uint_fast8_t mode)
+{
+    switch (mode) {
+    case softfloat_tininess_beforeRounding:
+        return float_tininess_before_rounding;
+    case softfloat_tininess_afterRounding:
+        return float_tininess_after_rounding;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static signed char softfloat_rounding_to_qemu(uint_fast8_t mode)
+{
+    switch (mode) {
+    case softfloat_round_near_even:
+        return float_round_nearest_even;
+    case softfloat_round_minMag:
+        return float_round_to_zero;
+    case softfloat_round_min:
+        return float_round_down;
+    case softfloat_round_max:
+        return float_round_up;
+    case softfloat_round_near_maxMag:
+        return float_round_ties_away;
+    case softfloat_round_odd:
+        return float_round_to_odd;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static uint_fast8_t qemu_flags_to_softfloat(uint8_t qflags)
+{
+    uint_fast8_t ret = 0;
+
+    if (qflags & float_flag_invalid) {
+        ret |= softfloat_flag_invalid;
+    }
+    if (qflags & float_flag_divbyzero) {
+        ret |= softfloat_flag_infinite;
+    }
+    if (qflags & float_flag_overflow) {
+        ret |= softfloat_flag_overflow;
+    }
+    if (qflags & float_flag_underflow) {
+        ret |= softfloat_flag_underflow;
+    }
+    if (qflags & float_flag_inexact) {
+        ret |= softfloat_flag_inexact;
+    }
+    return ret;
+}
+
+static uint_fast8_t qemu_softfloat_clearExceptionFlags(void)
+{
+    uint_fast8_t prevFlags;
+
+    prevFlags = qemu_flags_to_softfloat(qsf.float_exception_flags);
+    qsf.float_exception_flags = 0;
+    return prevFlags;
+}
+
+/*
+ * softfloat/testfloat calls look very different from QEMU ones.
+ * With these macros we wrap the QEMU calls to look like softfloat/testfloat's,
+ * so that we can use the testfloat infrastructure as-is.
+ */
+
+static extFloat80_t qemu_to_soft80(floatx80 a)
+{
+    extFloat80_t ret;
+    void *p = &ret;
+
+    memcpy(p, &a.high, sizeof(a.high));
+    memcpy(p + 8, &a.low, sizeof(a.low));
+    return ret;
+}
+
+static floatx80 soft_to_qemu80(extFloat80_t a)
+{
+    floatx80 ret;
+    void *p = &a;
+
+    memcpy(&ret.high, p, sizeof(ret.high));
+    memcpy(&ret.low, p + 8, sizeof(ret.low));
+    return ret;
+}
+
+static float128_t qemu_to_soft128(float128 a)
+{
+    float128_t ret;
+    struct uint128 *to = (struct uint128 *)&ret;
+
+#ifdef HOST_WORDS_BIGENDIAN
+    to->v0 = a.low;
+    to->v64 = a.high;
+#else
+    to->v0 = a.high;
+    to->v64 = a.low;
+#endif
+    return ret;
+}
+
+static float128 soft_to_qemu128(float128_t a)
+{
+    struct uint128 *from = (struct uint128 *)&a;
+    float128 ret;
+
+#ifdef HOST_WORDS_BIGENDIAN
+    ret.low = from->v0;
+    ret.high = from->v64;
+#else
+    ret.high = from->v0;
+    ret.low = from->v64;
+#endif
+    return ret;
+}
+
+/* conversions */
+#define WRAP_SF_TO_SF_IEEE(name, func, a_type, b_type)  \
+    static b_type##_t name(a_type##_t a)                \
+    {                                                   \
+        a_type *ap = (a_type *)&a;                      \
+        b_type ret;                                     \
+                                                        \
+        ret = func(*ap, true, &qsf);                    \
+        return *(b_type##_t *)&ret;                     \
+    }
+
+WRAP_SF_TO_SF_IEEE(qemu_f16_to_f32, float16_to_float32, float16, float32)
+WRAP_SF_TO_SF_IEEE(qemu_f16_to_f64, float16_to_float64, float16, float64)
+
+WRAP_SF_TO_SF_IEEE(qemu_f32_to_f16, float32_to_float16, float32, float16)
+WRAP_SF_TO_SF_IEEE(qemu_f64_to_f16, float64_to_float16, float64, float16)
+#undef WRAP_SF_TO_SF_IEEE
+
+#define WRAP_SF_TO_SF(name, func, a_type, b_type)       \
+    static b_type##_t name(a_type##_t a)                \
+    {                                                   \
+        a_type *ap = (a_type *)&a;                      \
+        b_type ret;                                     \
+                                                        \
+        ret = func(*ap, &qsf);                          \
+        return *(b_type##_t *)&ret;                     \
+    }
+
+WRAP_SF_TO_SF(qemu_f32_to_f64, float32_to_float64, float32, float64)
+WRAP_SF_TO_SF(qemu_f64_to_f32, float64_to_float32, float64, float32)
+#undef WRAP_SF_TO_SF
+
+#define WRAP_SF_TO_80(name, func, type)                 \
+    static void name(type##_t a, extFloat80_t *res)     \
+    {                                                   \
+        floatx80 ret;                                   \
+        type *ap = (type *)&a;                          \
+                                                        \
+        ret = func(*ap, &qsf);                          \
+        *res = qemu_to_soft80(ret);                     \
+    }
+
+WRAP_SF_TO_80(qemu_f32_to_extF80M, float32_to_floatx80, float32)
+WRAP_SF_TO_80(qemu_f64_to_extF80M, float64_to_floatx80, float64)
+#undef WRAP_SF_TO_80
+
+#define WRAP_SF_TO_128(name, func, type)                \
+    static void name(type##_t a, float128_t *res)       \
+    {                                                   \
+        float128 ret;                                   \
+        type *ap = (type *)&a;                          \
+                                                        \
+        ret = func(*ap, &qsf);                          \
+        *res = qemu_to_soft128(ret);                    \
+    }
+
+WRAP_SF_TO_128(qemu_f32_to_f128M, float32_to_float128, float32)
+WRAP_SF_TO_128(qemu_f64_to_f128M, float64_to_float128, float64)
+#undef WRAP_SF_TO_128
+
+/* Note: exact is ignored since qemu's softfloat assumes it is set */
+#define WRAP_SF_TO_INT(name, scalfunc, type, int_type, fast_type)       \
+    static fast_type name(type##_t a, uint_fast8_t round, bool exact)   \
+    {                                                                   \
+        type *ap = (type *)&a;                                          \
+        int r = softfloat_rounding_to_qemu(round);                      \
+                                                                        \
+        return scalfunc(*ap, r, 0, &qsf);                               \
+    }
+
+WRAP_SF_TO_INT(qemu_f16_to_ui32, float16_to_uint32_scalbn, float16, uint32_t,
+               uint_fast32_t)
+WRAP_SF_TO_INT(qemu_f16_to_ui64, float16_to_uint64_scalbn, float16, uint64_t,
+               uint_fast64_t)
+
+WRAP_SF_TO_INT(qemu_f32_to_ui32, float32_to_uint32_scalbn, float32, uint32_t,
+               uint_fast32_t)
+WRAP_SF_TO_INT(qemu_f32_to_ui64, float32_to_uint64_scalbn, float32, uint64_t,
+               uint_fast64_t)
+
+WRAP_SF_TO_INT(qemu_f64_to_ui32, float64_to_uint32_scalbn, float64, uint32_t,
+               uint_fast32_t)
+WRAP_SF_TO_INT(qemu_f64_to_ui64, float64_to_uint64_scalbn, float64, uint64_t,
+               uint_fast64_t)
+
+WRAP_SF_TO_INT(qemu_f16_to_i32, float16_to_int32_scalbn, float16, int32_t,
+               int_fast32_t)
+WRAP_SF_TO_INT(qemu_f16_to_i64, float16_to_int64_scalbn, float16, int64_t,
+               int_fast64_t)
+
+WRAP_SF_TO_INT(qemu_f32_to_i32, float32_to_int32_scalbn, float32, int32_t,
+               int_fast32_t)
+WRAP_SF_TO_INT(qemu_f32_to_i64, float32_to_int64_scalbn, float32, int64_t,
+               int_fast64_t)
+
+WRAP_SF_TO_INT(qemu_f64_to_i32, float64_to_int32_scalbn, float64, int32_t,
+               int_fast32_t)
+WRAP_SF_TO_INT(qemu_f64_to_i64, float64_to_int64_scalbn, float64, int64_t,
+               int_fast64_t)
+#undef WRAP_SF_TO_INT
+
+#define WRAP_80_TO_SF(name, func, type)                 \
+    static type##_t name(const extFloat80_t *ap)        \
+    {                                                   \
+        floatx80 a;                                     \
+        type ret;                                       \
+                                                        \
+        a = soft_to_qemu80(*ap);                        \
+        ret = func(a, &qsf);                            \
+        return *(type##_t *)&ret;                       \
+    }
+
+WRAP_80_TO_SF(qemu_extF80M_to_f32, floatx80_to_float32, float32)
+WRAP_80_TO_SF(qemu_extF80M_to_f64, floatx80_to_float64, float64)
+#undef WRAP_80_TO_SF
+
+#define WRAP_128_TO_SF(name, func, type)                \
+    static type##_t name(const float128_t *ap)          \
+    {                                                   \
+        float128 a;                                     \
+        type ret;                                       \
+                                                        \
+        a = soft_to_qemu128(*ap);                       \
+        ret = func(a, &qsf);                            \
+        return *(type##_t *)&ret;                       \
+    }
+
+WRAP_128_TO_SF(qemu_f128M_to_f32, float128_to_float32, float32)
+WRAP_128_TO_SF(qemu_f128M_to_f64, float128_to_float64, float64)
+#undef WRAP_80_TO_SF
+
+static void qemu_extF80M_to_f128M(const extFloat80_t *from, float128_t *to)
+{
+    floatx80 qfrom;
+    float128 qto;
+
+    qfrom = soft_to_qemu80(*from);
+    qto = floatx80_to_float128(qfrom, &qsf);
+    *to = qemu_to_soft128(qto);
+}
+
+static void qemu_f128M_to_extF80M(const float128_t *from, extFloat80_t *to)
+{
+    float128 qfrom;
+    floatx80 qto;
+
+    qfrom = soft_to_qemu128(*from);
+    qto = float128_to_floatx80(qfrom, &qsf);
+    *to = qemu_to_soft80(qto);
+}
+
+#define WRAP_INT_TO_SF(name, func, int_type, type)      \
+    static type##_t name(int_type a)                    \
+    {                                                   \
+        type ret;                                       \
+                                                        \
+        ret = func(a, &qsf);                            \
+        return *(type##_t *)&ret;                       \
+    }
+
+WRAP_INT_TO_SF(qemu_ui32_to_f16, uint32_to_float16, uint32_t, float16)
+WRAP_INT_TO_SF(qemu_ui32_to_f32, uint32_to_float32, uint32_t, float32)
+WRAP_INT_TO_SF(qemu_ui32_to_f64, uint32_to_float64, uint32_t, float64)
+
+WRAP_INT_TO_SF(qemu_ui64_to_f16, uint64_to_float16, uint64_t, float16)
+WRAP_INT_TO_SF(qemu_ui64_to_f32, uint64_to_float32, uint64_t, float32)
+WRAP_INT_TO_SF(qemu_ui64_to_f64, uint64_to_float64, uint64_t, float64)
+
+WRAP_INT_TO_SF(qemu_i32_to_f16, int32_to_float16, int32_t, float16)
+WRAP_INT_TO_SF(qemu_i32_to_f32, int32_to_float32, int32_t, float32)
+WRAP_INT_TO_SF(qemu_i32_to_f64, int32_to_float64, int32_t, float64)
+
+WRAP_INT_TO_SF(qemu_i64_to_f16, int64_to_float16, int64_t, float16)
+WRAP_INT_TO_SF(qemu_i64_to_f32, int64_to_float32, int64_t, float32)
+WRAP_INT_TO_SF(qemu_i64_to_f64, int64_to_float64, int64_t, float64)
+#undef WRAP_INT_TO_SF
+
+#define WRAP_INT_TO_80(name, func, int_type)            \
+    static void name(int_type a, extFloat80_t *res)     \
+    {                                                   \
+        floatx80 ret;                                   \
+                                                        \
+        ret = func(a, &qsf);                            \
+        *res = qemu_to_soft80(ret);                     \
+    }
+
+WRAP_INT_TO_80(qemu_i32_to_extF80M, int32_to_floatx80, int32_t)
+WRAP_INT_TO_80(qemu_i64_to_extF80M, int64_to_floatx80, int64_t)
+#undef WRAP_INT_TO_80
+
+/* Note: exact is ignored since qemu's softfloat assumes it is set */
+#define WRAP_80_TO_INT(name, func, int_type, fast_type)                 \
+    static fast_type name(const extFloat80_t *ap, uint_fast8_t round,   \
+                          bool exact)                                   \
+    {                                                                   \
+        floatx80 a;                                                     \
+        int_type ret;                                                   \
+                                                                        \
+        a = soft_to_qemu80(*ap);                                        \
+        qsf.float_rounding_mode = softfloat_rounding_to_qemu(round);    \
+        ret = func(a, &qsf);                                            \
+        return ret;                                                     \
+    }
+
+WRAP_80_TO_INT(qemu_extF80M_to_i32, floatx80_to_int32, int32_t, int_fast32_t)
+WRAP_80_TO_INT(qemu_extF80M_to_i64, floatx80_to_int64, int64_t, int_fast64_t)
+#undef WRAP_80_TO_INT
+
+/* Note: exact is ignored since qemu's softfloat assumes it is set */
+#define WRAP_128_TO_INT(name, func, int_type, fast_type)                \
+    static fast_type name(const float128_t *ap, uint_fast8_t round,     \
+                          bool exact)                                   \
+    {                                                                   \
+        float128 a;                                                     \
+        int_type ret;                                                   \
+                                                                        \
+        a = soft_to_qemu128(*ap);                                       \
+        qsf.float_rounding_mode = softfloat_rounding_to_qemu(round);    \
+        ret = func(a, &qsf);                                            \
+        return ret;                                                     \
+    }
+
+WRAP_128_TO_INT(qemu_f128M_to_i32, float128_to_int32, int32_t, int_fast32_t)
+WRAP_128_TO_INT(qemu_f128M_to_i64, float128_to_int64, int64_t, int_fast64_t)
+
+WRAP_128_TO_INT(qemu_f128M_to_ui64, float128_to_uint64, uint64_t, uint_fast64_t)
+#undef WRAP_80_TO_INT
+
+#define WRAP_INT_TO_128(name, func, int_type)           \
+    static void name(int_type a, float128_t *res)       \
+    {                                                   \
+        float128 ret;                                   \
+                                                        \
+        ret = func(a, &qsf);                            \
+        *res = qemu_to_soft128(ret);                    \
+    }
+
+WRAP_INT_TO_128(qemu_ui64_to_f128M, uint64_to_float128, uint64_t)
+
+WRAP_INT_TO_128(qemu_i32_to_f128M, int32_to_float128, int32_t)
+WRAP_INT_TO_128(qemu_i64_to_f128M, int64_to_float128, int64_t)
+#undef WRAP_INT_TO_128
+
+/* Note: exact is ignored since qemu's softfloat assumes it is set */
+#define WRAP_ROUND_TO_INT(name, func, type)                             \
+    static type##_t name(type##_t a, uint_fast8_t round, bool exact)    \
+    {                                                                   \
+        type *ap = (type *)&a;                                          \
+        type ret;                                                       \
+                                                                        \
+        qsf.float_rounding_mode = softfloat_rounding_to_qemu(round);    \
+        ret = func(*ap, &qsf);                                          \
+        return *(type##_t *)&ret;                                       \
+    }
+
+WRAP_ROUND_TO_INT(qemu_f16_roundToInt, float16_round_to_int, float16)
+WRAP_ROUND_TO_INT(qemu_f32_roundToInt, float32_round_to_int, float32)
+WRAP_ROUND_TO_INT(qemu_f64_roundToInt, float64_round_to_int, float64)
+#undef WRAP_ROUND_TO_INT
+
+static void qemu_extF80M_roundToInt(const extFloat80_t *ap, uint_fast8_t round,
+                                    bool exact, extFloat80_t *res)
+{
+    floatx80 a;
+    floatx80 ret;
+
+    a = soft_to_qemu80(*ap);
+    qsf.float_rounding_mode = softfloat_rounding_to_qemu(round);
+    ret = floatx80_round_to_int(a, &qsf);
+    *res = qemu_to_soft80(ret);
+}
+
+static void qemu_f128M_roundToInt(const float128_t *ap, uint_fast8_t round,
+                                  bool exact, float128_t *res)
+{
+    float128 a;
+    float128 ret;
+
+    a = soft_to_qemu128(*ap);
+    qsf.float_rounding_mode = softfloat_rounding_to_qemu(round);
+    ret = float128_round_to_int(a, &qsf);
+    *res = qemu_to_soft128(ret);
+}
+
+/* operations */
+#define WRAP1(name, func, type)                 \
+    static type##_t name(type##_t a)            \
+    {                                           \
+        type *ap = (type *)&a;                  \
+        type ret;                               \
+                                                \
+        ret = func(*ap, &qsf);                  \
+        return *(type##_t *)&ret;               \
+    }
+
+#define WRAP2(name, func, type)                         \
+    static type##_t name(type##_t a, type##_t b)        \
+    {                                                   \
+        type *ap = (type *)&a;                          \
+        type *bp = (type *)&b;                          \
+        type ret;                                       \
+                                                        \
+        ret = func(*ap, *bp, &qsf);                     \
+        return *(type##_t *)&ret;                       \
+    }
+
+#define WRAP_COMMON_OPS(b)                              \
+    WRAP1(qemu_f##b##_sqrt, float##b##_sqrt, float##b)  \
+    WRAP2(qemu_f##b##_add, float##b##_add, float##b)    \
+    WRAP2(qemu_f##b##_sub, float##b##_sub, float##b)    \
+    WRAP2(qemu_f##b##_mul, float##b##_mul, float##b)    \
+    WRAP2(qemu_f##b##_div, float##b##_div, float##b)
+
+WRAP_COMMON_OPS(16)
+WRAP_COMMON_OPS(32)
+WRAP_COMMON_OPS(64)
+#undef WRAP_COMMON
+
+WRAP2(qemu_f32_rem, float32_rem, float32)
+WRAP2(qemu_f64_rem, float64_rem, float64)
+#undef WRAP2
+#undef WRAP1
+
+#define WRAP1_80(name, func)                                    \
+    static void name(const extFloat80_t *ap, extFloat80_t *res) \
+    {                                                           \
+        floatx80 a;                                             \
+        floatx80 ret;                                           \
+                                                                \
+        a = soft_to_qemu80(*ap);                                \
+        ret = func(a, &qsf);                                    \
+        *res = qemu_to_soft80(ret);                             \
+    }
+
+WRAP1_80(qemu_extF80M_sqrt, floatx80_sqrt)
+#undef WRAP1_80
+
+#define WRAP1_128(name, func)                                   \
+    static void name(const float128_t *ap, float128_t *res)     \
+    {                                                           \
+        float128 a;                                             \
+        float128 ret;                                           \
+                                                                \
+        a = soft_to_qemu128(*ap);                               \
+        ret = func(a, &qsf);                                    \
+        *res = qemu_to_soft128(ret);                            \
+    }
+
+WRAP1_128(qemu_f128M_sqrt, float128_sqrt)
+#undef WRAP1_128
+
+#define WRAP2_80(name, func)                                            \
+    static void name(const extFloat80_t *ap, const extFloat80_t *bp,    \
+                     extFloat80_t *res)                                 \
+    {                                                                   \
+        floatx80 a;                                                     \
+        floatx80 b;                                                     \
+        floatx80 ret;                                                   \
+                                                                        \
+        a = soft_to_qemu80(*ap);                                        \
+        b = soft_to_qemu80(*bp);                                        \
+        ret = func(a, b, &qsf);                                         \
+        *res = qemu_to_soft80(ret);                                     \
+    }
+
+WRAP2_80(qemu_extF80M_add, floatx80_add)
+WRAP2_80(qemu_extF80M_sub, floatx80_sub)
+WRAP2_80(qemu_extF80M_mul, floatx80_mul)
+WRAP2_80(qemu_extF80M_div, floatx80_div)
+WRAP2_80(qemu_extF80M_rem, floatx80_rem)
+#undef WRAP2_80
+
+#define WRAP2_128(name, func)                                           \
+    static void name(const float128_t *ap, const float128_t *bp,        \
+                     float128_t *res)                                   \
+    {                                                                   \
+        float128 a;                                                     \
+        float128 b;                                                     \
+        float128 ret;                                                   \
+                                                                        \
+        a = soft_to_qemu128(*ap);                                       \
+        b = soft_to_qemu128(*bp);                                       \
+        ret = func(a, b, &qsf);                                         \
+        *res = qemu_to_soft128(ret);                                    \
+    }
+
+WRAP2_128(qemu_f128M_add, float128_add)
+WRAP2_128(qemu_f128M_sub, float128_sub)
+WRAP2_128(qemu_f128M_mul, float128_mul)
+WRAP2_128(qemu_f128M_div, float128_div)
+WRAP2_128(qemu_f128M_rem, float128_rem)
+#undef WRAP2_128
+
+#define WRAP_MULADD(name, func, type)                           \
+    static type##_t name(type##_t a, type##_t b, type##_t c)    \
+    {                                                           \
+        type *ap = (type *)&a;                                  \
+        type *bp = (type *)&b;                                  \
+        type *cp = (type *)&c;                                  \
+        type ret;                                               \
+                                                                \
+        ret = func(*ap, *bp, *cp, 0, &qsf);                     \
+        return *(type##_t *)&ret;                               \
+    }
+
+WRAP_MULADD(qemu_f16_mulAdd, float16_muladd, float16)
+WRAP_MULADD(qemu_f32_mulAdd, float32_muladd, float32)
+WRAP_MULADD(qemu_f64_mulAdd, float64_muladd, float64)
+#undef WRAP_MULADD
+
+#define WRAP_CMP(name, func, type, retcond)     \
+    static bool name(type##_t a, type##_t b)    \
+    {                                           \
+        type *ap = (type *)&a;                  \
+        type *bp = (type *)&b;                  \
+        int ret;                                \
+                                                \
+        ret = func(*ap, *bp, &qsf);             \
+        return retcond;                         \
+    }
+
+#define GEN_WRAP_CMP(b)                                                      \
+WRAP_CMP(qemu_f##b##_eq_signaling, float##b##_compare, float##b, ret == 0)   \
+WRAP_CMP(qemu_f##b##_eq, float##b##_compare_quiet, float##b, ret == 0)       \
+WRAP_CMP(qemu_f##b##_le, float##b##_compare, float##b, ret <= 0)             \
+WRAP_CMP(qemu_f##b##_lt, float##b##_compare, float##b, ret < 0)              \
+WRAP_CMP(qemu_f##b##_le_quiet, float##b##_compare_quiet, float##b, ret <= 0) \
+WRAP_CMP(qemu_f##b##_lt_quiet, float##b##_compare_quiet, float##b, ret < 0)
+
+GEN_WRAP_CMP(16)
+GEN_WRAP_CMP(32)
+GEN_WRAP_CMP(64)
+#undef GEN_WRAP_CMP
+#undef WRAP_CMP
+
+#define WRAP_CMP80(name, func, retcond)                                 \
+    static bool name(const extFloat80_t *ap, const extFloat80_t *bp)    \
+    {                                                                   \
+        floatx80 a;                                                     \
+        floatx80 b;                                                     \
+        int ret;                                                        \
+                                                                        \
+        a = soft_to_qemu80(*ap);                                        \
+        b = soft_to_qemu80(*bp);                                        \
+        ret = func(a, b, &qsf);                                         \
+        return retcond;                                                 \
+    }
+
+WRAP_CMP80(qemu_extF80M_eq_signaling, floatx80_compare, ret == 0)
+WRAP_CMP80(qemu_extF80M_eq, floatx80_compare_quiet, ret == 0)
+WRAP_CMP80(qemu_extF80M_le, floatx80_compare, ret <= 0)
+WRAP_CMP80(qemu_extF80M_lt, floatx80_compare, ret < 0)
+WRAP_CMP80(qemu_extF80M_le_quiet, floatx80_compare_quiet, ret <= 0)
+WRAP_CMP80(qemu_extF80M_lt_quiet, floatx80_compare_quiet, ret < 0)
+#undef WRAP_CMP80
+
+#define WRAP_CMP80(name, func, retcond)                                 \
+    static bool name(const float128_t *ap, const float128_t *bp)        \
+    {                                                                   \
+        float128 a;                                                     \
+        float128 b;                                                     \
+        int ret;                                                        \
+                                                                        \
+        a = soft_to_qemu128(*ap);                                       \
+        b = soft_to_qemu128(*bp);                                       \
+        ret = func(a, b, &qsf);                                         \
+        return retcond;                                                 \
+    }
+
+WRAP_CMP80(qemu_f128M_eq_signaling, float128_compare, ret == 0)
+WRAP_CMP80(qemu_f128M_eq, float128_compare_quiet, ret == 0)
+WRAP_CMP80(qemu_f128M_le, float128_compare, ret <= 0)
+WRAP_CMP80(qemu_f128M_lt, float128_compare, ret < 0)
+WRAP_CMP80(qemu_f128M_le_quiet, float128_compare_quiet, ret <= 0)
+WRAP_CMP80(qemu_f128M_lt_quiet, float128_compare_quiet, ret < 0)
+#undef WRAP_CMP80
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 87c81d1dcc..363f133101 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -657,6 +657,9 @@ tests/qht-bench$(EXESUF): tests/qht-bench.o $(test-util-obj-y)
 tests/test-bufferiszero$(EXESUF): tests/test-bufferiszero.o $(test-util-obj-y)
 tests/atomic_add-bench$(EXESUF): tests/atomic_add-bench.o $(test-util-obj-y)
 
+tests/fp/%:
+	$(MAKE) -C $(dir $@) $(notdir $@)
+
 tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
 	hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\
 	hw/core/bus.o \
diff --git a/tests/fp/.gitignore b/tests/fp/.gitignore
new file mode 100644
index 0000000000..8d45d18ac4
--- /dev/null
+++ b/tests/fp/.gitignore
@@ -0,0 +1 @@
+fp-test
diff --git a/tests/fp/Makefile b/tests/fp/Makefile
new file mode 100644
index 0000000000..2f9e58b649
--- /dev/null
+++ b/tests/fp/Makefile
@@ -0,0 +1,591 @@
+BUILD_DIR := $(CURDIR)/../..
+
+include $(BUILD_DIR)/config-host.mak
+include $(SRC_PATH)/rules.mak
+
+SOFTFLOAT_DIR := $(SRC_PATH)/tests/fp/berkeley-softfloat-3
+TESTFLOAT_DIR := $(SRC_PATH)/tests/fp/berkeley-testfloat-3
+
+SF_SOURCE_DIR  := $(SOFTFLOAT_DIR)/source
+SF_INCLUDE_DIR := $(SOFTFLOAT_DIR)/source/include
+# we could use any specialize here, it doesn't matter
+SF_SPECIALIZE := 8086-SSE
+SF_SPECIALIZE_DIR := $(SF_SOURCE_DIR)/$(SF_SPECIALIZE)
+
+TF_SOURCE_DIR := $(TESTFLOAT_DIR)/source
+
+$(call set-vpath, $(SRC_PATH)/fpu $(SRC_PATH)/tests/fp)
+
+LIBQEMUUTIL := $(BUILD_DIR)/libqemuutil.a
+
+# Use this variable to be clear when we pull in our own implementation
+# We build the object with a default rule thanks to the vpath above
+QEMU_SOFTFLOAT_OBJ := softfloat.o
+
+QEMU_INCLUDES += -I$(SRC_PATH)/tests/fp
+QEMU_INCLUDES += -I$(SF_INCLUDE_DIR)
+QEMU_INCLUDES += -I$(SF_SPECIALIZE_DIR)
+QEMU_INCLUDES += -I$(TF_SOURCE_DIR)
+
+# work around TARGET_* poisoning
+QEMU_CFLAGS += -DHW_POISON_H
+
+# capstone has a platform.h file that clashes with softfloat's
+QEMU_CFLAGS := $(filter-out %capstone, $(QEMU_CFLAGS))
+
+# softfloat defines
+SF_OPTS :=
+SF_OPTS += -DSOFTFLOAT_ROUND_ODD
+SF_OPTS += -DINLINE_LEVEL=5
+SF_OPTS += -DSOFTFLOAT_FAST_DIV32TO16
+SF_OPTS += -DSOFTFLOAT_FAST_DIV64TO32
+SF_OPTS += -DSOFTFLOAT_FAST_INT64
+QEMU_CFLAGS += $(SF_OPTS)
+
+# silence the build of softfloat objects
+SF_CFLAGS += -Wno-missing-prototypes
+SF_CFLAGS += -Wno-redundant-decls
+SF_CFLAGS += -Wno-return-type
+SF_CFLAGS += -Wno-error
+
+# testfloat defines
+TF_OPTS :=
+TF_OPTS += -DFLOAT16
+TF_OPTS += -DFLOAT64
+TF_OPTS += -DEXTFLOAT80
+TF_OPTS += -DFLOAT128
+TF_OPTS += -DFLOAT_ROUND_ODD
+TF_OPTS += -DLONG_DOUBLE_IS_EXTFLOAT80
+QEMU_CFLAGS += $(TF_OPTS)
+
+# silence the build of testfloat objects
+TF_CFLAGS :=
+TF_CFLAGS += -Wno-strict-prototypes
+TF_CFLAGS += -Wno-unknown-pragmas
+TF_CFLAGS += -Wno-discarded-qualifiers
+TF_CFLAGS += -Wno-maybe-uninitialized
+TF_CFLAGS += -Wno-missing-prototypes
+TF_CFLAGS += -Wno-return-type
+TF_CFLAGS += -Wno-unused-function
+TF_CFLAGS += -Wno-error
+
+# softfloat objects
+SF_OBJS_PRIMITIVES :=
+SF_OBJS_PRIMITIVES += s_eq128.o
+SF_OBJS_PRIMITIVES += s_le128.o
+SF_OBJS_PRIMITIVES += s_lt128.o
+SF_OBJS_PRIMITIVES += s_shortShiftLeft128.o
+SF_OBJS_PRIMITIVES += s_shortShiftRight128.o
+SF_OBJS_PRIMITIVES += s_shortShiftRightJam64.o
+SF_OBJS_PRIMITIVES += s_shortShiftRightJam64Extra.o
+SF_OBJS_PRIMITIVES += s_shortShiftRightJam128.o
+SF_OBJS_PRIMITIVES += s_shortShiftRightJam128Extra.o
+SF_OBJS_PRIMITIVES += s_shiftRightJam32.o
+SF_OBJS_PRIMITIVES += s_shiftRightJam64.o
+SF_OBJS_PRIMITIVES += s_shiftRightJam64Extra.o
+SF_OBJS_PRIMITIVES += s_shiftRightJam128.o
+SF_OBJS_PRIMITIVES += s_shiftRightJam128Extra.o
+SF_OBJS_PRIMITIVES += s_shiftRightJam256M.o
+SF_OBJS_PRIMITIVES += s_countLeadingZeros8.o
+SF_OBJS_PRIMITIVES += s_countLeadingZeros16.o
+SF_OBJS_PRIMITIVES += s_countLeadingZeros32.o
+SF_OBJS_PRIMITIVES += s_countLeadingZeros64.o
+SF_OBJS_PRIMITIVES += s_add128.o
+SF_OBJS_PRIMITIVES += s_add256M.o
+SF_OBJS_PRIMITIVES += s_sub128.o
+SF_OBJS_PRIMITIVES += s_sub256M.o
+SF_OBJS_PRIMITIVES += s_mul64ByShifted32To128.o
+SF_OBJS_PRIMITIVES += s_mul64To128.o
+SF_OBJS_PRIMITIVES += s_mul128By32.o
+SF_OBJS_PRIMITIVES += s_mul128To256M.o
+SF_OBJS_PRIMITIVES += s_approxRecip_1Ks.o
+SF_OBJS_PRIMITIVES += s_approxRecip32_1.o
+SF_OBJS_PRIMITIVES += s_approxRecipSqrt_1Ks.o
+SF_OBJS_PRIMITIVES += s_approxRecipSqrt32_1.o
+
+SF_OBJS_SPECIALIZE :=
+SF_OBJS_SPECIALIZE += softfloat_raiseFlags.o
+SF_OBJS_SPECIALIZE += s_f16UIToCommonNaN.o
+SF_OBJS_SPECIALIZE += s_commonNaNToF16UI.o
+SF_OBJS_SPECIALIZE += s_propagateNaNF16UI.o
+SF_OBJS_SPECIALIZE += s_f32UIToCommonNaN.o
+SF_OBJS_SPECIALIZE += s_commonNaNToF32UI.o
+SF_OBJS_SPECIALIZE += s_propagateNaNF32UI.o
+SF_OBJS_SPECIALIZE += s_f64UIToCommonNaN.o
+SF_OBJS_SPECIALIZE += s_commonNaNToF64UI.o
+SF_OBJS_SPECIALIZE += s_propagateNaNF64UI.o
+SF_OBJS_SPECIALIZE += extF80M_isSignalingNaN.o
+SF_OBJS_SPECIALIZE += s_extF80UIToCommonNaN.o
+SF_OBJS_SPECIALIZE += s_commonNaNToExtF80UI.o
+SF_OBJS_SPECIALIZE += s_propagateNaNExtF80UI.o
+SF_OBJS_SPECIALIZE += f128M_isSignalingNaN.o
+SF_OBJS_SPECIALIZE += s_f128UIToCommonNaN.o
+SF_OBJS_SPECIALIZE += s_commonNaNToF128UI.o
+SF_OBJS_SPECIALIZE += s_propagateNaNF128UI.o
+
+SF_OBJS_OTHERS :=
+SF_OBJS_OTHERS += s_roundToUI32.o
+SF_OBJS_OTHERS += s_roundToUI64.o
+SF_OBJS_OTHERS += s_roundToI32.o
+SF_OBJS_OTHERS += s_roundToI64.o
+SF_OBJS_OTHERS += s_normSubnormalF16Sig.o
+SF_OBJS_OTHERS += s_roundPackToF16.o
+SF_OBJS_OTHERS += s_normRoundPackToF16.o
+SF_OBJS_OTHERS += s_addMagsF16.o
+SF_OBJS_OTHERS += s_subMagsF16.o
+SF_OBJS_OTHERS += s_mulAddF16.o
+SF_OBJS_OTHERS += s_normSubnormalF32Sig.o
+SF_OBJS_OTHERS += s_roundPackToF32.o
+SF_OBJS_OTHERS += s_normRoundPackToF32.o
+SF_OBJS_OTHERS += s_addMagsF32.o
+SF_OBJS_OTHERS += s_subMagsF32.o
+SF_OBJS_OTHERS += s_mulAddF32.o
+SF_OBJS_OTHERS += s_normSubnormalF64Sig.o
+SF_OBJS_OTHERS += s_roundPackToF64.o
+SF_OBJS_OTHERS += s_normRoundPackToF64.o
+SF_OBJS_OTHERS += s_addMagsF64.o
+SF_OBJS_OTHERS += s_subMagsF64.o
+SF_OBJS_OTHERS += s_mulAddF64.o
+SF_OBJS_OTHERS += s_normSubnormalExtF80Sig.o
+SF_OBJS_OTHERS += s_roundPackToExtF80.o
+SF_OBJS_OTHERS += s_normRoundPackToExtF80.o
+SF_OBJS_OTHERS += s_addMagsExtF80.o
+SF_OBJS_OTHERS += s_subMagsExtF80.o
+SF_OBJS_OTHERS += s_normSubnormalF128Sig.o
+SF_OBJS_OTHERS += s_roundPackToF128.o
+SF_OBJS_OTHERS += s_normRoundPackToF128.o
+SF_OBJS_OTHERS += s_addMagsF128.o
+SF_OBJS_OTHERS += s_subMagsF128.o
+SF_OBJS_OTHERS += s_mulAddF128.o
+SF_OBJS_OTHERS += softfloat_state.o
+SF_OBJS_OTHERS += ui32_to_f16.o
+SF_OBJS_OTHERS += ui32_to_f32.o
+SF_OBJS_OTHERS += ui32_to_f64.o
+SF_OBJS_OTHERS += ui32_to_extF80.o
+SF_OBJS_OTHERS += ui32_to_extF80M.o
+SF_OBJS_OTHERS += ui32_to_f128.o
+SF_OBJS_OTHERS += ui32_to_f128M.o
+SF_OBJS_OTHERS += ui64_to_f16.o
+SF_OBJS_OTHERS += ui64_to_f32.o
+SF_OBJS_OTHERS += ui64_to_f64.o
+SF_OBJS_OTHERS += ui64_to_extF80.o
+SF_OBJS_OTHERS += ui64_to_extF80M.o
+SF_OBJS_OTHERS += ui64_to_f128.o
+SF_OBJS_OTHERS += ui64_to_f128M.o
+SF_OBJS_OTHERS += i32_to_f16.o
+SF_OBJS_OTHERS += i32_to_f32.o
+SF_OBJS_OTHERS += i32_to_f64.o
+SF_OBJS_OTHERS += i32_to_extF80.o
+SF_OBJS_OTHERS += i32_to_extF80M.o
+SF_OBJS_OTHERS += i32_to_f128.o
+SF_OBJS_OTHERS += i32_to_f128M.o
+SF_OBJS_OTHERS += i64_to_f16.o
+SF_OBJS_OTHERS += i64_to_f32.o
+SF_OBJS_OTHERS += i64_to_f64.o
+SF_OBJS_OTHERS += i64_to_extF80.o
+SF_OBJS_OTHERS += i64_to_extF80M.o
+SF_OBJS_OTHERS += i64_to_f128.o
+SF_OBJS_OTHERS += i64_to_f128M.o
+SF_OBJS_OTHERS += f16_to_ui32.o
+SF_OBJS_OTHERS += f16_to_ui64.o
+SF_OBJS_OTHERS += f16_to_i32.o
+SF_OBJS_OTHERS += f16_to_i64.o
+SF_OBJS_OTHERS += f16_to_ui32_r_minMag.o
+SF_OBJS_OTHERS += f16_to_ui64_r_minMag.o
+SF_OBJS_OTHERS += f16_to_i32_r_minMag.o
+SF_OBJS_OTHERS += f16_to_i64_r_minMag.o
+SF_OBJS_OTHERS += f16_to_f32.o
+SF_OBJS_OTHERS += f16_to_f64.o
+SF_OBJS_OTHERS += f16_to_extF80.o
+SF_OBJS_OTHERS += f16_to_extF80M.o
+SF_OBJS_OTHERS += f16_to_f128.o
+SF_OBJS_OTHERS += f16_to_f128M.o
+SF_OBJS_OTHERS += f16_roundToInt.o
+SF_OBJS_OTHERS += f16_add.o
+SF_OBJS_OTHERS += f16_sub.o
+SF_OBJS_OTHERS += f16_mul.o
+SF_OBJS_OTHERS += f16_mulAdd.o
+SF_OBJS_OTHERS += f16_div.o
+SF_OBJS_OTHERS += f16_rem.o
+SF_OBJS_OTHERS += f16_sqrt.o
+SF_OBJS_OTHERS += f16_eq.o
+SF_OBJS_OTHERS += f16_le.o
+SF_OBJS_OTHERS += f16_lt.o
+SF_OBJS_OTHERS += f16_eq_signaling.o
+SF_OBJS_OTHERS += f16_le_quiet.o
+SF_OBJS_OTHERS += f16_lt_quiet.o
+SF_OBJS_OTHERS += f16_isSignalingNaN.o
+SF_OBJS_OTHERS += f32_to_ui32.o
+SF_OBJS_OTHERS += f32_to_ui64.o
+SF_OBJS_OTHERS += f32_to_i32.o
+SF_OBJS_OTHERS += f32_to_i64.o
+SF_OBJS_OTHERS += f32_to_ui32_r_minMag.o
+SF_OBJS_OTHERS += f32_to_ui64_r_minMag.o
+SF_OBJS_OTHERS += f32_to_i32_r_minMag.o
+SF_OBJS_OTHERS += f32_to_i64_r_minMag.o
+SF_OBJS_OTHERS += f32_to_f16.o
+SF_OBJS_OTHERS += f32_to_f64.o
+SF_OBJS_OTHERS += f32_to_extF80.o
+SF_OBJS_OTHERS += f32_to_extF80M.o
+SF_OBJS_OTHERS += f32_to_f128.o
+SF_OBJS_OTHERS += f32_to_f128M.o
+SF_OBJS_OTHERS += f32_roundToInt.o
+SF_OBJS_OTHERS += f32_add.o
+SF_OBJS_OTHERS += f32_sub.o
+SF_OBJS_OTHERS += f32_mul.o
+SF_OBJS_OTHERS += f32_mulAdd.o
+SF_OBJS_OTHERS += f32_div.o
+SF_OBJS_OTHERS += f32_rem.o
+SF_OBJS_OTHERS += f32_sqrt.o
+SF_OBJS_OTHERS += f32_eq.o
+SF_OBJS_OTHERS += f32_le.o
+SF_OBJS_OTHERS += f32_lt.o
+SF_OBJS_OTHERS += f32_eq_signaling.o
+SF_OBJS_OTHERS += f32_le_quiet.o
+SF_OBJS_OTHERS += f32_lt_quiet.o
+SF_OBJS_OTHERS += f32_isSignalingNaN.o
+SF_OBJS_OTHERS += f64_to_ui32.o
+SF_OBJS_OTHERS += f64_to_ui64.o
+SF_OBJS_OTHERS += f64_to_i32.o
+SF_OBJS_OTHERS += f64_to_i64.o
+SF_OBJS_OTHERS += f64_to_ui32_r_minMag.o
+SF_OBJS_OTHERS += f64_to_ui64_r_minMag.o
+SF_OBJS_OTHERS += f64_to_i32_r_minMag.o
+SF_OBJS_OTHERS += f64_to_i64_r_minMag.o
+SF_OBJS_OTHERS += f64_to_f16.o
+SF_OBJS_OTHERS += f64_to_f32.o
+SF_OBJS_OTHERS += f64_to_extF80.o
+SF_OBJS_OTHERS += f64_to_extF80M.o
+SF_OBJS_OTHERS += f64_to_f128.o
+SF_OBJS_OTHERS += f64_to_f128M.o
+SF_OBJS_OTHERS += f64_roundToInt.o
+SF_OBJS_OTHERS += f64_add.o
+SF_OBJS_OTHERS += f64_sub.o
+SF_OBJS_OTHERS += f64_mul.o
+SF_OBJS_OTHERS += f64_mulAdd.o
+SF_OBJS_OTHERS += f64_div.o
+SF_OBJS_OTHERS += f64_rem.o
+SF_OBJS_OTHERS += f64_sqrt.o
+SF_OBJS_OTHERS += f64_eq.o
+SF_OBJS_OTHERS += f64_le.o
+SF_OBJS_OTHERS += f64_lt.o
+SF_OBJS_OTHERS += f64_eq_signaling.o
+SF_OBJS_OTHERS += f64_le_quiet.o
+SF_OBJS_OTHERS += f64_lt_quiet.o
+SF_OBJS_OTHERS += f64_isSignalingNaN.o
+SF_OBJS_OTHERS += extF80_to_ui32.o
+SF_OBJS_OTHERS += extF80_to_ui64.o
+SF_OBJS_OTHERS += extF80_to_i32.o
+SF_OBJS_OTHERS += extF80_to_i64.o
+SF_OBJS_OTHERS += extF80_to_ui32_r_minMag.o
+SF_OBJS_OTHERS += extF80_to_ui64_r_minMag.o
+SF_OBJS_OTHERS += extF80_to_i32_r_minMag.o
+SF_OBJS_OTHERS += extF80_to_i64_r_minMag.o
+SF_OBJS_OTHERS += extF80_to_f16.o
+SF_OBJS_OTHERS += extF80_to_f32.o
+SF_OBJS_OTHERS += extF80_to_f64.o
+SF_OBJS_OTHERS += extF80_to_f128.o
+SF_OBJS_OTHERS += extF80_roundToInt.o
+SF_OBJS_OTHERS += extF80_add.o
+SF_OBJS_OTHERS += extF80_sub.o
+SF_OBJS_OTHERS += extF80_mul.o
+SF_OBJS_OTHERS += extF80_div.o
+SF_OBJS_OTHERS += extF80_rem.o
+SF_OBJS_OTHERS += extF80_sqrt.o
+SF_OBJS_OTHERS += extF80_eq.o
+SF_OBJS_OTHERS += extF80_le.o
+SF_OBJS_OTHERS += extF80_lt.o
+SF_OBJS_OTHERS += extF80_eq_signaling.o
+SF_OBJS_OTHERS += extF80_le_quiet.o
+SF_OBJS_OTHERS += extF80_lt_quiet.o
+SF_OBJS_OTHERS += extF80_isSignalingNaN.o
+SF_OBJS_OTHERS += extF80M_to_ui32.o
+SF_OBJS_OTHERS += extF80M_to_ui64.o
+SF_OBJS_OTHERS += extF80M_to_i32.o
+SF_OBJS_OTHERS += extF80M_to_i64.o
+SF_OBJS_OTHERS += extF80M_to_ui32_r_minMag.o
+SF_OBJS_OTHERS += extF80M_to_ui64_r_minMag.o
+SF_OBJS_OTHERS += extF80M_to_i32_r_minMag.o
+SF_OBJS_OTHERS += extF80M_to_i64_r_minMag.o
+SF_OBJS_OTHERS += extF80M_to_f16.o
+SF_OBJS_OTHERS += extF80M_to_f32.o
+SF_OBJS_OTHERS += extF80M_to_f64.o
+SF_OBJS_OTHERS += extF80M_to_f128M.o
+SF_OBJS_OTHERS += extF80M_roundToInt.o
+SF_OBJS_OTHERS += extF80M_add.o
+SF_OBJS_OTHERS += extF80M_sub.o
+SF_OBJS_OTHERS += extF80M_mul.o
+SF_OBJS_OTHERS += extF80M_div.o
+SF_OBJS_OTHERS += extF80M_rem.o
+SF_OBJS_OTHERS += extF80M_sqrt.o
+SF_OBJS_OTHERS += extF80M_eq.o
+SF_OBJS_OTHERS += extF80M_le.o
+SF_OBJS_OTHERS += extF80M_lt.o
+SF_OBJS_OTHERS += extF80M_eq_signaling.o
+SF_OBJS_OTHERS += extF80M_le_quiet.o
+SF_OBJS_OTHERS += extF80M_lt_quiet.o
+SF_OBJS_OTHERS += f128_to_ui32.o
+SF_OBJS_OTHERS += f128_to_ui64.o
+SF_OBJS_OTHERS += f128_to_i32.o
+SF_OBJS_OTHERS += f128_to_i64.o
+SF_OBJS_OTHERS += f128_to_ui32_r_minMag.o
+SF_OBJS_OTHERS += f128_to_ui64_r_minMag.o
+SF_OBJS_OTHERS += f128_to_i32_r_minMag.o
+SF_OBJS_OTHERS += f128_to_i64_r_minMag.o
+SF_OBJS_OTHERS += f128_to_f16.o
+SF_OBJS_OTHERS += f128_to_f32.o
+SF_OBJS_OTHERS += f128_to_extF80.o
+SF_OBJS_OTHERS += f128_to_f64.o
+SF_OBJS_OTHERS += f128_roundToInt.o
+SF_OBJS_OTHERS += f128_add.o
+SF_OBJS_OTHERS += f128_sub.o
+SF_OBJS_OTHERS += f128_mul.o
+SF_OBJS_OTHERS += f128_mulAdd.o
+SF_OBJS_OTHERS += f128_div.o
+SF_OBJS_OTHERS += f128_rem.o
+SF_OBJS_OTHERS += f128_sqrt.o
+SF_OBJS_OTHERS += f128_eq.o
+SF_OBJS_OTHERS += f128_le.o
+SF_OBJS_OTHERS += f128_lt.o
+SF_OBJS_OTHERS += f128_eq_signaling.o
+SF_OBJS_OTHERS += f128_le_quiet.o
+SF_OBJS_OTHERS += f128_lt_quiet.o
+SF_OBJS_OTHERS += f128_isSignalingNaN.o
+SF_OBJS_OTHERS += f128M_to_ui32.o
+SF_OBJS_OTHERS += f128M_to_ui64.o
+SF_OBJS_OTHERS += f128M_to_i32.o
+SF_OBJS_OTHERS += f128M_to_i64.o
+SF_OBJS_OTHERS += f128M_to_ui32_r_minMag.o
+SF_OBJS_OTHERS += f128M_to_ui64_r_minMag.o
+SF_OBJS_OTHERS += f128M_to_i32_r_minMag.o
+SF_OBJS_OTHERS += f128M_to_i64_r_minMag.o
+SF_OBJS_OTHERS += f128M_to_f16.o
+SF_OBJS_OTHERS += f128M_to_f32.o
+SF_OBJS_OTHERS += f128M_to_extF80M.o
+SF_OBJS_OTHERS += f128M_to_f64.o
+SF_OBJS_OTHERS += f128M_roundToInt.o
+SF_OBJS_OTHERS += f128M_add.o
+SF_OBJS_OTHERS += f128M_sub.o
+SF_OBJS_OTHERS += f128M_mul.o
+SF_OBJS_OTHERS += f128M_mulAdd.o
+SF_OBJS_OTHERS += f128M_div.o
+SF_OBJS_OTHERS += f128M_rem.o
+SF_OBJS_OTHERS += f128M_sqrt.o
+SF_OBJS_OTHERS += f128M_eq.o
+SF_OBJS_OTHERS += f128M_le.o
+SF_OBJS_OTHERS += f128M_lt.o
+SF_OBJS_OTHERS += f128M_eq_signaling.o
+SF_OBJS_OTHERS += f128M_le_quiet.o
+SF_OBJS_OTHERS += f128M_lt_quiet.o
+
+SF_OBJS_ALL_NOSPEC :=
+SF_OBJS_ALL_NOSPEC += $(SF_OBJS_PRIMITIVES)
+SF_OBJS_ALL_NOSPEC += $(SF_OBJS_OTHERS)
+
+SF_OBJS_ALL :=
+SF_OBJS_ALL += $(SF_OBJS_ALL_NOSPEC)
+SF_OBJS_ALL += $(SF_OBJS_SPECIALIZE)
+
+# testfloat objects
+TF_OBJS_GENCASES :=
+TF_OBJS_GENCASES += genCases_ui32.o
+TF_OBJS_GENCASES += genCases_ui64.o
+TF_OBJS_GENCASES += genCases_i32.o
+TF_OBJS_GENCASES += genCases_i64.o
+TF_OBJS_GENCASES += genCases_f16.o
+TF_OBJS_GENCASES += genCases_f32.o
+TF_OBJS_GENCASES += genCases_f64.o
+TF_OBJS_GENCASES += genCases_extF80.o
+TF_OBJS_GENCASES += genCases_f128.o
+
+TF_OBJS_WRITECASE :=
+TF_OBJS_WRITECASE += writeCase_a_ui32.o
+TF_OBJS_WRITECASE += writeCase_a_ui64.o
+TF_OBJS_WRITECASE += writeCase_a_f16.o
+TF_OBJS_WRITECASE += writeCase_ab_f16.o
+TF_OBJS_WRITECASE += writeCase_abc_f16.o
+TF_OBJS_WRITECASE += writeCase_a_f32.o
+TF_OBJS_WRITECASE += writeCase_ab_f32.o
+TF_OBJS_WRITECASE += writeCase_abc_f32.o
+TF_OBJS_WRITECASE += writeCase_a_f64.o
+TF_OBJS_WRITECASE += writeCase_ab_f64.o
+TF_OBJS_WRITECASE += writeCase_abc_f64.o
+TF_OBJS_WRITECASE += writeCase_a_extF80M.o
+TF_OBJS_WRITECASE += writeCase_ab_extF80M.o
+TF_OBJS_WRITECASE += writeCase_a_f128M.o
+TF_OBJS_WRITECASE += writeCase_ab_f128M.o
+TF_OBJS_WRITECASE += writeCase_abc_f128M.o
+TF_OBJS_WRITECASE += writeCase_z_bool.o
+TF_OBJS_WRITECASE += writeCase_z_ui32.o
+TF_OBJS_WRITECASE += writeCase_z_ui64.o
+TF_OBJS_WRITECASE += writeCase_z_f16.o
+TF_OBJS_WRITECASE += writeCase_z_f32.o
+TF_OBJS_WRITECASE += writeCase_z_f64.o
+TF_OBJS_WRITECASE += writeCase_z_extF80M.o
+TF_OBJS_WRITECASE += writeCase_z_f128M.o
+
+TF_OBJS_TEST :=
+TF_OBJS_TEST += test_a_ui32_z_f16.o
+TF_OBJS_TEST += test_a_ui32_z_f32.o
+TF_OBJS_TEST += test_a_ui32_z_f64.o
+TF_OBJS_TEST += test_a_ui32_z_extF80.o
+TF_OBJS_TEST += test_a_ui32_z_f128.o
+TF_OBJS_TEST += test_a_ui64_z_f16.o
+TF_OBJS_TEST += test_a_ui64_z_f32.o
+TF_OBJS_TEST += test_a_ui64_z_f64.o
+TF_OBJS_TEST += test_a_ui64_z_extF80.o
+TF_OBJS_TEST += test_a_ui64_z_f128.o
+TF_OBJS_TEST += test_a_i32_z_f16.o
+TF_OBJS_TEST += test_a_i32_z_f32.o
+TF_OBJS_TEST += test_a_i32_z_f64.o
+TF_OBJS_TEST += test_a_i32_z_extF80.o
+TF_OBJS_TEST += test_a_i32_z_f128.o
+TF_OBJS_TEST += test_a_i64_z_f16.o
+TF_OBJS_TEST += test_a_i64_z_f32.o
+TF_OBJS_TEST += test_a_i64_z_f64.o
+TF_OBJS_TEST += test_a_i64_z_extF80.o
+TF_OBJS_TEST += test_a_i64_z_f128.o
+TF_OBJS_TEST += test_a_f16_z_ui32_rx.o
+TF_OBJS_TEST += test_a_f16_z_ui64_rx.o
+TF_OBJS_TEST += test_a_f16_z_i32_rx.o
+TF_OBJS_TEST += test_a_f16_z_i64_rx.o
+TF_OBJS_TEST += test_a_f16_z_ui32_x.o
+TF_OBJS_TEST += test_a_f16_z_ui64_x.o
+TF_OBJS_TEST += test_a_f16_z_i32_x.o
+TF_OBJS_TEST += test_a_f16_z_i64_x.o
+TF_OBJS_TEST += test_a_f16_z_f32.o
+TF_OBJS_TEST += test_a_f16_z_f64.o
+TF_OBJS_TEST += test_a_f16_z_extF80.o
+TF_OBJS_TEST += test_a_f16_z_f128.o
+TF_OBJS_TEST += test_az_f16.o
+TF_OBJS_TEST += test_az_f16_rx.o
+TF_OBJS_TEST += test_abz_f16.o
+TF_OBJS_TEST += test_abcz_f16.o
+TF_OBJS_TEST += test_ab_f16_z_bool.o
+TF_OBJS_TEST += test_a_f32_z_ui32_rx.o
+TF_OBJS_TEST += test_a_f32_z_ui64_rx.o
+TF_OBJS_TEST += test_a_f32_z_i32_rx.o
+TF_OBJS_TEST += test_a_f32_z_i64_rx.o
+TF_OBJS_TEST += test_a_f32_z_ui32_x.o
+TF_OBJS_TEST += test_a_f32_z_ui64_x.o
+TF_OBJS_TEST += test_a_f32_z_i32_x.o
+TF_OBJS_TEST += test_a_f32_z_i64_x.o
+TF_OBJS_TEST += test_a_f32_z_f16.o
+TF_OBJS_TEST += test_a_f32_z_f64.o
+TF_OBJS_TEST += test_a_f32_z_extF80.o
+TF_OBJS_TEST += test_a_f32_z_f128.o
+TF_OBJS_TEST += test_az_f32.o
+TF_OBJS_TEST += test_az_f32_rx.o
+TF_OBJS_TEST += test_abz_f32.o
+TF_OBJS_TEST += test_abcz_f32.o
+TF_OBJS_TEST += test_ab_f32_z_bool.o
+TF_OBJS_TEST += test_a_f64_z_ui32_rx.o
+TF_OBJS_TEST += test_a_f64_z_ui64_rx.o
+TF_OBJS_TEST += test_a_f64_z_i32_rx.o
+TF_OBJS_TEST += test_a_f64_z_i64_rx.o
+TF_OBJS_TEST += test_a_f64_z_ui32_x.o
+TF_OBJS_TEST += test_a_f64_z_ui64_x.o
+TF_OBJS_TEST += test_a_f64_z_i32_x.o
+TF_OBJS_TEST += test_a_f64_z_i64_x.o
+TF_OBJS_TEST += test_a_f64_z_f16.o
+TF_OBJS_TEST += test_a_f64_z_f32.o
+TF_OBJS_TEST += test_a_f64_z_extF80.o
+TF_OBJS_TEST += test_a_f64_z_f128.o
+TF_OBJS_TEST += test_az_f64.o
+TF_OBJS_TEST += test_az_f64_rx.o
+TF_OBJS_TEST += test_abz_f64.o
+TF_OBJS_TEST += test_abcz_f64.o
+TF_OBJS_TEST += test_ab_f64_z_bool.o
+TF_OBJS_TEST += test_a_extF80_z_ui32_rx.o
+TF_OBJS_TEST += test_a_extF80_z_ui64_rx.o
+TF_OBJS_TEST += test_a_extF80_z_i32_rx.o
+TF_OBJS_TEST += test_a_extF80_z_i64_rx.o
+TF_OBJS_TEST += test_a_extF80_z_ui32_x.o
+TF_OBJS_TEST += test_a_extF80_z_ui64_x.o
+TF_OBJS_TEST += test_a_extF80_z_i32_x.o
+TF_OBJS_TEST += test_a_extF80_z_i64_x.o
+TF_OBJS_TEST += test_a_extF80_z_f16.o
+TF_OBJS_TEST += test_a_extF80_z_f32.o
+TF_OBJS_TEST += test_a_extF80_z_f64.o
+TF_OBJS_TEST += test_a_extF80_z_f128.o
+TF_OBJS_TEST += test_az_extF80.o
+TF_OBJS_TEST += test_az_extF80_rx.o
+TF_OBJS_TEST += test_abz_extF80.o
+TF_OBJS_TEST += test_ab_extF80_z_bool.o
+TF_OBJS_TEST += test_a_f128_z_ui32_rx.o
+TF_OBJS_TEST += test_a_f128_z_ui64_rx.o
+TF_OBJS_TEST += test_a_f128_z_i32_rx.o
+TF_OBJS_TEST += test_a_f128_z_i64_rx.o
+TF_OBJS_TEST += test_a_f128_z_ui32_x.o
+TF_OBJS_TEST += test_a_f128_z_ui64_x.o
+TF_OBJS_TEST += test_a_f128_z_i32_x.o
+TF_OBJS_TEST += test_a_f128_z_i64_x.o
+TF_OBJS_TEST += test_a_f128_z_f16.o
+TF_OBJS_TEST += test_a_f128_z_f32.o
+TF_OBJS_TEST += test_a_f128_z_f64.o
+TF_OBJS_TEST += test_a_f128_z_extF80.o
+TF_OBJS_TEST += test_az_f128.o
+TF_OBJS_TEST += test_az_f128_rx.o
+TF_OBJS_TEST += test_abz_f128.o
+TF_OBJS_TEST += test_abcz_f128.o
+TF_OBJS_TEST += test_ab_f128_z_bool.o
+
+TF_OBJS_LIB :=
+TF_OBJS_LIB += uint128_inline.o
+TF_OBJS_LIB += uint128.o
+TF_OBJS_LIB += fail.o
+TF_OBJS_LIB += functions_common.o
+TF_OBJS_LIB += functionInfos.o
+TF_OBJS_LIB += standardFunctionInfos.o
+TF_OBJS_LIB += random.o
+TF_OBJS_LIB += genCases_common.o
+TF_OBJS_LIB += $(TF_OBJS_GENCASES)
+TF_OBJS_LIB += genCases_writeTestsTotal.o
+TF_OBJS_LIB += verCases_inline.o
+TF_OBJS_LIB += verCases_common.o
+TF_OBJS_LIB += verCases_writeFunctionName.o
+TF_OBJS_LIB += readHex.o
+TF_OBJS_LIB += writeHex.o
+TF_OBJS_LIB += $(TF_OBJS_WRITECASE)
+TF_OBJS_LIB += testLoops_common.o
+TF_OBJS_LIB += $(TF_OBJS_TEST)
+
+BINARIES := fp-test$(EXESUF)
+
+all: $(BINARIES)
+
+$(LIBQEMUUTIL):
+	$(MAKE) -C $(BUILD_DIR) libqemuutil.a
+
+# libtestfloat.a depends on libsoftfloat.a, so specify it first
+FP_TEST_LIBS := libtestfloat.a libsoftfloat.a $(LIBQEMUUTIL)
+
+fp-test$(EXESUF): fp-test.o slowfloat.o $(QEMU_SOFTFLOAT_OBJ) $(FP_TEST_LIBS)
+
+# Custom rule to build with SF_CFLAGS
+SF_BUILD = $(call quiet-command,$(CC) $(QEMU_LOCAL_INCLUDES) $(QEMU_INCLUDES) \
+		$(QEMU_CFLAGS) $(SF_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) \
+		$($@-cflags) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
+
+$(SF_OBJS_ALL_NOSPEC): %.o: $(SF_SOURCE_DIR)/%.c
+	$(SF_BUILD)
+$(SF_OBJS_SPECIALIZE): %.o: $(SF_SPECIALIZE_DIR)/%.c
+	$(SF_BUILD)
+
+libsoftfloat.a: $(SF_OBJS_ALL)
+
+# Custom rule to build with TF_CFLAGS
+$(TF_OBJS_LIB) slowfloat.o: %.o: $(TF_SOURCE_DIR)/%.c
+	$(call quiet-command,$(CC) $(QEMU_LOCAL_INCLUDES) $(QEMU_INCLUDES) \
+		$(QEMU_CFLAGS) $(TF_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) \
+		$($@-cflags) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
+
+libtestfloat.a: $(TF_OBJS_LIB)
+
+clean:
+	rm -f *.o *.d $(BINARIES)
+	rm -f fp-test$(EXESUF)
+	rm -f libsoftfloat.a
+	rm -f libtestfloat.a
+
+-include $(wildcard *.d)
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/2] gitmodules: add berkeley's softfloat + testfloat version 3
  2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 1/2] gitmodules: add berkeley's softfloat + testfloat version 3 Emilio G. Cota
@ 2018-09-10  9:29   ` Alex Bennée
  0 siblings, 0 replies; 10+ messages in thread
From: Alex Bennée @ 2018-09-10  9:29 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: qemu-devel, Peter Maydell, Aurelien Jarno, Richard Henderson,
	Laurent Vivier


Emilio G. Cota <cota@braap.org> writes:

> These are BSD-licensed so we can add them as submodules.
>
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> ---
>  .gitmodules                   | 6 ++++++
>  tests/fp/berkeley-softfloat-3 | 1 +
>  tests/fp/berkeley-testfloat-3 | 1 +
>  3 files changed, 8 insertions(+)
>  create mode 160000 tests/fp/berkeley-softfloat-3
>  create mode 160000 tests/fp/berkeley-testfloat-3
>
> diff --git a/.gitmodules b/.gitmodules
> index d108478e0a..165c7c5286 100644
> --- a/.gitmodules
> +++ b/.gitmodules
> @@ -43,3 +43,9 @@
>  [submodule "roms/u-boot-sam460ex"]
>  	path = roms/u-boot-sam460ex
>  	url = git://git.qemu.org/u-boot-sam460ex.git
> +[submodule "tests/fp/testfloat"]
> +	path = tests/fp/berkeley-testfloat-3
> +	url = git://github.com/ucb-bar/berkeley-testfloat-3
> +[submodule "tests/fp/berkeley-softfloat-3"]
> +	path = tests/fp/berkeley-softfloat-3
> +	url = git://github.com/ucb-bar/berkeley-softfloat-3

I think generally when we add submodules we setup a mirror at
git://git.qemu.org so we are only at the whims of our own
infrastructure. See https://wiki.qemu.org/AdminContacts

Nevertheless:

Acked-by: Alex Bennée <alex.bennee@linaro.org>




> diff --git a/tests/fp/berkeley-softfloat-3 b/tests/fp/berkeley-softfloat-3
> new file mode 160000
> index 0000000000..b64af41c32
> --- /dev/null
> +++ b/tests/fp/berkeley-softfloat-3
> @@ -0,0 +1 @@
> +Subproject commit b64af41c3276f97f0e181920400ee056b9c88037
> diff --git a/tests/fp/berkeley-testfloat-3 b/tests/fp/berkeley-testfloat-3
> new file mode 160000
> index 0000000000..06b20075dd
> --- /dev/null
> +++ b/tests/fp/berkeley-testfloat-3
> @@ -0,0 +1 @@
> +Subproject commit 06b20075dd3c1a5d0dd007a93643282832221612


--
Alex Bennée

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/2] tests: add floating point tests
  2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 2/2] tests: add floating point tests Emilio G. Cota
@ 2018-09-10 11:00   ` Alex Bennée
  2018-09-10 14:37     ` Emilio G. Cota
  0 siblings, 1 reply; 10+ messages in thread
From: Alex Bennée @ 2018-09-10 11:00 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: qemu-devel, Peter Maydell, Aurelien Jarno, Richard Henderson,
	Laurent Vivier


Emilio G. Cota <cota@braap.org> writes:

> By leveraging berkeley's softfloat and testfloat.
>
> fp-test.c is derived from testfloat's testsoftfloat.c. To ease
> the tracking of upstream changes to the latter file, fp-test.c
> keeps the original camel-case variable naming, and includes
> most new code via wrap.inc.c.
>
> Most changes to the original code are simple style changes,
> although a couple of not-so-subtle modifications have been
> made (noted with XXX in the code), namely:
>
> - We do not test ROUND_ODD, since not all of our primitives
>   support it (e.g. fp16)
>
> - Do not test !exact in round-to-integer, since it is not
>   implemented in QEMU (this flag was added to softfloat v3).
>
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> ---
>  configure              |    2 +
>  tests/fp/platform.h    |   41 ++
>  tests/fp/fp-test.c     | 1052 ++++++++++++++++++++++++++++++++++++++++
>  tests/fp/wrap.inc.c    |  600 +++++++++++++++++++++++
>  tests/Makefile.include |    3 +
>  tests/fp/.gitignore    |    1 +
>  tests/fp/Makefile      |  591 ++++++++++++++++++++++
>  7 files changed, 2290 insertions(+)

<snip>

> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 87c81d1dcc..363f133101 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -657,6 +657,9 @@ tests/qht-bench$(EXESUF): tests/qht-bench.o $(test-util-obj-y)
>  tests/test-bufferiszero$(EXESUF): tests/test-bufferiszero.o $(test-util-obj-y)
>  tests/atomic_add-bench$(EXESUF): tests/atomic_add-bench.o $(test-util-obj-y)
>
> +tests/fp/%:
> +	$(MAKE) -C $(dir $@) $(notdir $@)
> +

This isn't enough to cause the build to be included in make check or
indeed be run. Perhaps that should be included in a new patch in the
series?

>  tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
>  	hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\
>  	hw/core/bus.o \
<snip>

--
Alex Bennée

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat
  2018-09-08 19:17 [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat Emilio G. Cota
  2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 1/2] gitmodules: add berkeley's softfloat + testfloat version 3 Emilio G. Cota
  2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 2/2] tests: add floating point tests Emilio G. Cota
@ 2018-09-10 11:26 ` Alex Bennée
  2018-09-10 15:14   ` Emilio G. Cota
  2 siblings, 1 reply; 10+ messages in thread
From: Alex Bennée @ 2018-09-10 11:26 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: qemu-devel, Peter Maydell, Aurelien Jarno, Richard Henderson,
	Laurent Vivier


Emilio G. Cota <cota@braap.org> writes:

> A few fixes since yesterday's v1:
>   https://lists.gnu.org/archive/html/qemu-devel/2018-09/msg00884.html
>
> - Convert copy_qemu_to_soft80 to qemu_to_soft80, just like the other
>   conversion functions
> - Set fp-test as the program name as reported by itself
> - Fix Makefile to include .d files so that dependencies are
>   properly tracked
> - Update commit log

Just some general comments:

 - I think this is a better way to go than the IBM test suite
 - I'm ambivalent about maintaining our fp-test.c in close alignment to
   softfloat unless we expect much upstreaming of changes.
 - the coverage seems a bit low. Rebuilding everything with
   --enable-gcov and running -all1 -all2 I get:

  tests/fp/fp-test.c - 53.5 % coverage 43.3 % branch coverage
  fpu/softfloat.c - 32.5 % coverage 25.1 % branch coverage

But maybe I didn't pass enough options to fp-test? I could really do
with a --just-run-everything-and-summarise-failing-functions option so I
can then go through in more detail with fp-test fFOO_BAR.

>
> Grab this from:
>   https://github.com/cota/qemu/tree/fp-test-v2
>
> Thanks,
>
> 		Emilio


--
Alex Bennée

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/2] tests: add floating point tests
  2018-09-10 11:00   ` Alex Bennée
@ 2018-09-10 14:37     ` Emilio G. Cota
  0 siblings, 0 replies; 10+ messages in thread
From: Emilio G. Cota @ 2018-09-10 14:37 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Peter Maydell, Aurelien Jarno, Richard Henderson,
	Laurent Vivier

On Mon, Sep 10, 2018 at 12:00:56 +0100, Alex Bennée wrote:
> Emilio G. Cota <cota@braap.org> writes:
> > diff --git a/tests/Makefile.include b/tests/Makefile.include
> > index 87c81d1dcc..363f133101 100644
> > --- a/tests/Makefile.include
> > +++ b/tests/Makefile.include
> > @@ -657,6 +657,9 @@ tests/qht-bench$(EXESUF): tests/qht-bench.o $(test-util-obj-y)
> >  tests/test-bufferiszero$(EXESUF): tests/test-bufferiszero.o $(test-util-obj-y)
> >  tests/atomic_add-bench$(EXESUF): tests/atomic_add-bench.o $(test-util-obj-y)
> >
> > +tests/fp/%:
> > +	$(MAKE) -C $(dir $@) $(notdir $@)
> > +
> 
> This isn't enough to cause the build to be included in make check or
> indeed be run. Perhaps that should be included in a new patch in the
> series?

Yes I figured we should fix the reported errors first -- otherwise
we'll knowingly break the integration tests.

		Emilio

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat
  2018-09-10 11:26 ` [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat Alex Bennée
@ 2018-09-10 15:14   ` Emilio G. Cota
  2018-09-10 15:41     ` Alex Bennée
  0 siblings, 1 reply; 10+ messages in thread
From: Emilio G. Cota @ 2018-09-10 15:14 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Peter Maydell, Aurelien Jarno, Richard Henderson,
	Laurent Vivier

On Mon, Sep 10, 2018 at 12:26:58 +0100, Alex Bennée wrote:
> 
> Emilio G. Cota <cota@braap.org> writes:
> 
> > A few fixes since yesterday's v1:
> >   https://lists.gnu.org/archive/html/qemu-devel/2018-09/msg00884.html
> >
> > - Convert copy_qemu_to_soft80 to qemu_to_soft80, just like the other
> >   conversion functions
> > - Set fp-test as the program name as reported by itself
> > - Fix Makefile to include .d files so that dependencies are
> >   properly tracked
> > - Update commit log
> 
> Just some general comments:
> 
>  - I think this is a better way to go than the IBM test suite
>  - I'm ambivalent about maintaining our fp-test.c in close alignment to
>    softfloat unless we expect much upstreaming of changes.

I don't think there'll be any, to be honest. They have a git repo but
I doubt they'll take any patches. This was just a minimum attempt to
get some tests working (I don't have a lot of time to work on this)

>  - the coverage seems a bit low. Rebuilding everything with
>    --enable-gcov and running -all1 -all2 I get:
> 
>   tests/fp/fp-test.c - 53.5 % coverage 43.3 % branch coverage
>   fpu/softfloat.c - 32.5 % coverage 25.1 % branch coverage
> 
> But maybe I didn't pass enough options to fp-test? I could really do
> with a --just-run-everything-and-summarise-failing-functions option so I
> can then go through in more detail with fp-test fFOO_BAR.

Yes right now to get better coverage you need to run it several times.
After a few runs I got it to 58%, but still without testing some
rounding modes. So considering we're coming from 0% coverage, I'd
say coverage is pretty good!

But yes, we should add a flag to just test -all.

There are some functions that we are not testing yet though, but
that can be fixed over time (we can add more tests to fp-test even
though they're not in testfloat, such as testing flush-to-zero/
denormals-are-zero, or the muladd variants that we have).

I have basically no time left to work on this. What do you think about
the following plan?

1. Have our own clones (forks) of testfloat/softfloat in qemu servers.
2. Add those as submodules
3. Add fp-test with as you said an -all flag that reports all
   errors to get decent coverage.
4. Add hardfloat patches, with tests. This requires a small
   change to testfloat:
   https://github.com/cota/berkeley-testfloat-3/commit/ca9fa2ba05

I'd then leave adding further tests to increase coverage and fixing
the existing bugs (prior to hardfloat) to someone else with
more time/resources.

Thanks,

		Emilio

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat
  2018-09-10 15:14   ` Emilio G. Cota
@ 2018-09-10 15:41     ` Alex Bennée
  2018-09-10 16:25       ` Emilio G. Cota
  0 siblings, 1 reply; 10+ messages in thread
From: Alex Bennée @ 2018-09-10 15:41 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: qemu-devel, Peter Maydell, Aurelien Jarno, Richard Henderson,
	Laurent Vivier


Emilio G. Cota <cota@braap.org> writes:

> On Mon, Sep 10, 2018 at 12:26:58 +0100, Alex Bennée wrote:
>>
>> Emilio G. Cota <cota@braap.org> writes:
>>
>> > A few fixes since yesterday's v1:
>> >   https://lists.gnu.org/archive/html/qemu-devel/2018-09/msg00884.html
>> >
>> > - Convert copy_qemu_to_soft80 to qemu_to_soft80, just like the other
>> >   conversion functions
>> > - Set fp-test as the program name as reported by itself
>> > - Fix Makefile to include .d files so that dependencies are
>> >   properly tracked
>> > - Update commit log
>>
>> Just some general comments:
>>
>>  - I think this is a better way to go than the IBM test suite
>>  - I'm ambivalent about maintaining our fp-test.c in close alignment to
>>    softfloat unless we expect much upstreaming of changes.
>
> I don't think there'll be any, to be honest. They have a git repo but
> I doubt they'll take any patches. This was just a minimum attempt to
> get some tests working (I don't have a lot of time to work on this)
>
>>  - the coverage seems a bit low. Rebuilding everything with
>>    --enable-gcov and running -all1 -all2 I get:
>>
>>   tests/fp/fp-test.c - 53.5 % coverage 43.3 % branch coverage
>>   fpu/softfloat.c - 32.5 % coverage 25.1 % branch coverage
>>
>> But maybe I didn't pass enough options to fp-test? I could really do
>> with a --just-run-everything-and-summarise-failing-functions option so I
>> can then go through in more detail with fp-test fFOO_BAR.
>
> Yes right now to get better coverage you need to run it several times.
> After a few runs I got it to 58%, but still without testing some
> rounding modes. So considering we're coming from 0% coverage, I'd
> say coverage is pretty good!

I agree ;-)

>
> But yes, we should add a flag to just test -all.
>
> There are some functions that we are not testing yet though, but
> that can be fixed over time (we can add more tests to fp-test even
> though they're not in testfloat, such as testing flush-to-zero/
> denormals-are-zero, or the muladd variants that we have).
>
> I have basically no time left to work on this. What do you think about
> the following plan?
>
> 1. Have our own clones (forks) of testfloat/softfloat in qemu servers.
> 2. Add those as submodules
> 3. Add fp-test with as you said an -all flag that reports all
>    errors to get decent coverage.

Works for me.

> 4. Add hardfloat patches, with tests. This requires a small
>    change to testfloat:
>    https://github.com/cota/berkeley-testfloat-3/commit/ca9fa2ba05

It seems a shame to have our mirror of testfloat diverge but if it can't
be avoided I guess it will have to do. Couldn't we just zero the HW
flags in the wrapped up function? I may be misremembering but don't we
fall-back to softfloat code anyway if we have reached any limits that
trigger exception flags?

> I'd then leave adding further tests to increase coverage and fixing
> the existing bugs (prior to hardfloat) to someone else with
> more time/resources.

Agreed. I should have time to chase down the softfloat regressions once
I'm back from Connect after next week.

>
> Thanks,
>
> 		Emilio


--
Alex Bennée

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat
  2018-09-10 15:41     ` Alex Bennée
@ 2018-09-10 16:25       ` Emilio G. Cota
  0 siblings, 0 replies; 10+ messages in thread
From: Emilio G. Cota @ 2018-09-10 16:25 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Peter Maydell, Aurelien Jarno, Richard Henderson,
	Laurent Vivier

On Mon, Sep 10, 2018 at 16:41:21 +0100, Alex Bennée wrote:
> 
> Emilio G. Cota <cota@braap.org> writes:
> 
> > On Mon, Sep 10, 2018 at 12:26:58 +0100, Alex Bennée wrote:
> >>
> >> Emilio G. Cota <cota@braap.org> writes:
> >>
> >> > A few fixes since yesterday's v1:
> >> >   https://lists.gnu.org/archive/html/qemu-devel/2018-09/msg00884.html
> >> >
> >> > - Convert copy_qemu_to_soft80 to qemu_to_soft80, just like the other
> >> >   conversion functions
> >> > - Set fp-test as the program name as reported by itself
> >> > - Fix Makefile to include .d files so that dependencies are
> >> >   properly tracked
> >> > - Update commit log
> >>
> >> Just some general comments:
> >>
> >>  - I think this is a better way to go than the IBM test suite
> >>  - I'm ambivalent about maintaining our fp-test.c in close alignment to
> >>    softfloat unless we expect much upstreaming of changes.
> >
> > I don't think there'll be any, to be honest. They have a git repo but
> > I doubt they'll take any patches. This was just a minimum attempt to
> > get some tests working (I don't have a lot of time to work on this)
> >
> >>  - the coverage seems a bit low. Rebuilding everything with
> >>    --enable-gcov and running -all1 -all2 I get:
> >>
> >>   tests/fp/fp-test.c - 53.5 % coverage 43.3 % branch coverage
> >>   fpu/softfloat.c - 32.5 % coverage 25.1 % branch coverage
> >>
> >> But maybe I didn't pass enough options to fp-test? I could really do
> >> with a --just-run-everything-and-summarise-failing-functions option so I
> >> can then go through in more detail with fp-test fFOO_BAR.
> >
> > Yes right now to get better coverage you need to run it several times.
> > After a few runs I got it to 58%, but still without testing some
> > rounding modes. So considering we're coming from 0% coverage, I'd
> > say coverage is pretty good!
> 
> I agree ;-)
> 
> >
> > But yes, we should add a flag to just test -all.
> >
> > There are some functions that we are not testing yet though, but
> > that can be fixed over time (we can add more tests to fp-test even
> > though they're not in testfloat, such as testing flush-to-zero/
> > denormals-are-zero, or the muladd variants that we have).
> >
> > I have basically no time left to work on this. What do you think about
> > the following plan?
> >
> > 1. Have our own clones (forks) of testfloat/softfloat in qemu servers.
> > 2. Add those as submodules
> > 3. Add fp-test with as you said an -all flag that reports all
> >    errors to get decent coverage.
> 
> Works for me.
> 
> > 4. Add hardfloat patches, with tests. This requires a small
> >    change to testfloat:
> >    https://github.com/cota/berkeley-testfloat-3/commit/ca9fa2ba05
> 
> It seems a shame to have our mirror of testfloat diverge but if it can't
> be avoided I guess it will have to do. Couldn't we just zero the HW
> flags in the wrapped up function? I may be misremembering but don't we
> fall-back to softfloat code anyway if we have reached any limits that
> trigger exception flags?

testfloat compares the result of the ops as well as the resulting flags.
It zeroes the exception flags register before computing the
"golden" result/flags. The hardfloat code only kicks in when inexact
is set, so we need to add the above patch to testfloat so that we can
control the initial flags from outside. With this patch + a patch
on the fp-test side to set the initial flags, we can choose whether
to test hardfloat or not.

About your second question: yes, for corner cases we defer to softfloat.
But to reach those corner cases we first have to reach the hardfloat
code, which requires inexact to be set.

> > I'd then leave adding further tests to increase coverage and fixing
> > the existing bugs (prior to hardfloat) to someone else with
> > more time/resources.
> 
> Agreed. I should have time to chase down the softfloat regressions once
> I'm back from Connect after next week.

Nice! I'll try to have something ready later today.

		Emilio

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-09-10 16:26 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-08 19:17 [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat Emilio G. Cota
2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 1/2] gitmodules: add berkeley's softfloat + testfloat version 3 Emilio G. Cota
2018-09-10  9:29   ` Alex Bennée
2018-09-08 19:17 ` [Qemu-devel] [PATCH v2 2/2] tests: add floating point tests Emilio G. Cota
2018-09-10 11:00   ` Alex Bennée
2018-09-10 14:37     ` Emilio G. Cota
2018-09-10 11:26 ` [Qemu-devel] [PATCH v2 0/2] softfloat tests based on berkeley's testfloat Alex Bennée
2018-09-10 15:14   ` Emilio G. Cota
2018-09-10 15:41     ` Alex Bennée
2018-09-10 16:25       ` Emilio G. Cota

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.