Add halfword greater-than compares and out-of-line helpers for
truncating and rounding halfword averages.

Signed-off-by: Marco Liebel <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 target/hexagon/helper.h          |  10 +++
 target/hexagon/hex_common.py     |  16 +++++
 target/hexagon/hlx_gvec_tables.c | 105 +++++++++++++++++++++++++++++++
 target/hexagon/hlx_gvec_tables.h |   5 ++
 target/hexagon/hlx_helper.c      |  52 +++++++++++++++
 5 files changed, 188 insertions(+)

diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 471ef0903b..f42cb8d9b6 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -44,6 +44,16 @@ DEF_HELPER_FLAGS_4(hlx_gvec_ushsat_sub16, TCG_CALL_NO_RWG,
                    void, ptr, ptr, ptr, i32)
 DEF_HELPER_FLAGS_3(hlx_gvec_abs_uh_sat16, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
 
+/* GVec helpers for MO_16 averages. */
+DEF_HELPER_FLAGS_4(hlx_gvec_avg_sh16, TCG_CALL_NO_RWG,
+                   void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(hlx_gvec_avg_sh16_rnd, TCG_CALL_NO_RWG,
+                   void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(hlx_gvec_avg_uh16, TCG_CALL_NO_RWG,
+                   void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(hlx_gvec_avg_uh16_rnd, TCG_CALL_NO_RWG,
+                   void, ptr, ptr, ptr, i32)
+
 /* Floating point */
 DEF_HELPER_3(conv_sf2df, f64, env, f32, i32)
 DEF_HELPER_3(conv_df2sf, f32, env, f64, i32)
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index 3f4d796a98..d0b36b8e06 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -388,6 +388,22 @@ def skip_qemu_helper(tag):
                          "vece": "MO_16", "size": "2 * sizeof(HLXVector)"},
     "LX_abs_uh_sat":    {"op": "gvec2", "table": "hlx_abs_uh_sat_op",
                          "vece": "MO_16"},
+    "LX_cmp_gt_h":   {"op": "cmp",    "cond": "TCG_COND_GT",
+                      "vece": "MO_16"},
+    "LX_cmp_gt_uh":  {"op": "cmp",    "cond": "TCG_COND_GTU",
+                      "vece": "MO_16"},
+    "LX_cmp_gt_hp":  {"op": "cmp",    "cond": "TCG_COND_GT",
+                      "vece": "MO_16",   "size": "2 * sizeof(HLXVector)"},
+    "LX_cmp_gt_uhp": {"op": "cmp",    "cond": "TCG_COND_GTU",
+                      "vece": "MO_16",   "size": "2 * sizeof(HLXVector)"},
+    "LX_avg_h":         {"op": "gvec3", "table": "hlx_avg_sh_op",
+                         "vece": "MO_16"},
+    "LX_avg_h_rnd":     {"op": "gvec3", "table": "hlx_avg_sh_rnd_op",
+                         "vece": "MO_16"},
+    "LX_avg_uh":        {"op": "gvec3", "table": "hlx_avg_uh_op",
+                         "vece": "MO_16"},
+    "LX_avg_uh_rnd":    {"op": "gvec3", "table": "hlx_avg_uh_rnd_op",
+                         "vece": "MO_16"},
 }
 
 def is_hlx_inline_tag(tag):
diff --git a/target/hexagon/hlx_gvec_tables.c b/target/hexagon/hlx_gvec_tables.c
index dd5aa788e0..a5d40e149c 100644
--- a/target/hexagon/hlx_gvec_tables.c
+++ b/target/hexagon/hlx_gvec_tables.c
@@ -111,3 +111,108 @@ const GVecGen2 hlx_abs_uh_sat_op = {
     .fno     = gen_helper_hlx_gvec_abs_uh_sat16,
     .vece    = MO_16,
 };
+
+/* Halfword averages. The shift is arithmetic or logical by signedness. */
+static void hlx_fniv_avg_sh(unsigned vece, TCGv_vec r,
+                             TCGv_vec a, TCGv_vec b)
+{
+    TCGv_vec ta = tcg_temp_new_vec_matching(r);
+    TCGv_vec tb = tcg_temp_new_vec_matching(r);
+    tcg_gen_and_vec(vece, ta, a, b);
+    tcg_gen_xor_vec(vece, tb, a, b);
+    tcg_gen_sari_vec(vece, tb, tb, 1);
+    tcg_gen_add_vec(vece, r, ta, tb);
+}
+
+static void hlx_fniv_avg_sh_rnd(unsigned vece, TCGv_vec r,
+                                 TCGv_vec a, TCGv_vec b)
+{
+    TCGv_vec ta = tcg_temp_new_vec_matching(r);
+    TCGv_vec tb = tcg_temp_new_vec_matching(r);
+    tcg_gen_or_vec(vece, ta, a, b);
+    tcg_gen_xor_vec(vece, tb, a, b);
+    tcg_gen_sari_vec(vece, tb, tb, 1);
+    tcg_gen_sub_vec(vece, r, ta, tb);
+}
+
+static void hlx_fniv_avg_uh(unsigned vece, TCGv_vec r,
+                             TCGv_vec a, TCGv_vec b)
+{
+    TCGv_vec ta = tcg_temp_new_vec_matching(r);
+    TCGv_vec tb = tcg_temp_new_vec_matching(r);
+    tcg_gen_and_vec(vece, ta, a, b);
+    tcg_gen_xor_vec(vece, tb, a, b);
+    tcg_gen_shri_vec(vece, tb, tb, 1);
+    tcg_gen_add_vec(vece, r, ta, tb);
+}
+
+static void hlx_fniv_avg_uh_rnd(unsigned vece, TCGv_vec r,
+                                  TCGv_vec a, TCGv_vec b)
+{
+    TCGv_vec ta = tcg_temp_new_vec_matching(r);
+    TCGv_vec tb = tcg_temp_new_vec_matching(r);
+    tcg_gen_or_vec(vece, ta, a, b);
+    tcg_gen_xor_vec(vece, tb, a, b);
+    tcg_gen_shri_vec(vece, tb, tb, 1);
+    tcg_gen_sub_vec(vece, r, ta, tb);
+}
+
+static const TCGOpcode hlx_vecop_avg_sh[] = {
+    INDEX_op_and_vec,
+    INDEX_op_xor_vec,
+    INDEX_op_sari_vec,
+    INDEX_op_add_vec,
+    0
+};
+
+static const TCGOpcode hlx_vecop_avg_sh_rnd[] = {
+    INDEX_op_or_vec,
+    INDEX_op_xor_vec,
+    INDEX_op_sari_vec,
+    INDEX_op_sub_vec,
+    0
+};
+
+static const TCGOpcode hlx_vecop_avg_uh[] = {
+    INDEX_op_and_vec,
+    INDEX_op_xor_vec,
+    INDEX_op_shri_vec,
+    INDEX_op_add_vec,
+    0
+};
+
+static const TCGOpcode hlx_vecop_avg_uh_rnd[] = {
+    INDEX_op_or_vec,
+    INDEX_op_xor_vec,
+    INDEX_op_shri_vec,
+    INDEX_op_sub_vec,
+    0
+};
+
+const GVecGen3 hlx_avg_sh_op = {
+    .fniv    = hlx_fniv_avg_sh,
+    .opt_opc = hlx_vecop_avg_sh,
+    .fno     = gen_helper_hlx_gvec_avg_sh16,
+    .vece    = MO_16,
+};
+
+const GVecGen3 hlx_avg_sh_rnd_op = {
+    .fniv    = hlx_fniv_avg_sh_rnd,
+    .opt_opc = hlx_vecop_avg_sh_rnd,
+    .fno     = gen_helper_hlx_gvec_avg_sh16_rnd,
+    .vece    = MO_16,
+};
+
+const GVecGen3 hlx_avg_uh_op = {
+    .fniv    = hlx_fniv_avg_uh,
+    .opt_opc = hlx_vecop_avg_uh,
+    .fno     = gen_helper_hlx_gvec_avg_uh16,
+    .vece    = MO_16,
+};
+
+const GVecGen3 hlx_avg_uh_rnd_op = {
+    .fniv    = hlx_fniv_avg_uh_rnd,
+    .opt_opc = hlx_vecop_avg_uh_rnd,
+    .fno     = gen_helper_hlx_gvec_avg_uh16_rnd,
+    .vece    = MO_16,
+};
diff --git a/target/hexagon/hlx_gvec_tables.h b/target/hexagon/hlx_gvec_tables.h
index 55ab6bb63f..e01c853eb1 100644
--- a/target/hexagon/hlx_gvec_tables.h
+++ b/target/hexagon/hlx_gvec_tables.h
@@ -12,4 +12,9 @@ extern const GVecGen3 hlx_ushsat_add_op;
 extern const GVecGen3 hlx_ushsat_sub_op;
 extern const GVecGen2 hlx_abs_uh_sat_op;
 
+extern const GVecGen3 hlx_avg_sh_op;
+extern const GVecGen3 hlx_avg_sh_rnd_op;
+extern const GVecGen3 hlx_avg_uh_op;
+extern const GVecGen3 hlx_avg_uh_rnd_op;
+
 #endif /* HLX_GVEC_TABLES_H */
diff --git a/target/hexagon/hlx_helper.c b/target/hexagon/hlx_helper.c
index 906f31ba17..c624b66f83 100644
--- a/target/hexagon/hlx_helper.c
+++ b/target/hexagon/hlx_helper.c
@@ -143,3 +143,55 @@ void HELPER(hlx_gvec_abs_uh_sat16)(void *d, void *a, 
uint32_t desc)
         *(int16_t *)((char *)d + i) = (int16_t)r;
     }
 }
