qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v3 01/15] tests: add fp-test, a floating point t


From: Alex Bennée
Subject: Re: [Qemu-devel] [PATCH v3 01/15] tests: add fp-test, a floating point test suite
Date: Wed, 11 Apr 2018 02:20:49 +0100
User-agent: mu4e 1.1.0; emacs 26.1

Emilio G. Cota <address@hidden> writes:

> This will allow us to run correctness tests against our
> FP implementation. The test can be run in two modes (called
> "testers"): host and soft. With the former we check the results
> and FP flags on the host machine against the model.
> With the latter we check QEMU's fpu primitives against the
> model. Note that in soft mode we are not instantiating any
> particular CPU (hence the HW_POISON_H hack to avoid macro poisoning);
> for that we need to run the test in host mode under QEMU.
<snip>

So with the attached patch and my proposed cross build we can now get:

02:15:54 address@hidden:~/l/q/qemu.git] softfloat-fixes-for-2.12-v1 ± find . 
-iname "fp-test" | xargs file
./ppc64-linux-user/tests/fp-test:      ELF 64-bit LSB executable, 64-bit 
PowerPC or cisco 7500, version 1 (GNU/Linux), statically linked, for GNU/Linux 
3.2.0, not stripped
./armeb-linux-user/tests/fp-test:      ELF 32-bit LSB executable, ARM, EABI5 
version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, not stripped
./aarch64-linux-user/tests/fp-test:    ELF 64-bit LSB executable, ARM aarch64, 
version 1 (SYSV), statically linked, for GNU/Linux 3.7.0, not stripped
./i386-linux-user/tests/fp-test:       ELF 32-bit LSB executable, Intel 80386, 
version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, not stripped
./arm-linux-user/tests/fp-test:        ELF 32-bit LSB executable, ARM, EABI5 
version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, not stripped
./s390x-linux-user/tests/fp-test:      ELF 64-bit MSB executable, IBM S/390, 
version 1 (SYSV), statically linked, for GNU/Linux 3.2.0, not stripped
./aarch64_be-linux-user/tests/fp-test: ELF 64-bit LSB executable, ARM aarch64, 
version 1 (SYSV), statically linked, for GNU/Linux 3.7.0, not stripped
./tests/fp-test/fp-test:               ELF 64-bit LSB shared object, x86-64, 
version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, 
for GNU/Linux 2.6.32, not stripped

But it did mean having to hack about a little, mainly to get rid of
glib.

--8<---------------cut here---------------start------------->8---
>From 04ed0d9f58f34aa51b9a8284514aab6e36a702b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <address@hidden>
Date: Wed, 11 Apr 2018 01:35:52 +0100
Subject: [PATCH] tests/tcg: add fp-test to per-guest tests
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The fp-test code was originally designed to be able to include
softfloat. However cross-compiling QEMU based code is harder than it
needs to be so hide softfloat stuff behind USE_SOFTFLOAT. We also need
to tweak:

  - manually include what we need
  - g_assert -> assert()
  - use libc hsearch instead of g_hash_table

Signed-off-by: Alex Bennée <address@hidden>
---
 tests/fp/fp-test.c | 148 ++++++++++++++++++++++++++++++++++++++++++-----------
 tests/tcg/Makefile |   3 ++
 2 files changed, 121 insertions(+), 30 deletions(-)

diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
index 27637c4617..4cee2a918c 100644
--- a/tests/fp/fp-test.c
+++ b/tests/fp/fp-test.c
@@ -6,12 +6,72 @@
  * License: GNU GPL, version 2 or later.
  *   See the COPYING file in the top-level directory.
  */
-#ifndef HW_POISON_H
-#error Must define HW_POISON_H to work around TARGET_* poisoning
-#endif
+
+/* If HW_POISON_H isn't defined then we aren't building against qemu's
+ * softfloat */
+#ifdef HW_POISON_H

 #include "qemu/osdep.h"
 #include "fpu/softfloat.h"
+#define USE_SOFTFLOAT 1
+
+#else /* else define what QEMU would have given us */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <search.h>
+
+/* See include/fpu/softfloat-types.h */
+enum {
+    float_tininess_after_rounding  = 0,
+    float_tininess_before_rounding = 1
+};
+
+enum {
+    float_round_nearest_even = 0,
+    float_round_down         = 1,
+    float_round_up           = 2,
+    float_round_to_zero      = 3,
+    float_round_ties_away    = 4,
+    float_round_to_odd       = 5,
+};
+
+enum {
+    float_flag_invalid   =  1,
+    float_flag_divbyzero =  4,
+    float_flag_overflow  =  8,
+    float_flag_underflow = 16,
+    float_flag_inexact   = 32,
+    float_flag_input_denormal = 64,
+    float_flag_output_denormal = 128
+};
+
+/* See include/compiler.h */
+#ifndef likely
+#if __GNUC__ < 3
+#define __builtin_expect(x, n) (x)
+#endif
+
+#define likely(x)   __builtin_expect(!!(x), 1)
+#define unlikely(x)   __builtin_expect(!!(x), 0)
+#endif
+
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif

 #include <fenv.h>
 #include <math.h>
