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
