diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
index 27db552160..320da2398a 100644
--- a/tests/fp/fp-test.c
+++ b/tests/fp/fp-test.c
@@ -38,15 +38,167 @@ struct input {
 };
 
 enum precision {
+    PREC_HALF,
     PREC_FLOAT,
     PREC_DOUBLE,
     PREC_QUAD,
+    /* Integers */
+    PREC_INT16,
+    PREC_INT32,
+    PREC_INT64,
+    PREC_UINT16,
+    PREC_UINT32,
+    PREC_UINT64,
+    /* Float to Float conversions */
+    PREC_HALF_TO_FLOAT,
+    PREC_HALF_TO_DOUBLE,
+    PREC_FLOAT_TO_HALF,
     PREC_FLOAT_TO_DOUBLE,
+    PREC_DOUBLE_TO_HALF,
+    PREC_DOUBLE_TO_FLOAT,
+    /* Float to Int conversions */
+    PREC_HALF_TO_INT16,
+    PREC_HALF_TO_INT32,
+    PREC_HALF_TO_INT64,
+    PREC_FLOAT_TO_INT16,
+    PREC_FLOAT_TO_INT32,
+    PREC_FLOAT_TO_INT64,
+    PREC_DOUBLE_TO_INT16,
+    PREC_DOUBLE_TO_INT32,
+    PREC_DOUBLE_TO_INT64,
+    /* Float to unsigned int conversions */
+    PREC_HALF_TO_UINT16,
+    PREC_HALF_TO_UINT32,
+    PREC_HALF_TO_UINT64,
+    PREC_FLOAT_TO_UINT16,
+    PREC_FLOAT_TO_UINT32,
+    PREC_FLOAT_TO_UINT64,
+    PREC_DOUBLE_TO_UINT16,
+    PREC_DOUBLE_TO_UINT32,
+    PREC_DOUBLE_TO_UINT64,
+    /* Int to float conversions */
+    PREC_INT16_TO_HALF,
+    PREC_INT16_TO_FLOAT,
+    PREC_INT16_TO_DOUBLE,
+    PREC_INT32_TO_HALF,
+    PREC_INT32_TO_FLOAT,
+    PREC_INT32_TO_DOUBLE,
+    PREC_INT64_TO_HALF,
+    PREC_INT64_TO_FLOAT,
+    PREC_INT64_TO_DOUBLE,
+    /* Unsigned int to float conversions */
+    PREC_UINT16_TO_HALF,
+    PREC_UINT16_TO_FLOAT,
+    PREC_UINT16_TO_DOUBLE,
+    PREC_UINT32_TO_HALF,
+    PREC_UINT32_TO_FLOAT,
+    PREC_UINT32_TO_DOUBLE,
+    PREC_UINT64_TO_HALF,
+    PREC_UINT64_TO_FLOAT,
+    PREC_UINT64_TO_DOUBLE,
 };
 