+
+void HELPER(hlx_gvec_avg_sh16)(void *d, void *a, void *b, uint32_t desc)
+{
+    intptr_t oprsz = simd_oprsz(desc);
+    intptr_t i;
+
+    for (i = 0; i < oprsz; i += sizeof(int16_t)) {
+        int16_t av = *(int16_t *)((char *)a + i);
+        int16_t bv = *(int16_t *)((char *)b + i);
+        int16_t r = (int16_t)((av & bv) + ((av ^ bv) >> 1));
+        *(int16_t *)((char *)d + i) = r;
+    }
+}
+
+void HELPER(hlx_gvec_avg_sh16_rnd)(void *d, void *a, void *b, uint32_t desc)
+{
+    intptr_t oprsz = simd_oprsz(desc);
+    intptr_t i;
+
+    for (i = 0; i < oprsz; i += sizeof(int16_t)) {
+        int16_t av = *(int16_t *)((char *)a + i);
+        int16_t bv = *(int16_t *)((char *)b + i);
+        int16_t r = (int16_t)((av | bv) - ((av ^ bv) >> 1));
+        *(int16_t *)((char *)d + i) = r;
+    }
+}
+
+void HELPER(hlx_gvec_avg_uh16)(void *d, void *a, void *b, uint32_t desc)
+{
+    intptr_t oprsz = simd_oprsz(desc);
+    intptr_t i;
+
+    for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+        uint16_t av = *(uint16_t *)((char *)a + i);
+        uint16_t bv = *(uint16_t *)((char *)b + i);
+        uint16_t r = (uint16_t)((av & bv) + ((av ^ bv) >> 1));
+        *(uint16_t *)((char *)d + i) = r;
+    }
+}
+
+void HELPER(hlx_gvec_avg_uh16_rnd)(void *d, void *a, void *b, uint32_t desc)
+{
+    intptr_t oprsz = simd_oprsz(desc);
+    intptr_t i;
+
+    for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+        uint16_t av = *(uint16_t *)((char *)a + i);
+        uint16_t bv = *(uint16_t *)((char *)b + i);
+        uint16_t r = (uint16_t)((av | bv) - ((av ^ bv) >> 1));
+        *(uint16_t *)((char *)d + i) = r;
+    }
+}
-- 
2.43.0


Reply via email to