Add out-of-line gvec helpers for signed-to-unsigned halfword saturation
and saturating absolute value.

HLX vectors exceed the gvec unroll limit, so these helpers run.

Signed-off-by: Marco Liebel <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 target/hexagon/genptr.c          |   2 +-
 target/hexagon/helper.h          |   7 ++
 target/hexagon/hex_common.py     |  10 +++
 target/hexagon/hlx_gvec_tables.c | 113 +++++++++++++++++++++++++++++++
 target/hexagon/hlx_gvec_tables.h |  15 ++++
 target/hexagon/hlx_helper.c      |  50 ++++++++++++++
 target/hexagon/meson.build       |   1 +
 7 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 target/hexagon/hlx_gvec_tables.c
 create mode 100644 target/hexagon/hlx_gvec_tables.h

diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 808caf4289..b57f255b24 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -36,7 +36,7 @@
 #ifndef CONFIG_USER_ONLY
 #include "gen_tcg_sys.h"
 #endif
-
+#include "hlx_gvec_tables.h"
 #include "genptr.h"
 
 static void gen_sabsdiff_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 766995fae3..471ef0903b 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -37,6 +37,13 @@ DEF_HELPER_5(hlx_store_vec, void, env, tl, ptr, i32, i32)
 DEF_HELPER_1(hlx_commit_store, void, env)
 DEF_HELPER_FLAGS_2(hlx_trace_op, TCG_CALL_NO_RWG, void, env, i32)
 
+/* GVec helpers for signed-to-unsigned MO_16 saturation. */
+DEF_HELPER_FLAGS_4(hlx_gvec_ushsat_add16, TCG_CALL_NO_RWG,
+                   void, ptr, ptr, ptr, i32)
+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)
+
 /* 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 a6ac84d792..3f4d796a98 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -378,6 +378,16 @@ def skip_qemu_helper(tag):
                       "vece": "MO_16"},
     "LX_abs_uhp":    {"op": "gvec2_fn", "fn": "abs",
                       "vece": "MO_16", "size": "2 * sizeof(HLXVector)"},
+    "LX_add_uhh_sat":   {"op": "gvec3", "table": "hlx_ushsat_add_op",
+                         "vece": "MO_16"},
+    "LX_sub_uhh_sat":   {"op": "gvec3", "table": "hlx_ushsat_sub_op",
+                         "vece": "MO_16"},
+    "LX_add_uhp_h_sat": {"op": "gvec3", "table": "hlx_ushsat_add_op",
+                         "vece": "MO_16", "size": "2 * sizeof(HLXVector)"},
+    "LX_sub_uhp_h_sat": {"op": "gvec3", "table": "hlx_ushsat_sub_op",
+                         "vece": "MO_16", "size": "2 * sizeof(HLXVector)"},
+    "LX_abs_uh_sat":    {"op": "gvec2", "table": "hlx_abs_uh_sat_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
new file mode 100644
index 0000000000..dd5aa788e0
--- /dev/null
+++ b/target/hexagon/hlx_gvec_tables.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "tcg/tcg.h"
+#include "tcg/tcg-op-common.h"
+#include "tcg/tcg-op-gvec-common.h"
+#include "hlx_gvec_tables.h"
+#include "exec/helper-gen.h"
+
+/* Saturate signed halfword results to uint16_t. */
+
+static const TCGOpcode hlx_vecop_ushsat_add[] = {
+    INDEX_op_add_vec,
+    INDEX_op_ssadd_vec,
+    INDEX_op_smax_vec,
+    INDEX_op_cmp_vec,
+    0
+};
+
+static const TCGOpcode hlx_vecop_ushsat_sub[] = {
+    INDEX_op_sub_vec,
+    INDEX_op_sssub_vec,
+    INDEX_op_smax_vec,
+    INDEX_op_cmp_vec,
+    0
+};
+
+static const TCGOpcode hlx_vecop_abs_uh_sat[] = {
+    INDEX_op_abs_vec,
+    INDEX_op_umin_vec,
+    0
+};
+
+static void hlx_fniv_ushsat_add(unsigned vece, TCGv_vec r,
+                                 TCGv_vec a, TCGv_vec b)
+{
+    TCGv_vec wrap    = tcg_temp_new_vec_matching(r);
+    TCGv_vec ssat    = tcg_temp_new_vec_matching(r);
+    TCGv_vec pos_ovf = tcg_temp_new_vec_matching(r);
+    TCGv_vec pa      = tcg_temp_new_vec_matching(r);
+    TCGv_vec pb      = tcg_temp_new_vec_matching(r);
+    TCGv_vec zero    = tcg_constant_vec_matching(r, vece, 0);
+
+    tcg_gen_add_vec(vece, wrap, a, b);
+
+    tcg_gen_ssadd_vec(vece, ssat, a, b);
+    tcg_gen_smax_vec(vece, ssat, ssat, zero);
+
+    tcg_gen_cmp_vec(TCG_COND_GE, vece, pa, a, zero);
+    tcg_gen_cmp_vec(TCG_COND_GE, vece, pb, b, zero);
+    tcg_gen_cmp_vec(TCG_COND_LT, vece, pos_ovf, wrap, zero);
+    tcg_gen_and_vec(vece, pos_ovf, pos_ovf, pa);
+    tcg_gen_and_vec(vece, pos_ovf, pos_ovf, pb);
+
+    tcg_gen_bitsel_vec(vece, r, pos_ovf, wrap, ssat);
+}
+
+static void hlx_fniv_ushsat_sub(unsigned vece, TCGv_vec r,
+                                 TCGv_vec a, TCGv_vec b)
+{
+    TCGv_vec wrap    = tcg_temp_new_vec_matching(r);
+    TCGv_vec ssat    = tcg_temp_new_vec_matching(r);
+    TCGv_vec pos_ovf = tcg_temp_new_vec_matching(r);
+    TCGv_vec pa      = tcg_temp_new_vec_matching(r);
+    TCGv_vec nb      = tcg_temp_new_vec_matching(r);
+    TCGv_vec zero    = tcg_constant_vec_matching(r, vece, 0);
+
+    tcg_gen_sub_vec(vece, wrap, a, b);
+
+    tcg_gen_sssub_vec(vece, ssat, a, b);
+    tcg_gen_smax_vec(vece, ssat, ssat, zero);
+
+    /* Positive subtraction overflow needs a >= 0 and b < 0. */
+    tcg_gen_cmp_vec(TCG_COND_GE, vece, pa, a, zero);
+    tcg_gen_cmp_vec(TCG_COND_LT, vece, nb, b, zero);
+    tcg_gen_cmp_vec(TCG_COND_LT, vece, pos_ovf, wrap, zero);
+    tcg_gen_and_vec(vece, pos_ovf, pos_ovf, pa);
+    tcg_gen_and_vec(vece, pos_ovf, pos_ovf, nb);
+
+    tcg_gen_bitsel_vec(vece, r, pos_ovf, wrap, ssat);
+}
+
+static void hlx_fniv_abs_uh_sat(unsigned vece, TCGv_vec r, TCGv_vec a)
+{
+    /* Clamp abs(INT16_MIN) to INT16_MAX. */
+    TCGv_vec imax = tcg_constant_vec_matching(r, vece, 0x7FFF);
+    tcg_gen_abs_vec(vece, r, a);
+    tcg_gen_umin_vec(vece, r, r, imax);
+}
+
+const GVecGen3 hlx_ushsat_add_op = {
+    .fniv    = hlx_fniv_ushsat_add,
+    .opt_opc = hlx_vecop_ushsat_add,
+    .fno     = gen_helper_hlx_gvec_ushsat_add16,
+    .vece    = MO_16,
+};
+
+const GVecGen3 hlx_ushsat_sub_op = {
+    .fniv    = hlx_fniv_ushsat_sub,
+    .opt_opc = hlx_vecop_ushsat_sub,
+    .fno     = gen_helper_hlx_gvec_ushsat_sub16,
+    .vece    = MO_16,
+};
+
+const GVecGen2 hlx_abs_uh_sat_op = {
+    .fniv    = hlx_fniv_abs_uh_sat,
+    .opt_opc = hlx_vecop_abs_uh_sat,
+    .fno     = gen_helper_hlx_gvec_abs_uh_sat16,
+    .vece    = MO_16,
+};
diff --git a/target/hexagon/hlx_gvec_tables.h b/target/hexagon/hlx_gvec_tables.h
new file mode 100644
index 0000000000..55ab6bb63f
--- /dev/null
+++ b/target/hexagon/hlx_gvec_tables.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HLX_GVEC_TABLES_H
+#define HLX_GVEC_TABLES_H
+
+#include "tcg/tcg-op-gvec-common.h"
+
+extern const GVecGen3 hlx_ushsat_add_op;
+extern const GVecGen3 hlx_ushsat_sub_op;
+extern const GVecGen2 hlx_abs_uh_sat_op;
+
+#endif /* HLX_GVEC_TABLES_H */
diff --git a/target/hexagon/hlx_helper.c b/target/hexagon/hlx_helper.c
index 6525abfb2c..906f31ba17 100644
--- a/target/hexagon/hlx_helper.c
+++ b/target/hexagon/hlx_helper.c
@@ -93,3 +93,53 @@ void HELPER(hlx_commit_reg)(CPUHexagonState *env, uint32_t 
rnum)
     memcpy(&env->hlx_ctx->LRegs[rnum], &env->future_LRegs[rnum],
            sizeof(HLXVector));
 }