+static enum precision get_input_prec(enum precision prec)
+{
+    /* Map conversions to input precision */
+    if (prec >= PREC_HALF_TO_FLOAT) {
+        switch (prec) {
+        case PREC_HALF_TO_FLOAT:
+        case PREC_HALF_TO_DOUBLE:
+        case PREC_HALF_TO_INT16:
+        case PREC_HALF_TO_INT32:
+        case PREC_HALF_TO_INT64:
+        case PREC_HALF_TO_UINT16:
+        case PREC_HALF_TO_UINT32:
+        case PREC_HALF_TO_UINT64:
+            return PREC_HALF;
+        case PREC_FLOAT_TO_HALF:
+        case PREC_FLOAT_TO_DOUBLE:
+        case PREC_FLOAT_TO_INT16:
+        case PREC_FLOAT_TO_INT32:
+        case PREC_FLOAT_TO_INT64:
+        case PREC_FLOAT_TO_UINT16:
+        case PREC_FLOAT_TO_UINT32:
+        case PREC_FLOAT_TO_UINT64:
+            return PREC_FLOAT;
+        case PREC_DOUBLE_TO_HALF:
+        case PREC_DOUBLE_TO_FLOAT:
+        case PREC_DOUBLE_TO_INT16:
+        case PREC_DOUBLE_TO_INT32:
+        case PREC_DOUBLE_TO_INT64:
+        case PREC_DOUBLE_TO_UINT16:
+        case PREC_DOUBLE_TO_UINT32:
+        case PREC_DOUBLE_TO_UINT64:
+            return PREC_DOUBLE;
+        default:
+            assert(false);
+        }
+    }
+
+    return prec;
+}
+
+static enum precision get_output_prec(enum precision prec)
+{
+    /* Map conversions to input precision */
+    if (prec >= PREC_HALF_TO_FLOAT) {
+        switch (prec) {
+        case PREC_FLOAT_TO_HALF:
+        case PREC_DOUBLE_TO_HALF:
+        case PREC_INT16_TO_HALF:
+        case PREC_INT32_TO_HALF:
+        case PREC_INT64_TO_HALF:
+        case PREC_UINT16_TO_HALF:
+        case PREC_UINT32_TO_HALF:
+        case PREC_UINT64_TO_HALF:
+            return PREC_HALF;
+        case PREC_HALF_TO_FLOAT:
+        case PREC_DOUBLE_TO_FLOAT:
+            return PREC_FLOAT;
+        case PREC_HALF_TO_DOUBLE:
+        case PREC_FLOAT_TO_DOUBLE:
+            return PREC_DOUBLE;
+        case PREC_HALF_TO_INT16:
+        case PREC_FLOAT_TO_INT16:
+        case PREC_DOUBLE_TO_INT16:
+            return PREC_INT16;
+        case PREC_HALF_TO_INT32:
+        case PREC_FLOAT_TO_INT32:
+        case PREC_DOUBLE_TO_INT32:
+            return PREC_INT32;
+        case PREC_HALF_TO_INT64:
+        case PREC_FLOAT_TO_INT64:
+        case PREC_DOUBLE_TO_INT64:
+            return PREC_INT64;
+        case PREC_HALF_TO_UINT16:
+        case PREC_FLOAT_TO_UINT16:
+        case PREC_DOUBLE_TO_UINT16:
+            return PREC_UINT16;
+        case PREC_HALF_TO_UINT32:
+        case PREC_FLOAT_TO_UINT32:
+        case PREC_DOUBLE_TO_UINT32:
+            return PREC_UINT32;
+        case PREC_HALF_TO_UINT64:
+        case PREC_FLOAT_TO_UINT64:
+        case PREC_DOUBLE_TO_UINT64:
+            return PREC_UINT64;
+        default:
+            assert(false);
+        }
+    }
+
+    return prec;
+}
+
+typedef struct {
+    char *opstr;
+    enum precision prec;
+} map_to_prec;
+
 struct op_desc {
     const char * const name;
     int n_operands;
+    map_to_prec *decode_tbl;
 };
 
 enum op {
@@ -62,9 +214,46 @@ enum op {
     OP_ABS,
     OP_IS_NAN,
     OP_IS_INF,
-    OP_FLOAT_TO_DOUBLE,
+    /* All above are conversions */
+    OP_FLOAT_TO_FLOAT,
+    OP_FLOAT_TO_INT,
+    OP_FLOAT_TO_UINT,
+    OP_INT_TO_FLOAT,
+    OP_UINT_TO_FLOAT
 };
 
+map_to_prec float_to_float[] = { {"b16b32", PREC_HALF_TO_FLOAT},
+                                 {"b16b64", PREC_HALF_TO_DOUBLE},
+                                 {"b32b16", PREC_FLOAT_TO_HALF},
+                                 {"b32b64", PREC_FLOAT_TO_DOUBLE},
+                                 {"b64b16", PREC_DOUBLE_TO_HALF},
+                                 {"b64b32", PREC_DOUBLE_TO_FLOAT},
+                                 { NULL, 0} };
+
+map_to_prec float_to_int[] = { {"b16b16", PREC_HALF_TO_INT16},
+                               {"b16b32", PREC_HALF_TO_INT16},
+                               {"b16b64", PREC_HALF_TO_INT16},
+                               {"b32b16", PREC_FLOAT_TO_INT16},
+                               {"b32b32", PREC_FLOAT_TO_INT32},
+                               {"b32b64", PREC_FLOAT_TO_INT64},
+                               {"b64b16", PREC_DOUBLE_TO_INT16},
+                               {"b64b32", PREC_DOUBLE_TO_INT32},
+                               {"b64b64", PREC_DOUBLE_TO_INT64},
+                               { NULL, 0} };
+
+static enum precision decode_map_table(map_to_prec *tbl, char *opstr)
+{
+    while (tbl->opstr) {
+        if (strncmp(tbl->opstr, opstr, strlen(tbl->opstr)) == 0) {
+            return tbl->prec;
+        }
+        tbl++;
+    }
+
+    /* lookup failed */
+    assert(false);
+}
+
 static const struct op_desc ops[] = {
     [OP_ADD] =       { "+", 2 },
     [OP_SUB] =       { "-", 2 },
@@ -78,7 +267,11 @@ static const struct op_desc ops[] = {
     [OP_ABS] =       { "A", 1 },
     [OP_IS_NAN] =    { "?N", 1 },
     [OP_IS_INF] =    { "?i", 1 },
-    [OP_FLOAT_TO_DOUBLE] = { "cff", 1 },
+    [OP_FLOAT_TO_FLOAT] = { "cff", 1, float_to_float },
+    [OP_FLOAT_TO_INT] = { "cfi", 1, float_to_int },
+    [OP_FLOAT_TO_UINT] = { "cfu", 1 },
+    [OP_INT_TO_FLOAT] = { "cif", 1 },
+    [OP_UINT_TO_FLOAT] = { "cuf", 1 },
 };
 
 /*
@@ -269,6 +462,159 @@ static enum error tester_check(const struct test_op *t, uint64_t res64,
     return err;
 }
 
+static float get_float(struct operand op)
+{
+    switch (op.type) {
+    case OP_TYPE_QNAN:
+        return __builtin_nanf("");
+    case OP_TYPE_SNAN:
+        return __builtin_nansf("");
+    default:
+        return u64_to_float(op.val);
+    }
+}
+
+static double get_double(struct operand op)
+{
+    switch (op.type) {
+    case OP_TYPE_QNAN:
+        return __builtin_nanf("");
+    case OP_TYPE_SNAN:
+        return __builtin_nansf("");
+    default:
+        return u64_to_double(op.val);
+    }
+}
+
+static enum error host_tester_cff(struct test_op *t)
+{
+    float in32, res32;
+    double in64, res64;
+    bool result_is_nan;
+    uint8_t flags = 0;
+
+    assert(t->op == OP_FLOAT_TO_FLOAT);
+
+    switch (t->prec) {
+    case PREC_HALF_TO_FLOAT:
+    case PREC_HALF_TO_DOUBLE:
+        return ERROR_NOT_HANDLED;
+    case PREC_FLOAT_TO_HALF:
+        return ERROR_NOT_HANDLED;
+    case PREC_FLOAT_TO_DOUBLE:
+    {
+        in32 = get_float(t->operands[0]);
+        t->expected_result.val = double_to_u64(get_double(t->expected_result));
+        res64 = (double) in32;
+        break;
+    }
+    case PREC_DOUBLE_TO_HALF:
+        return ERROR_NOT_HANDLED;
+    case PREC_DOUBLE_TO_FLOAT:
+        in64 = get_double(t->operands[0]);
+        t->expected_result.val = float_to_u64(get_float(t->expected_result));
+        res32 = (float) in64;
+        break;
+    default:
+        return ERROR_NOT_HANDLED;
+    }
+
+    flags = host_get_exceptions();
+
+    switch (t->prec) {
+    case PREC_HALF_TO_DOUBLE:
+    case PREC_FLOAT_TO_DOUBLE:
+        result_is_nan = isnan(res64);
+        return tester_check(t, res64, result_is_nan, flags);
+    case PREC_HALF_TO_FLOAT:
+    case PREC_DOUBLE_TO_FLOAT:
+        result_is_nan = isnan(res32);
+        return tester_check(t, res32, result_is_nan, flags);
+    default:
+        assert(false);
+    }
+
+    return ERROR_NOT_HANDLED;
+}
+
+static enum error host_tester_cfi(struct test_op *t)
+{
+    uint8_t flags = 0;
+    float in32;
+    double in64;
+    uint64_t res;
+
+    assert(t->op == OP_FLOAT_TO_INT || t->op == OP_FLOAT_TO_UINT);
+
+    switch (get_input_prec(t->prec)) {
+    case PREC_HALF:
+        return ERROR_NOT_HANDLED;
+    case PREC_FLOAT:
+        in32 = get_float(t->operands[0]);
+        break;
+    case PREC_DOUBLE:
+        in64 = get_double(t->operands[0]);
+        break;
+    default:
+        assert(false);
+    }
+
+
+    switch (t->prec) {
+    case PREC_HALF_TO_INT16:
+    case PREC_HALF_TO_INT32:
+    case PREC_HALF_TO_INT64:
+        return ERROR_NOT_HANDLED;
+    case PREC_FLOAT_TO_INT16:
+    {
+        int16_t oi16 = (int16_t) in32;
+        res = (uint64_t) oi16;
+        break;
+    }
+    case PREC_FLOAT_TO_INT32:
+    {
+        int32_t oi32 = (int32_t) in32;
+        res = (uint64_t) oi32;
+        break;
+    }
+    case PREC_FLOAT_TO_INT64:
+    {
+        int64_t oi64 = (int64_t) in32;
+        res = (uint64_t) oi64;
+        break;
+    }
+    case PREC_DOUBLE_TO_INT16:
+    {
+        int16_t oi16 = (int16_t) in64;
+        res = (uint64_t) oi16;
+        break;
+    }
+    case PREC_DOUBLE_TO_INT32:
+    {
+        int32_t oi32 = (int32_t) in64;
+        res = (uint64_t) oi32;
+        break;
+    }
+    case PREC_DOUBLE_TO_INT64:
+    {
+        int64_t oi64 = (int64_t) in64;
+        res = (uint64_t) oi64;
+        break;
+    }
+    default:
+        assert(false);
+    }
+
+    flags = host_get_exceptions();
+
+    return tester_check(t, res, false, flags);
+}
+
+static enum error host_tester_cif(struct test_op *t)
+{
+    return ERROR_NOT_HANDLED;
+}
+
 static enum error host_tester(struct test_op *t)
 {
     uint64_t res64;
@@ -280,6 +626,20 @@ static enum error host_tester(struct test_op *t)
         host_set_exceptions(default_exceptions);
     }
 
+    /* Handle conversions first */
+    switch (t->op) {
+    case OP_FLOAT_TO_FLOAT:
+        return host_tester_cff(t);
+    case OP_FLOAT_TO_INT:
+    case OP_FLOAT_TO_UINT:
+        return host_tester_cfi(t);
+    case OP_INT_TO_FLOAT:
+    case OP_UINT_TO_FLOAT:
+        return host_tester_cif(t);
+    default:
+        break;
+    }
+
     if (t->prec == PREC_FLOAT) {
         float a, b, c;
         float *in[] = { &a, &b, &c };
@@ -396,40 +756,68 @@ static enum error host_tester(struct test_op *t)
         flags = host_get_exceptions();
         res64 = double_to_u64(res);
         result_is_nan = isnan(res);
-    } else if (t->prec == PREC_FLOAT_TO_DOUBLE) {
-        float a;
-        double res;
-
-        if (t->operands[0].type == OP_TYPE_QNAN) {
-            a = __builtin_nanf("");
-        } else if (t->operands[0].type == OP_TYPE_SNAN) {
-            a = __builtin_nansf("");
-        } else {
-            a = u64_to_float(t->operands[0].val);
-        }
-
-        if (t->expected_result.type == OP_TYPE_QNAN) {
-            t->expected_result.val = double_to_u64(__builtin_nan(""));
-        } else if (t->expected_result.type == OP_TYPE_SNAN) {
-            t->expected_result.val = double_to_u64(__builtin_nans(""));
-        }
-
-        switch (t->op) {
-        case OP_FLOAT_TO_DOUBLE:
-            res = a;
-            break;
-        default:
-            return ERROR_NOT_HANDLED;
-        }
-        flags = host_get_exceptions();
-        res64 = double_to_u64(res);
-        result_is_nan = isnan(res);
     } else {
         return ERROR_NOT_HANDLED; /* XXX */
     }
     return tester_check(t, res64, result_is_nan, flags);
 }
 
+static enum error soft_tester_cff(struct test_op *t, float_status *s)
+{
+    float in32, res32;
+    double in64, res64;
+    bool result_is_nan;
+
+    assert(t->op == OP_FLOAT_TO_FLOAT);
+
+    switch (t->prec) {
+    case PREC_HALF_TO_FLOAT:
+    case PREC_HALF_TO_DOUBLE:
+        return ERROR_NOT_HANDLED;
+    case PREC_FLOAT_TO_HALF:
+        return ERROR_NOT_HANDLED;
+    case PREC_FLOAT_TO_DOUBLE:
+    {
+        in32 = get_float(t->operands[0]);
+        t->expected_result.val = double_to_u64(get_double(t->expected_result));
+        res64 = float32_to_float64(in32, s);
+        break;
+    }
+    case PREC_DOUBLE_TO_HALF:
+        return ERROR_NOT_HANDLED;
+    case PREC_DOUBLE_TO_FLOAT:
+        in64 = get_double(t->operands[0]);
+        t->expected_result.val = float_to_u64(get_float(t->expected_result));
+        res32 = float64_to_float32(in64, s);
+        break;
+    default:
+        return ERROR_NOT_HANDLED;
+    }
+
+    switch (t->prec) {
+    case PREC_HALF_TO_DOUBLE:
+    case PREC_FLOAT_TO_DOUBLE:
+        result_is_nan = isnan(res64);
+        return tester_check(t, res64, result_is_nan, s->float_exception_flags);
+    case PREC_HALF_TO_FLOAT:
+    case PREC_DOUBLE_TO_FLOAT:
+        result_is_nan = isnan(res32);
+        return tester_check(t, res32, result_is_nan, s->float_exception_flags);
+    default:
+        assert(false);
+    }
+}
+
+static enum error soft_tester_cfi(struct test_op *t, float_status *s)
+{
+    return ERROR_NOT_HANDLED;
+}
+
+static enum error soft_tester_cif(struct test_op *t, float_status *s)
+{
+    return ERROR_NOT_HANDLED;
+}
+
 static enum error soft_tester(struct test_op *t)
 {
     float_status *s = &soft_status;
@@ -440,6 +828,20 @@ static enum error soft_tester(struct test_op *t)
     s->float_rounding_mode = t->round;
     s->float_exception_flags = default_exceptions;
 
+    /* Handle conversions first */
+    switch (t->op) {
+    case OP_FLOAT_TO_FLOAT:
+        return soft_tester_cff(t, s);
+    case OP_FLOAT_TO_INT:
+    case OP_FLOAT_TO_UINT:
+        return soft_tester_cfi(t, s);
+    case OP_INT_TO_FLOAT:
+    case OP_UINT_TO_FLOAT:
+        return soft_tester_cif(t, s);
+    default:
+        break;
+    }
+
     if (t->prec == PREC_FLOAT) {
         float32 a, b, c;
         float32 *in[] = { &a, &b, &c };
@@ -558,17 +960,6 @@ static enum error soft_tester(struct test_op *t)
             return ERROR_NOT_HANDLED;
         }
         result_is_nan = isnan(*(double *)&res64);
-    } else if (t->prec == PREC_FLOAT_TO_DOUBLE) {
-        float32 a = t->operands[0].val;
-
-        switch (t->op) {
-        case OP_FLOAT_TO_DOUBLE:
-            res64 = float32_to_float64(a, s);
-            break;
-        default:
-            return ERROR_NOT_HANDLED;
-        }
-        result_is_nan = isnan(*(double *)&res64);
     } else {
         return ERROR_NOT_HANDLED; /* XXX */
     }
@@ -752,23 +1143,41 @@ ibm_fp_hex(const char *p, enum precision prec, struct operand *ret)
             return 0;
         }
         return 0;