@@ -116,16 +176,18 @@ struct tester {
 struct whitelist {
     char **lines;
     size_t n;
-    GHashTable *ht;
+    struct hsearch_data ht;
 };

 static uint64_t test_stats[ERROR_MAX];
 static struct whitelist whitelist;
 static uint8_t default_exceptions;
 static bool die_on_error = true;
+#ifdef USE_SOFTFLOAT
 static struct float_status soft_status = {
     .float_detect_tininess = float_tininess_before_rounding,
 };
+#endif

 static inline float u64_to_float(uint64_t v)
 {
@@ -285,7 +347,7 @@ static enum error host_tester(struct test_op *t)
         float res;
         int i;

-        g_assert(ops[t->op].n_operands <= ARRAY_SIZE(in));
+        assert(ops[t->op].n_operands <= ARRAY_SIZE(in));
         for (i = 0; i < ops[t->op].n_operands; i++) {
             /* use the host's QNaN/SNaN patterns */
             if (t->operands[i].type == OP_TYPE_QNAN) {
@@ -343,7 +405,7 @@ static enum error host_tester(struct test_op *t)
         double res;
         int i;

-        g_assert(ops[t->op].n_operands <= ARRAY_SIZE(in));
+        assert(ops[t->op].n_operands <= ARRAY_SIZE(in));
         for (i = 0; i < ops[t->op].n_operands; i++) {
             /* use the host's QNaN/SNaN patterns */
             if (t->operands[i].type == OP_TYPE_QNAN) {
@@ -429,6 +491,8 @@ static enum error host_tester(struct test_op *t)
     return tester_check(t, res64, result_is_nan, flags);
 }

+#ifdef USE_SOFTFLOAT
+
 static enum error soft_tester(struct test_op *t)
 {
     float_status *s = &soft_status;
@@ -445,7 +509,7 @@ static enum error soft_tester(struct test_op *t)
         float32 res;
         int i;

-        g_assert(ops[t->op].n_operands <= ARRAY_SIZE(in));
+        assert(ops[t->op].n_operands <= ARRAY_SIZE(in));
         for (i = 0; i < ops[t->op].n_operands; i++) {
             *in[i] = t->operands[i].val;
         }
@@ -504,7 +568,7 @@ static enum error soft_tester(struct test_op *t)
         float64 *in[] = { &a, &b, &c };
         int i;

-        g_assert(ops[t->op].n_operands <= ARRAY_SIZE(in));
+        assert(ops[t->op].n_operands <= ARRAY_SIZE(in));
         for (i = 0; i < ops[t->op].n_operands; i++) {
             *in[i] = t->operands[i].val;
         }
@@ -585,6 +649,14 @@ static const struct tester valid_testers[] = {
         .func = host_tester,
     },
 };
+#else
+static const struct tester valid_testers[] = {
+    [0] = {
+        .name = "host",
+        .func = host_tester,
+    },
+};
+#endif
 static const struct tester *tester = &valid_testers[0];

 static int ibm_get_exceptions(const char *p, uint8_t *excp)
@@ -622,7 +694,7 @@ static uint64_t fp_choose(enum precision prec, uint64_t f, 
uint64_t d)
     case PREC_DOUBLE:
         return d;
     default:
-        g_assert_not_reached();
+        assert(false);
     }
 }

@@ -756,7 +828,7 @@ ibm_fp_hex(const char *p, enum precision prec, struct 
operand *ret)
         } else if (prec == PREC_DOUBLE) {
             ret->val = double_to_u64(0.0);
         } else {
-            g_assert_not_reached();
+            assert(false);
         }
         return 0;
     } else if (!strcmp(p, "0x1")) {
@@ -765,7 +837,7 @@ ibm_fp_hex(const char *p, enum precision prec, struct 
operand *ret)
         } else if (prec == PREC_DOUBLE) {
             ret->val = double_to_u64(1.0);
         } else {
-            g_assert_not_reached();
+            assert(false);
         }
         return 0;
     }
@@ -915,10 +987,13 @@ static const struct input *input_type = 
&valid_input_types[INPUT_FMT_IBM];

 static bool line_is_whitelisted(const char *line)
 {
-    if (whitelist.ht == NULL) {
+    ENTRY e, *ep;
+
+    if (whitelist.ht.size == 0) {
         return false;
     }
-    return !!g_hash_table_lookup(whitelist.ht, line);
+    e.key = line;
+    return hsearch_r(e, FIND, &ep, &whitelist.ht)==0;
 }

 static void test_file(const char *filename)
@@ -958,7 +1033,7 @@ static void test_file(const char *filename)
                         filename, i);
                 break;
             default:
