Add V6_vcvt2_{hf_ub,hf_b,ub_hf,b_hf}, which differ from vcvt only in
element interleaving.

Reviewed-by: Pierrick Bouvier <[email protected]>
Reviewed-by: Marco Liebel <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 tests/tcg/hexagon/check_rev_gating.c         |   6 +
 tests/tcg/hexagon/fp_hvx_v79.c               | 110 +++++++++++++++++++
 target/hexagon/tag_rev_info.c.inc            |   4 +
 target/hexagon/imported/mmvec/encode_ext.def |   4 +
 target/hexagon/imported/mmvec/ext.idef       |  33 ++++++
 tests/tcg/hexagon/meson.build                |   2 +
 6 files changed, 159 insertions(+)
 create mode 100644 tests/tcg/hexagon/fp_hvx_v79.c

diff --git a/tests/tcg/hexagon/check_rev_gating.c 
b/tests/tcg/hexagon/check_rev_gating.c
index 3a5ed9c71ca..529cae70d85 100644
--- a/tests/tcg/hexagon/check_rev_gating.c
+++ b/tests/tcg/hexagon/check_rev_gating.c
@@ -131,6 +131,10 @@ TRY_FUNC(v83_vsfadd,
 
 TRY_FUNC(v79hvx_vmerge_qf,
          ".word 0x1f01e0e2    /* v2 = vmerge(v0.x, v1.w) */\n")
+TRY_FUNC(v79hvx_vcvt2_hf_ub,
+         ".word 0x1ed5e0e2    /* v3:2.hf = vcvt2(v0.ub) */\n")
+TRY_FUNC(v79hvx_vcvt2_b_hf,
+         ".word 0x1ac1e0c2    /* v2.b = vcvt2(v0.hf, v1.hf) */\n")
 
 TRY_FUNC(v81hvx_veqhf,
          ".word 0x1f82c11c    /* q0 = vcmp.eq(v1.hf, v2.hf) */\n")
@@ -177,6 +181,8 @@ int main(void)
     assert(try_v83_vsfadd() == SIGILL);
 
     assert(try_v79hvx_vmerge_qf() == SIGILL);
+    assert(try_v79hvx_vcvt2_hf_ub() == SIGILL);
+    assert(try_v79hvx_vcvt2_b_hf() == SIGILL);
 
     assert(try_v81hvx_veqhf() == SIGILL);
 
diff --git a/tests/tcg/hexagon/fp_hvx_v79.c b/tests/tcg/hexagon/fp_hvx_v79.c
new file mode 100644
index 00000000000..2f6bbd7cf40
--- /dev/null
+++ b/tests/tcg/hexagon/fp_hvx_v79.c
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ *  SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+ * Tests for the HVX IEEE floating point instructions introduced in v79.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <inttypes.h>
+#include <hexagon_types.h>
+#include <hvx_hexagon_protos.h>
+
+int err;
+#include "hvx_misc.h"
+#include "hex_test.h"
+
+/*
+ * The vcvt2 instructions differ from vcvt in how elements are interleaved
+ * between the vectors of a pair or the sources:
+ *
+ *    Vdd.v[0].hf[2*i]   = OP(Vu.FROM[4*i]);
+ *    Vdd.v[0].hf[2*i+1] = OP(Vu.FROM[4*i+2]);
+ *    Vdd.v[1].hf[2*i]   = OP(Vu.FROM[4*i+1]);
+ *    Vdd.v[1].hf[2*i+1] = OP(Vu.FROM[4*i+3]);
+ *
+ *    Vd.TO[4*i]   = OP(Vu.hf[2*i]);
+ *    Vd.TO[4*i+1] = OP(Vv.hf[2*i]);
+ *    Vd.TO[4*i+2] = OP(Vu.hf[2*i+1]);
+ *    Vd.TO[4*i+3] = OP(Vv.hf[2*i+1]);
+ */
+#define DEF_TEST_VCVT2_WIDEN(FROM, MUL, ADD) \
+    static void test_vcvt2_hf_##FROM(void) \
+    { \
+        HVX_VectorPair *hvx_output = (HVX_VectorPair *)&output[0]; \
+        HVX_Vector buffer; \
+        memset(expect, 0, sizeof(expect)); \
+        for (int i = 0; i < MAX_VEC_SIZE_BYTES; i++) { \
+            ((MMVector *)&buffer)->FROM[i] = i * MUL + ADD; \
+            expect[i % 2].hf[2 * (i / 4) + ((i % 4) / 2)] = \
+                raw_hf((_Float16)(((MMVector *)&buffer)->FROM[i])); \
+        } \
+        *hvx_output = Q6_Whf_vcvt2_V##FROM(buffer); \
+        check_output_hf(__LINE__, 2); \
+    }
+
+DEF_TEST_VCVT2_WIDEN(ub, 3, 1)
+DEF_TEST_VCVT2_WIDEN(b, 5, 7)
+
+static const struct {
+    uint16_t hf;
+    uint8_t ub;
+    int8_t b;
+} cvt2_narrow_cases[] = {
+    { HF_QNaN, UINT8_MAX, INT8_MAX },
+    { HF_SNaN, UINT8_MAX, INT8_MAX },
+    { HF_QNaN_neg, UINT8_MAX, INT8_MAX },
+    { HF_INF, UINT8_MAX, INT8_MAX },
+    { HF_INF_neg, 0, INT8_MIN },
+    { HF_zero, 0, 0 },
+    { HF_zero_neg, 0, 0 },
+    { HF_neg_two, 0, -2 },
+    { HF_one, 1, 1 },
+    { 0x3e00 /* 1.5 */, 2, 2 },
+    { 0x4100 /* 2.5 */, 2, 2 },
+    { 0x4300 /* 3.5 */, 4, 4 },
+    { 0x5640 /* 100 */, 100, 100 },
+    { 0x5a40 /* 200 */, 200, INT8_MAX },
+    { 0x5c00 /* 256 */, UINT8_MAX, INT8_MAX },
+    { 0xd640 /* -100 */, 0, -100 },
+    { 0xda40 /* -200 */, 0, INT8_MIN },
+};
+#define NUM_CVT2_NARROW_CASES ARRAY_SIZE(cvt2_narrow_cases)
+
+#define DEF_TEST_VCVT2_NARROW(TO) \
+    static void test_vcvt2_##TO##_hf(void) \
+    { \
+        HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; \
+        HVX_Vector buffers[2]; \
+        memset(expect, 0, sizeof(expect)); \
+        for (int j = 0; j < MAX_VEC_SIZE_BYTES / 2; j++) { \
+            for (int s = 0; s < 2; s++) { \
+                int c = (2 * j + s) % NUM_CVT2_NARROW_CASES; \
+                ((MMVector *)&buffers[s])->hf[j] = cvt2_narrow_cases[c].hf; \
+                expect[0].TO[4 * (j / 2) + 2 * (j % 2) + s] = \
+                    cvt2_narrow_cases[c].TO; \
+            } \
+        } \
+        *hvx_output = Q6_V##TO##_vcvt2_VhfVhf(buffers[0], buffers[1]); \
+        check_output_##TO(__LINE__, 1); \
+    }
+
+DEF_TEST_VCVT2_NARROW(ub)
+DEF_TEST_VCVT2_NARROW(b)
+
+int main(void)
+{
+    test_vcvt2_hf_ub();
+    test_vcvt2_hf_b();
+    test_vcvt2_ub_hf();
+    test_vcvt2_b_hf();
+
+    puts(err ? "FAIL" : "PASS");
+    return err ? 1 : 0;
+}
diff --git a/target/hexagon/tag_rev_info.c.inc 
b/target/hexagon/tag_rev_info.c.inc
index da0b1a648cf..ea586e1613e 100644
--- a/target/hexagon/tag_rev_info.c.inc
+++ b/target/hexagon/tag_rev_info.c.inc
@@ -664,6 +664,10 @@ static const struct tag_rev_info 
tag_rev_info[XX_LAST_OPCODE] = {
         .introduced = HEX_VER_V79, .removed = HEX_VER_NONE
     },
     [V6_vconv_qf32_sf] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE 
},
+    [V6_vcvt2_b_hf] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
+    [V6_vcvt2_hf_b] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
+    [V6_vcvt2_hf_ub] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
+    [V6_vcvt2_ub_hf] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
     [V6_vilog2_hf] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
     [V6_vilog2_qf16] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
     [V6_vilog2_qf32] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