-    } else if (!strcmp(p, "0x0")) {
-        if (prec == PREC_FLOAT) {
-            ret->val = float_to_u64(0.0);
-        } else if (prec == PREC_DOUBLE) {
-            ret->val = double_to_u64(0.0);
-        } else {
-            assert(false);
+    } else if (strncmp("0x", p, 2) == 0) {
+        unsigned long long result;
+        char *end;
+
+        result = strtoull(p, &end, 16);
+        if (result == 0 && end == p) {
+            /* not a number */
+            return 1;
+        } else if (result == ULLONG_MAX && errno) {
+            /* value does not fit in unsigned long long */
+            return 1;
+        } else if (*end) {
+            /* began with a number but has junk left over at the end */
+            return 1;
         }
-        return 0;
-    } else if (!strcmp(p, "0x1")) {
-        if (prec == PREC_FLOAT) {
-            ret->val = float_to_u64(1.0);
-        } else if (prec == PREC_DOUBLE) {
-            ret->val = double_to_u64(1.0);
-        } else {
+
+        switch (prec) {
+        case PREC_FLOAT:
+            ret->val = float_to_u64(result);
+            break;
+        case PREC_DOUBLE:
+            ret->val = double_to_u64(result);
+            break;
+        case PREC_INT16:
+        case PREC_INT32:
+        case PREC_INT64:
+        case PREC_UINT16:
+        case PREC_UINT32:
+        case PREC_UINT64:
+            ret->val = result;
+            break;
+        default:
             assert(false);
         }
+
         return 0;
     }
     return 1;
@@ -814,11 +1223,14 @@ static enum error ibm_test_line(const char *line)
     if (unlikely(strlen(p) < 4)) {
         return ERROR_INPUT;
     }
-    if (strcmp("b32b64cff", p) == 0) {
-        t.prec = PREC_FLOAT_TO_DOUBLE;
+    /* Conversions are of the form bXXbYYcZZ */
+    if (p[0] == 'b' && p[3] == 'b' && p[6] == 'c') {
         if (find_op(&p[6], &t.op)) {
+            fprintf(stderr, "%s: unhandled conversion %s\n", __func__, p);
             return ERROR_NOT_HANDLED;
         }
+        assert(ops[t.op].decode_tbl);
+        t.prec = decode_map_table(ops[t.op].decode_tbl, p);
     } else {
         if (strncmp("b32", p, 3) == 0) {
             t.prec = PREC_FLOAT;
@@ -855,9 +1267,7 @@ static enum error ibm_test_line(const char *line)
     }
 
     for (i = 0; i < ops[t.op].n_operands; i++) {
-        enum precision prec = t.prec == PREC_FLOAT_TO_DOUBLE ?
-            PREC_FLOAT : t.prec;
-
+        enum precision prec = get_input_prec(t.prec);
         p = s[field++];
         if (ibm_fp_hex(p, prec, &t.operands[i])) {
             return ERROR_INPUT;
@@ -873,8 +1283,7 @@ static enum error ibm_test_line(const char *line)
     if (unlikely(strcmp("#", p) == 0)) {
         t.expected_result_is_valid = false;
     } else {
-        enum precision prec = t.prec == PREC_FLOAT_TO_DOUBLE ?
-            PREC_DOUBLE : t.prec;
+        enum precision prec = get_output_prec(t.prec);
 
         if (ibm_fp_hex(p, prec, &t.expected_result)) {
             return ERROR_INPUT;
@@ -943,7 +1352,7 @@ static void test_file(const char *filename)
         enum error err;
 
         i++;
-        if (unlikely(line_is_whitelisted(line))) {
+        if (whitelist.n > 0 && unlikely(line_is_whitelisted(line))) {
             test_stats[ERROR_WHITELISTED]++;
             continue;
         }
diff --git a/tests/fp/qemu/regression-tests.fptest b/tests/fp/qemu/regression-tests.fptest
new file mode 100644
index 0000000000..a105d3aa44
--- /dev/null
+++ b/tests/fp/qemu/regression-tests.fptest
@@ -0,0 +1,7 @@
+QEMU Floating point regression tests
+------------------------------------
+
+b32b32cfi =0 -Inf -> 0xffffffff80000000 i
+b32b32cfi =0 +Inf -> 0xffffffff80000000 i
+b32b64cfi =0 -Inf -> 0x8000000000000000 i
+b32b64cfi =0 +Inf -> 0x8000000000000000 i