-                g_assert_not_reached();
+                assert(false);
             }
             fprintf(stderr, "%s", line);
             if (die_on_error) {
@@ -1007,23 +1082,32 @@ static void set_tester(const char *optarg)

 static void whitelist_add_line(const char *orig_line)
 {
-    char *line;
+    char *line = strdup(orig_line);
     bool inserted;
+    ENTRY e, *ep;
+    int r;

-    if (whitelist.ht == NULL) {
-        whitelist.ht = g_hash_table_new(g_str_hash, g_str_equal);
+    if (whitelist.ht.size == 0) {
+        if (!hcreate_r(4096, &whitelist.ht)) {
+            fprintf(stderr, "%s: error creating hash table\n", __func__);
+        }
     }
-    line = g_hash_table_lookup(whitelist.ht, orig_line);
-    if (unlikely(line != NULL)) {
+
+    int hsearch_r(ENTRY item, ACTION action, ENTRY **retval,
+              struct hsearch_data *htab);
+
+    e.key = line;
+    r = hsearch_r(e, FIND, &ep, &whitelist.ht);
+    if (unlikely(r)) {
+        free(line);
         return;
     }
     whitelist.n++;
-    whitelist.lines = g_realloc_n(whitelist.lines, whitelist.n, sizeof(line));
-    line = strdup(orig_line);
+    whitelist.lines = realloc(whitelist.lines, (whitelist.n * sizeof(line)));
     whitelist.lines[whitelist.n - 1] = line;
-    /* if we pass key == val GLib will not reserve space for the value */
-    inserted = g_hash_table_insert(whitelist.ht, line, line);
-    g_assert(inserted);
+    e.data = line;
+    inserted = hsearch_r(e, ENTER, &ep, &whitelist.ht);
+    assert(inserted);
 }

 static void set_whitelist(const char *filename)
@@ -1061,18 +1145,20 @@ static void usage_complete(int argc, char *argv[])
 {
     fprintf(stderr, "Usage: %s [options] file1 [file2 ...]\n", argv[0]);
     fprintf(stderr, "options:\n");
-    fprintf(stderr, "  -a = Perform tininess detection after rounding "
-            "(soft tester only). Default: before\n");
     fprintf(stderr, "  -n = do not die on error. Default: dies on error\n");
     fprintf(stderr, "  -e = default exception flags (xiozu). Default: none\n");
     fprintf(stderr, "  -f = format of the input file(s). Default: %s\n",
             valid_input_types[0].name);
     fprintf(stderr, "  -t = tester. Default: %s\n", valid_testers[0].name);
     fprintf(stderr, "  -w = path to file with test cases to be whitelisted\n");
+#ifdef USE_SOFTFLOAT
+    fprintf(stderr, "  -a = Perform tininess detection after rounding "
+            "(soft tester only). Default: before\n");
     fprintf(stderr, "  -z = flush inputs to zero (soft tester only). "
             "Default: disabled\n");
     fprintf(stderr, "  -Z = flush output to zero (soft tester only). "
             "Default: disabled\n");
+#endif
 }

 static void parse_opts(int argc, char *argv[])
@@ -1085,9 +1171,6 @@ static void parse_opts(int argc, char *argv[])
             return;
         }
         switch (c) {
-        case 'a':
-            soft_status.float_detect_tininess = float_tininess_after_rounding;
-            break;
         case 'e':
             set_default_exceptions(optarg);
             break;
@@ -1106,15 +1189,20 @@ static void parse_opts(int argc, char *argv[])
         case 'w':
             set_whitelist(optarg);
             break;
+#ifdef USE_SOFTFLOAT
+        case 'a':
+            soft_status.float_detect_tininess = float_tininess_after_rounding;
+            break;
         case 'z':
             soft_status.flush_inputs_to_zero = 1;
             break;
         case 'Z':
             soft_status.flush_to_zero = 1;
             break;
+#endif
         }
     }
-    g_assert_not_reached();
+    assert(false);
 }

 static uint64_t count_errors(void)
diff --git a/tests/tcg/Makefile b/tests/tcg/Makefile
index 2bba0d2a32..9c8011063e 100644
--- a/tests/tcg/Makefile
+++ b/tests/tcg/Makefile
@@ -24,6 +24,9 @@
 VPATH = $(SRC_PATH)/tests/tcg/multiarch
 TEST_SRCS = $(wildcard $(SRC_PATH)/tests/tcg/multiarch/*.c)

+VPATH     += $(SRC_PATH)/tests/fp
+TEST_SRCS += $(wildcard $(SRC_PATH)/tests/fp/*.c)
+
 VPATH     += $(SRC_PATH)/tests/tcg/$(ARCH)
 TEST_SRCS += $(wildcard $(SRC_PATH)/tests/tcg/$(ARCH)/*.c)

--
2.16.2
--8<---------------cut here---------------end--------------->8---




--
Alex Bennée



reply via email to

[Prev in Thread] Current Thread [Next in Thread]