diff --git a/target/hexagon/imported/mmvec/encode_ext.def 
b/target/hexagon/imported/mmvec/encode_ext.def
index 34e63b89743..9605e870a1e 100644
--- a/target/hexagon/imported/mmvec/encode_ext.def
+++ b/target/hexagon/imported/mmvec/encode_ext.def
@@ -846,12 +846,16 @@ DEF_ENC(V6_vcvt_sf_hf,"00011110--0-0100PP1uuuuu100ddddd")
 DEF_ENC(V6_vcvt_hf_sf,"00011111011vvvvvPP1uuuuu001ddddd")
 DEF_ENC(V6_vcvt_hf_ub,"00011110--0-0100PP1uuuuu001ddddd")
 DEF_ENC(V6_vcvt_hf_b,"00011110--0-0100PP1uuuuu010ddddd")
+DEF_ENC(V6_vcvt2_hf_ub,"0001111011010101PP1uuuuu111ddddd")
+DEF_ENC(V6_vcvt2_hf_b,"0001111011010101PP1uuuuu110ddddd")
 DEF_ENC(V6_vcvt_hf_uh,"00011110--0-0100PP1uuuuu101ddddd")
 DEF_ENC(V6_vcvt_hf_h,"00011110--0-0100PP1uuuuu111ddddd")
 DEF_ENC(V6_vcvt_uh_hf,"00011110--0--101PP1uuuuu000ddddd")
 DEF_ENC(V6_vcvt_h_hf,"00011110--0-0110PP1uuuuu000ddddd")
 DEF_ENC(V6_vcvt_ub_hf,"00011111110vvvvvPP1uuuuu101ddddd")
 DEF_ENC(V6_vcvt_b_hf,"00011111110vvvvvPP1uuuuu110ddddd")
