target/arm: Implement SVE2 saturating add/subtract (predicated)
Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20210525010358.152808-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
8597dc8b86
commit
4f07fbebb1
@ -371,6 +371,60 @@ DEF_HELPER_FLAGS_5(sve2_uminp_zpzz_s, TCG_CALL_NO_RWG,
|
||||
DEF_HELPER_FLAGS_5(sve2_uminp_zpzz_d, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(sve2_sqadd_zpzz_b, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_sqadd_zpzz_h, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_sqadd_zpzz_s, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_sqadd_zpzz_d, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(sve2_uqadd_zpzz_b, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_uqadd_zpzz_h, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_uqadd_zpzz_s, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_uqadd_zpzz_d, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(sve2_sqsub_zpzz_b, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_sqsub_zpzz_h, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_sqsub_zpzz_s, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_sqsub_zpzz_d, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(sve2_uqsub_zpzz_b, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_uqsub_zpzz_h, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_uqsub_zpzz_s, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_uqsub_zpzz_d, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(sve2_suqadd_zpzz_b, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_suqadd_zpzz_h, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_suqadd_zpzz_s, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_suqadd_zpzz_d, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(sve2_usqadd_zpzz_b, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_usqadd_zpzz_h, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_usqadd_zpzz_s, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve2_usqadd_zpzz_d, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(sve_asr_zpzw_b, TCG_CALL_NO_RWG,
|
||||
void, ptr, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_5(sve_asr_zpzw_h, TCG_CALL_NO_RWG,
|
||||
|
@ -1148,3 +1148,14 @@ SMAXP 01000100 .. 010 100 101 ... ..... ..... @rdn_pg_rm
|
||||
UMAXP 01000100 .. 010 101 101 ... ..... ..... @rdn_pg_rm
|
||||
SMINP 01000100 .. 010 110 101 ... ..... ..... @rdn_pg_rm
|
||||
UMINP 01000100 .. 010 111 101 ... ..... ..... @rdn_pg_rm
|
||||
|
||||
### SVE2 saturating add/subtract (predicated)
|
||||
|
||||
SQADD_zpzz 01000100 .. 011 000 100 ... ..... ..... @rdn_pg_rm
|
||||
UQADD_zpzz 01000100 .. 011 001 100 ... ..... ..... @rdn_pg_rm
|
||||
SQSUB_zpzz 01000100 .. 011 010 100 ... ..... ..... @rdn_pg_rm
|
||||
UQSUB_zpzz 01000100 .. 011 011 100 ... ..... ..... @rdn_pg_rm
|
||||
SUQADD 01000100 .. 011 100 100 ... ..... ..... @rdn_pg_rm
|
||||
USQADD 01000100 .. 011 101 100 ... ..... ..... @rdn_pg_rm
|
||||
SQSUB_zpzz 01000100 .. 011 110 100 ... ..... ..... @rdm_pg_rn # SQSUBR
|
||||
UQSUB_zpzz 01000100 .. 011 111 100 ... ..... ..... @rdm_pg_rn # UQSUBR
|
||||
|
@ -687,6 +687,135 @@ DO_ZPZZ(sve2_uhsub_zpzz_h, uint16_t, H1_2, DO_HSUB_BHS)
|
||||
DO_ZPZZ(sve2_uhsub_zpzz_s, uint32_t, H1_4, DO_HSUB_BHS)
|
||||
DO_ZPZZ_D(sve2_uhsub_zpzz_d, uint64_t, DO_HSUB_D)
|
||||
|
||||
static inline int32_t do_sat_bhs(int64_t val, int64_t min, int64_t max)
|
||||
{
|
||||
return val >= max ? max : val <= min ? min : val;
|
||||
}
|
||||
|
||||
#define DO_SQADD_B(n, m) do_sat_bhs((int64_t)n + m, INT8_MIN, INT8_MAX)
|
||||
#define DO_SQADD_H(n, m) do_sat_bhs((int64_t)n + m, INT16_MIN, INT16_MAX)
|
||||
#define DO_SQADD_S(n, m) do_sat_bhs((int64_t)n + m, INT32_MIN, INT32_MAX)
|
||||
|
||||
static inline int64_t do_sqadd_d(int64_t n, int64_t m)
|
||||
{
|
||||
int64_t r = n + m;
|
||||
if (((r ^ n) & ~(n ^ m)) < 0) {
|
||||
/* Signed overflow. */
|
||||
return r < 0 ? INT64_MAX : INT64_MIN;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
DO_ZPZZ(sve2_sqadd_zpzz_b, int8_t, H1, DO_SQADD_B)
|
||||
DO_ZPZZ(sve2_sqadd_zpzz_h, int16_t, H1_2, DO_SQADD_H)
|
||||
DO_ZPZZ(sve2_sqadd_zpzz_s, int32_t, H1_4, DO_SQADD_S)
|
||||
DO_ZPZZ_D(sve2_sqadd_zpzz_d, int64_t, do_sqadd_d)
|
||||
|
||||
#define DO_UQADD_B(n, m) do_sat_bhs((int64_t)n + m, 0, UINT8_MAX)
|
||||
#define DO_UQADD_H(n, m) do_sat_bhs((int64_t)n + m, 0, UINT16_MAX)
|
||||
#define DO_UQADD_S(n, m) do_sat_bhs((int64_t)n + m, 0, UINT32_MAX)
|
||||
|
||||
static inline uint64_t do_uqadd_d(uint64_t n, uint64_t m)
|
||||
{
|
||||
uint64_t r = n + m;
|
||||
return r < n ? UINT64_MAX : r;
|
||||
}
|
||||
|
||||
DO_ZPZZ(sve2_uqadd_zpzz_b, uint8_t, H1, DO_UQADD_B)
|
||||
DO_ZPZZ(sve2_uqadd_zpzz_h, uint16_t, H1_2, DO_UQADD_H)
|
||||
DO_ZPZZ(sve2_uqadd_zpzz_s, uint32_t, H1_4, DO_UQADD_S)
|
||||
DO_ZPZZ_D(sve2_uqadd_zpzz_d, uint64_t, do_uqadd_d)
|
||||
|
||||
#define DO_SQSUB_B(n, m) do_sat_bhs((int64_t)n - m, INT8_MIN, INT8_MAX)
|
||||
#define DO_SQSUB_H(n, m) do_sat_bhs((int64_t)n - m, INT16_MIN, INT16_MAX)
|
||||
#define DO_SQSUB_S(n, m) do_sat_bhs((int64_t)n - m, INT32_MIN, INT32_MAX)
|
||||
|
||||
static inline int64_t do_sqsub_d(int64_t n, int64_t m)
|
||||
{
|
||||
int64_t r = n - m;
|
||||
if (((r ^ n) & (n ^ m)) < 0) {
|
||||
/* Signed overflow. */
|
||||
return r < 0 ? INT64_MAX : INT64_MIN;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
DO_ZPZZ(sve2_sqsub_zpzz_b, int8_t, H1, DO_SQSUB_B)
|
||||
DO_ZPZZ(sve2_sqsub_zpzz_h, int16_t, H1_2, DO_SQSUB_H)
|
||||
DO_ZPZZ(sve2_sqsub_zpzz_s, int32_t, H1_4, DO_SQSUB_S)
|
||||
DO_ZPZZ_D(sve2_sqsub_zpzz_d, int64_t, do_sqsub_d)
|
||||
|
||||
#define DO_UQSUB_B(n, m) do_sat_bhs((int64_t)n - m, 0, UINT8_MAX)
|
||||
#define DO_UQSUB_H(n, m) do_sat_bhs((int64_t)n - m, 0, UINT16_MAX)
|
||||
#define DO_UQSUB_S(n, m) do_sat_bhs((int64_t)n - m, 0, UINT32_MAX)
|
||||
|
||||
static inline uint64_t do_uqsub_d(uint64_t n, uint64_t m)
|
||||
{
|
||||
return n > m ? n - m : 0;
|
||||
}
|
||||
|
||||
DO_ZPZZ(sve2_uqsub_zpzz_b, uint8_t, H1, DO_UQSUB_B)
|
||||
DO_ZPZZ(sve2_uqsub_zpzz_h, uint16_t, H1_2, DO_UQSUB_H)
|
||||
DO_ZPZZ(sve2_uqsub_zpzz_s, uint32_t, H1_4, DO_UQSUB_S)
|
||||
DO_ZPZZ_D(sve2_uqsub_zpzz_d, uint64_t, do_uqsub_d)
|
||||
|
||||
#define DO_SUQADD_B(n, m) \
|
||||
do_sat_bhs((int64_t)(int8_t)n + m, INT8_MIN, INT8_MAX)
|
||||
#define DO_SUQADD_H(n, m) \
|
||||
do_sat_bhs((int64_t)(int16_t)n + m, INT16_MIN, INT16_MAX)
|
||||
#define DO_SUQADD_S(n, m) \
|
||||
do_sat_bhs((int64_t)(int32_t)n + m, INT32_MIN, INT32_MAX)
|
||||
|
||||
static inline int64_t do_suqadd_d(int64_t n, uint64_t m)
|
||||
{
|
||||
uint64_t r = n + m;
|
||||
|
||||
if (n < 0) {
|
||||
/* Note that m - abs(n) cannot underflow. */
|
||||
if (r > INT64_MAX) {
|
||||
/* Result is either very large positive or negative. */
|
||||
if (m > -n) {
|
||||
/* m > abs(n), so r is a very large positive. */
|
||||
return INT64_MAX;
|
||||
}
|
||||
/* Result is negative. */
|
||||
}
|
||||
} else {
|
||||
/* Both inputs are positive: check for overflow. */
|
||||
if (r < m || r > INT64_MAX) {
|
||||
return INT64_MAX;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
DO_ZPZZ(sve2_suqadd_zpzz_b, uint8_t, H1, DO_SUQADD_B)
|
||||
DO_ZPZZ(sve2_suqadd_zpzz_h, uint16_t, H1_2, DO_SUQADD_H)
|
||||
DO_ZPZZ(sve2_suqadd_zpzz_s, uint32_t, H1_4, DO_SUQADD_S)
|
||||
DO_ZPZZ_D(sve2_suqadd_zpzz_d, uint64_t, do_suqadd_d)
|
||||
|
||||
#define DO_USQADD_B(n, m) \
|
||||
do_sat_bhs((int64_t)n + (int8_t)m, 0, UINT8_MAX)
|
||||
#define DO_USQADD_H(n, m) \
|
||||
do_sat_bhs((int64_t)n + (int16_t)m, 0, UINT16_MAX)
|
||||
#define DO_USQADD_S(n, m) \
|
||||
do_sat_bhs((int64_t)n + (int32_t)m, 0, UINT32_MAX)
|
||||
|
||||
static inline uint64_t do_usqadd_d(uint64_t n, int64_t m)
|
||||
{
|
||||
uint64_t r = n + m;
|
||||
|
||||
if (m < 0) {
|
||||
return n < -m ? 0 : r;
|
||||
}
|
||||
return r < n ? UINT64_MAX : r;
|
||||
}
|
||||
|
||||
DO_ZPZZ(sve2_usqadd_zpzz_b, uint8_t, H1, DO_USQADD_B)
|
||||
DO_ZPZZ(sve2_usqadd_zpzz_h, uint16_t, H1_2, DO_USQADD_H)
|
||||
DO_ZPZZ(sve2_usqadd_zpzz_s, uint32_t, H1_4, DO_USQADD_S)
|
||||
DO_ZPZZ_D(sve2_usqadd_zpzz_d, uint64_t, do_usqadd_d)
|
||||
|
||||
#undef DO_ZPZZ
|
||||
#undef DO_ZPZZ_D
|
||||
|
||||
@ -1623,13 +1752,7 @@ void HELPER(sve_sqaddi_b)(void *d, void *a, int32_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(int8_t)) {
|
||||
int r = *(int8_t *)(a + i) + b;
|
||||
if (r > INT8_MAX) {
|
||||
r = INT8_MAX;
|
||||
} else if (r < INT8_MIN) {
|
||||
r = INT8_MIN;
|
||||
}
|
||||
*(int8_t *)(d + i) = r;
|
||||
*(int8_t *)(d + i) = DO_SQADD_B(b, *(int8_t *)(a + i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1638,13 +1761,7 @@ void HELPER(sve_sqaddi_h)(void *d, void *a, int32_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(int16_t)) {
|
||||
int r = *(int16_t *)(a + i) + b;
|
||||
if (r > INT16_MAX) {
|
||||
r = INT16_MAX;
|
||||
} else if (r < INT16_MIN) {
|
||||
r = INT16_MIN;
|
||||
}
|
||||
*(int16_t *)(d + i) = r;
|
||||
*(int16_t *)(d + i) = DO_SQADD_H(b, *(int16_t *)(a + i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1653,13 +1770,7 @@ void HELPER(sve_sqaddi_s)(void *d, void *a, int64_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(int32_t)) {
|
||||
int64_t r = *(int32_t *)(a + i) + b;
|
||||
if (r > INT32_MAX) {
|
||||
r = INT32_MAX;
|
||||
} else if (r < INT32_MIN) {
|
||||
r = INT32_MIN;
|
||||
}
|
||||
*(int32_t *)(d + i) = r;
|
||||
*(int32_t *)(d + i) = DO_SQADD_S(b, *(int32_t *)(a + i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1668,13 +1779,7 @@ void HELPER(sve_sqaddi_d)(void *d, void *a, int64_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(int64_t)) {
|
||||
int64_t ai = *(int64_t *)(a + i);
|
||||
int64_t r = ai + b;
|
||||
if (((r ^ ai) & ~(ai ^ b)) < 0) {
|
||||
/* Signed overflow. */
|
||||
r = (r < 0 ? INT64_MAX : INT64_MIN);
|
||||
}
|
||||
*(int64_t *)(d + i) = r;
|
||||
*(int64_t *)(d + i) = do_sqadd_d(b, *(int64_t *)(a + i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1687,13 +1792,7 @@ void HELPER(sve_uqaddi_b)(void *d, void *a, int32_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
int r = *(uint8_t *)(a + i) + b;
|
||||
if (r > UINT8_MAX) {
|
||||
r = UINT8_MAX;
|
||||
} else if (r < 0) {
|
||||
r = 0;
|
||||
}
|
||||
*(uint8_t *)(d + i) = r;
|
||||
*(uint8_t *)(d + i) = DO_UQADD_B(b, *(uint8_t *)(a + i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1702,13 +1801,7 @@ void HELPER(sve_uqaddi_h)(void *d, void *a, int32_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
int r = *(uint16_t *)(a + i) + b;
|
||||
if (r > UINT16_MAX) {
|
||||
r = UINT16_MAX;
|
||||
} else if (r < 0) {
|
||||
r = 0;
|
||||
}
|
||||
*(uint16_t *)(d + i) = r;
|
||||
*(uint16_t *)(d + i) = DO_UQADD_H(b, *(uint16_t *)(a + i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1717,13 +1810,7 @@ void HELPER(sve_uqaddi_s)(void *d, void *a, int64_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
int64_t r = *(uint32_t *)(a + i) + b;
|
||||
if (r > UINT32_MAX) {
|
||||
r = UINT32_MAX;
|
||||
} else if (r < 0) {
|
||||
r = 0;
|
||||
}
|
||||
*(uint32_t *)(d + i) = r;
|
||||
*(uint32_t *)(d + i) = DO_UQADD_S(b, *(uint32_t *)(a + i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1732,11 +1819,7 @@ void HELPER(sve_uqaddi_d)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
uint64_t r = *(uint64_t *)(a + i) + b;
|
||||
if (r < b) {
|
||||
r = UINT64_MAX;
|
||||
}
|
||||
*(uint64_t *)(d + i) = r;
|
||||
*(uint64_t *)(d + i) = do_uqadd_d(b, *(uint64_t *)(a + i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1745,8 +1828,7 @@ void HELPER(sve_uqsubi_d)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
intptr_t i, oprsz = simd_oprsz(desc);
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
uint64_t ai = *(uint64_t *)(a + i);
|
||||
*(uint64_t *)(d + i) = (ai < b ? 0 : ai - b);
|
||||
*(uint64_t *)(d + i) = do_uqsub_d(*(uint64_t *)(a + i), b);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5963,3 +5963,10 @@ DO_SVE2_ZPZZ(SMAXP, smaxp)
|
||||
DO_SVE2_ZPZZ(UMAXP, umaxp)
|
||||
DO_SVE2_ZPZZ(SMINP, sminp)
|
||||
DO_SVE2_ZPZZ(UMINP, uminp)
|
||||
|
||||
DO_SVE2_ZPZZ(SQADD_zpzz, sqadd)
|
||||
DO_SVE2_ZPZZ(UQADD_zpzz, uqadd)
|
||||
DO_SVE2_ZPZZ(SQSUB_zpzz, sqsub)
|
||||
DO_SVE2_ZPZZ(UQSUB_zpzz, uqsub)
|
||||
DO_SVE2_ZPZZ(SUQADD, suqadd)
|
||||
DO_SVE2_ZPZZ(USQADD, usqadd)
|
||||
|
Loading…
Reference in New Issue
Block a user