+
+/* HLX vectors exceed the gvec inline limit. */
+void HELPER(hlx_gvec_ushsat_add16)(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)) {
+        int32_t r = (int32_t)(*(int16_t *)((char *)a + i))
+                  + (int32_t)(*(int16_t *)((char *)b + i));
+        if (r < 0) {
+            r = 0;
+        } else if (r > 0xFFFF) {
+            r = 0xFFFF;
+        }
+        *(uint16_t *)((char *)d + i) = (uint16_t)r;
+    }
+}
+
+void HELPER(hlx_gvec_ushsat_sub16)(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)) {
+        int32_t r = (int32_t)(*(int16_t *)((char *)a + i))
+                  - (int32_t)(*(int16_t *)((char *)b + i));
+        if (r < 0) {
+            r = 0;
+        } else if (r > 0xFFFF) {
+            r = 0xFFFF;
+        }
+        *(uint16_t *)((char *)d + i) = (uint16_t)r;
+    }
+}
+
+void HELPER(hlx_gvec_abs_uh_sat16)(void *d, void *a, uint32_t desc)
+{
+    intptr_t oprsz = simd_oprsz(desc);
+    intptr_t i;
+
+    for (i = 0; i < oprsz; i += sizeof(int16_t)) {
+        int16_t v = *(int16_t *)((char *)a + i);
+        int32_t r = (v < 0) ? -(int32_t)v : (int32_t)v;
+        if (r > INT16_MAX) {
+            r = INT16_MAX;
+        }
+        *(int16_t *)((char *)d + i) = (int16_t)r;
+    }
+}
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 1aa4df7ac7..fd4983343d 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -266,6 +266,7 @@ hexagon_ss.add(files(
     'mmvec/hvx_ieee_fp.c',
     'mmvec/hvx_qfloat.c',
     'hlx_helper.c',
+    'hlx_gvec_tables.c',
 ))
 
 hexagon_softmmu_ss.add(files(
-- 
2.43.0


Reply via email to