+DEF_ENC(V6_vcvt2_ub_hf,"00011010110vvvvvPP1uuuuu111ddddd")
+DEF_ENC(V6_vcvt2_b_hf,"00011010110vvvvvPP1uuuuu110ddddd")
 
 /* IEEE FP vconv instructions */
 DEF_ENC(V6_vconv_sf_w,"00011110--0--101PP1uuuuu011ddddd")
diff --git a/target/hexagon/imported/mmvec/ext.idef 
b/target/hexagon/imported/mmvec/ext.idef
index 3592930777e..b9a4858d0c1 100644
--- a/target/hexagon/imported/mmvec/ext.idef
+++ b/target/hexagon/imported/mmvec/ext.idef
@@ -3103,6 +3103,25 @@ ITERATOR_INSN_IEEE_FP_DOUBLE_16(32,  vcvt_hf_b,  
"Vdd32.hf=vcvt(Vu32.b)",
     VddV.v[1].hf[2*i]   = int64_to_float16_scalbn(VuV.b[4*i+2], 
float_round_nearest_even, 0);
     VddV.v[1].hf[2*i+1] = int64_to_float16_scalbn(VuV.b[4*i+3], 
float_round_nearest_even, 0))
 
+/*
+ * The vcvt2 variants differ from vcvt only in which source elements land in
+ * which half of the result pair: the even source bytes go to the first
+ * vector and the odd ones to the second.
+ */
+ITERATOR_INSN_IEEE_FP_DOUBLE_16(32,  vcvt2_hf_ub, "Vdd32.hf=vcvt2(Vu32.ub)",
+    "Vector IEEE cvt2 from int: ub widen to hf",
+    VddV.v[0].hf[2*i]   = uint64_to_float16_scalbn(VuV.ub[4*i], 0, 
&env->hvx_fp_status);
+    VddV.v[0].hf[2*i+1] = uint64_to_float16_scalbn(VuV.ub[4*i+2], 0, 
&env->hvx_fp_status);
+    VddV.v[1].hf[2*i]   = uint64_to_float16_scalbn(VuV.ub[4*i+1], 0, 
&env->hvx_fp_status);
+    VddV.v[1].hf[2*i+1] = uint64_to_float16_scalbn(VuV.ub[4*i+3], 0, 
&env->hvx_fp_status))
+
+ITERATOR_INSN_IEEE_FP_DOUBLE_16(32,  vcvt2_hf_b,  "Vdd32.hf=vcvt2(Vu32.b)",
+    "Vector IEEE cvt2 from int: b widen to hf",
+    VddV.v[0].hf[2*i]   = int64_to_float16_scalbn(VuV.b[4*i], 0, 
&env->hvx_fp_status);
+    VddV.v[0].hf[2*i+1] = int64_to_float16_scalbn(VuV.b[4*i+2], 0, 
&env->hvx_fp_status);
+    VddV.v[1].hf[2*i]   = int64_to_float16_scalbn(VuV.b[4*i+1], 0, 
&env->hvx_fp_status);
+    VddV.v[1].hf[2*i+1] = int64_to_float16_scalbn(VuV.b[4*i+3], 0, 
&env->hvx_fp_status))
+
 ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vcvt_sf_hf, "Vdd32.sf=vcvt(Vu32.hf)",
     "Vector IEEE cvt: hf widen to sf",
     VddV.v[0].sf[i] = f16_to_f32(VuV.hf[2*i]);
