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;
+ }
+}