@@ -3139,6 +3158,20 @@ ITERATOR_INSN_IEEE_FP_16_32(32, vcvt_b_hf,  
"Vd32.b=vcvt(Vu32.hf,Vv32.hf)",
     VdV.b[4*i+2] = float16_to_int8_scalbn(VvV.hf[2*i], 
float_round_nearest_even, 0, &env->hvx_fp_status);
     VdV.b[4*i+3] = float16_to_int8_scalbn(VvV.hf[2*i+1], 
float_round_nearest_even, 0, &env->hvx_fp_status))
 
+ITERATOR_INSN_IEEE_FP_16_32(32, vcvt2_ub_hf, "Vd32.ub=vcvt2(Vu32.hf,Vv32.hf)",
+    "Vector cvt2 to int: hf narrow to ub",
+    VdV.ub[4*i]   = float16_to_uint8_scalbn(VuV.hf[2*i], 
float_round_nearest_even, 0, &env->hvx_fp_status);
+    VdV.ub[4*i+1] = float16_to_uint8_scalbn(VvV.hf[2*i], 
float_round_nearest_even, 0, &env->hvx_fp_status);
+    VdV.ub[4*i+2] = float16_to_uint8_scalbn(VuV.hf[2*i+1], 
float_round_nearest_even, 0, &env->hvx_fp_status);
+    VdV.ub[4*i+3] = float16_to_uint8_scalbn(VvV.hf[2*i+1], 
float_round_nearest_even, 0, &env->hvx_fp_status))
+
+ITERATOR_INSN_IEEE_FP_16_32(32, vcvt2_b_hf,  "Vd32.b=vcvt2(Vu32.hf,Vv32.hf)",
+    "Vector cvt2 to int: hf narrow to b",
+    VdV.b[4*i]   = float16_to_int8_scalbn(VuV.hf[2*i], 
float_round_nearest_even, 0, &env->hvx_fp_status);
+    VdV.b[4*i+1] = float16_to_int8_scalbn(VvV.hf[2*i], 
float_round_nearest_even, 0, &env->hvx_fp_status);
+    VdV.b[4*i+2] = float16_to_int8_scalbn(VuV.hf[2*i+1], 
float_round_nearest_even, 0, &env->hvx_fp_status);
+    VdV.b[4*i+3] = float16_to_int8_scalbn(VvV.hf[2*i+1], 
float_round_nearest_even, 0, &env->hvx_fp_status))
+
 ITERATOR_INSN_SHIFT_SLOT_FLT(32, vconv_w_sf,"Vd32.w=Vu32.sf",
     "Vector conversion of sf32 format to int w",
     VdV.w[i] = conv_w_sf(VuV.sf[i], &env->hvx_fp_status))
diff --git a/tests/tcg/hexagon/meson.build b/tests/tcg/hexagon/meson.build
index 2b924598640..c38d2bea84f 100644
--- a/tests/tcg/hexagon/meson.build
+++ b/tests/tcg/hexagon/meson.build
@@ -54,6 +54,8 @@ tests += {
                         'qemu_args': ['-cpu', 'v73,ieee-fp=false']},
   'fp_hvx_cvt.c': {'cflags': [cflags, '-mv73', '-mhvx', '-mhvx-ieee-fp']},
   'fp_hvx_cmp.c': {'cflags': [cflags, '-mv73', '-mhvx', '-mhvx-ieee-fp']},
+  'fp_hvx_v79.c': {'cflags': [cflags, '-mv79', '-mhvx', '-mhvx-ieee-fp'],
+                   'qemu_args': ['-cpu', 'v79']},
   'v81_hvx.c': {'cflags': [cflags, '-mv81', '-mhvx', '-mhvx-ieee-fp'],
                'qemu_args': ['-cpu', 'v81']},
   'qfloat_v81.c': {'cflags': [cflags, '-mv81', '-mhvx', '-mhvx-ieee-fp'],
-- 
2.34.1

Reply via email to