xref: /qemu/target/arm/tcg/vec_internal.h (revision 368b42f6dd64521b9282ddefa9e267eca621271c)
1a04b68e1SRichard Henderson /*
2a04b68e1SRichard Henderson  * ARM AdvSIMD / SVE Vector Helpers
3a04b68e1SRichard Henderson  *
4a04b68e1SRichard Henderson  * Copyright (c) 2020 Linaro
5a04b68e1SRichard Henderson  *
6a04b68e1SRichard Henderson  * This library is free software; you can redistribute it and/or
7a04b68e1SRichard Henderson  * modify it under the terms of the GNU Lesser General Public
8a04b68e1SRichard Henderson  * License as published by the Free Software Foundation; either
950f57e09SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10a04b68e1SRichard Henderson  *
11a04b68e1SRichard Henderson  * This library is distributed in the hope that it will be useful,
12a04b68e1SRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13a04b68e1SRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14a04b68e1SRichard Henderson  * Lesser General Public License for more details.
15a04b68e1SRichard Henderson  *
16a04b68e1SRichard Henderson  * You should have received a copy of the GNU Lesser General Public
17a04b68e1SRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18a04b68e1SRichard Henderson  */
19a04b68e1SRichard Henderson 
2052581c71SMarkus Armbruster #ifndef TARGET_ARM_VEC_INTERNAL_H
2152581c71SMarkus Armbruster #define TARGET_ARM_VEC_INTERNAL_H
22a04b68e1SRichard Henderson 
23416650acSPeter Maydell #include "fpu/softfloat.h"
24416650acSPeter Maydell 
25*368b42f6SPierrick Bouvier typedef struct CPUArchState CPUARMState;
26*368b42f6SPierrick Bouvier 
2793966af1SRichard Henderson /*
2893966af1SRichard Henderson  * Note that vector data is stored in host-endian 64-bit chunks,
2993966af1SRichard Henderson  * so addressing units smaller than that needs a host-endian fixup.
3093966af1SRichard Henderson  *
3193966af1SRichard Henderson  * The H<N> macros are used when indexing an array of elements of size N.
3293966af1SRichard Henderson  *
3393966af1SRichard Henderson  * The H1_<N> macros are used when performing byte arithmetic and then
3493966af1SRichard Henderson  * casting the final pointer to a type of size N.
3593966af1SRichard Henderson  */
36e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
3793966af1SRichard Henderson #define H1(x)   ((x) ^ 7)
3893966af1SRichard Henderson #define H1_2(x) ((x) ^ 6)
3993966af1SRichard Henderson #define H1_4(x) ((x) ^ 4)
4093966af1SRichard Henderson #define H2(x)   ((x) ^ 3)
4193966af1SRichard Henderson #define H4(x)   ((x) ^ 1)
4293966af1SRichard Henderson #else
4393966af1SRichard Henderson #define H1(x)   (x)
4493966af1SRichard Henderson #define H1_2(x) (x)
4593966af1SRichard Henderson #define H1_4(x) (x)
4693966af1SRichard Henderson #define H2(x)   (x)
4793966af1SRichard Henderson #define H4(x)   (x)
4893966af1SRichard Henderson #endif
496e802db3SPeter Maydell /*
506e802db3SPeter Maydell  * Access to 64-bit elements isn't host-endian dependent; we provide H8
516e802db3SPeter Maydell  * and H1_8 so that when a function is being generated from a macro we
526e802db3SPeter Maydell  * can pass these rather than an empty macro argument, for clarity.
536e802db3SPeter Maydell  */
546e802db3SPeter Maydell #define H8(x)   (x)
556e802db3SPeter Maydell #define H1_8(x) (x)
5693966af1SRichard Henderson 
57820e0bb9SRichard Henderson /*
58820e0bb9SRichard Henderson  * Expand active predicate bits to bytes, for byte elements.
59820e0bb9SRichard Henderson  */
6077f96148SPeter Maydell extern const uint64_t expand_pred_b_data[256];
expand_pred_b(uint8_t byte)61820e0bb9SRichard Henderson static inline uint64_t expand_pred_b(uint8_t byte)
62820e0bb9SRichard Henderson {
63820e0bb9SRichard Henderson     return expand_pred_b_data[byte];
64820e0bb9SRichard Henderson }
6577f96148SPeter Maydell 
66a613cf2dSRichard Henderson /* Similarly for half-word elements. */
67a613cf2dSRichard Henderson extern const uint64_t expand_pred_h_data[0x55 + 1];
expand_pred_h(uint8_t byte)68a613cf2dSRichard Henderson static inline uint64_t expand_pred_h(uint8_t byte)
69a613cf2dSRichard Henderson {
70a613cf2dSRichard Henderson     return expand_pred_h_data[byte & 0x55];
71a613cf2dSRichard Henderson }
72a613cf2dSRichard Henderson 
clear_tail(void * vd,uintptr_t opr_sz,uintptr_t max_sz)73a04b68e1SRichard Henderson static inline void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz)
74a04b68e1SRichard Henderson {
75a04b68e1SRichard Henderson     uint64_t *d = vd + opr_sz;
76a04b68e1SRichard Henderson     uintptr_t i;
77a04b68e1SRichard Henderson 
78a04b68e1SRichard Henderson     for (i = opr_sz; i < max_sz; i += 8) {
79a04b68e1SRichard Henderson         *d++ = 0;
80a04b68e1SRichard Henderson     }
81a04b68e1SRichard Henderson }
82a04b68e1SRichard Henderson 
do_sqrshl_bhs(int32_t src,int32_t shift,int bits,bool round,uint32_t * sat)838b3f15b0SRichard Henderson static inline int32_t do_sqrshl_bhs(int32_t src, int32_t shift, int bits,
848b3f15b0SRichard Henderson                                     bool round, uint32_t *sat)
858b3f15b0SRichard Henderson {
868b3f15b0SRichard Henderson     if (shift <= -bits) {
878b3f15b0SRichard Henderson         /* Rounding the sign bit always produces 0. */
888b3f15b0SRichard Henderson         if (round) {
898b3f15b0SRichard Henderson             return 0;
908b3f15b0SRichard Henderson         }
918b3f15b0SRichard Henderson         return src >> 31;
928b3f15b0SRichard Henderson     } else if (shift < 0) {
938b3f15b0SRichard Henderson         if (round) {
948b3f15b0SRichard Henderson             src >>= -shift - 1;
958b3f15b0SRichard Henderson             return (src >> 1) + (src & 1);
968b3f15b0SRichard Henderson         }
978b3f15b0SRichard Henderson         return src >> -shift;
988b3f15b0SRichard Henderson     } else if (shift < bits) {
998b3f15b0SRichard Henderson         int32_t val = src << shift;
1008b3f15b0SRichard Henderson         if (bits == 32) {
1018b3f15b0SRichard Henderson             if (!sat || val >> shift == src) {
1028b3f15b0SRichard Henderson                 return val;
1038b3f15b0SRichard Henderson             }
1048b3f15b0SRichard Henderson         } else {
1058b3f15b0SRichard Henderson             int32_t extval = sextract32(val, 0, bits);
1068b3f15b0SRichard Henderson             if (!sat || val == extval) {
1078b3f15b0SRichard Henderson                 return extval;
1088b3f15b0SRichard Henderson             }
1098b3f15b0SRichard Henderson         }
1108b3f15b0SRichard Henderson     } else if (!sat || src == 0) {
1118b3f15b0SRichard Henderson         return 0;
1128b3f15b0SRichard Henderson     }
1138b3f15b0SRichard Henderson 
1148b3f15b0SRichard Henderson     *sat = 1;
1158b3f15b0SRichard Henderson     return (1u << (bits - 1)) - (src >= 0);
1168b3f15b0SRichard Henderson }
1178b3f15b0SRichard Henderson 
do_uqrshl_bhs(uint32_t src,int32_t shift,int bits,bool round,uint32_t * sat)1188b3f15b0SRichard Henderson static inline uint32_t do_uqrshl_bhs(uint32_t src, int32_t shift, int bits,
1198b3f15b0SRichard Henderson                                      bool round, uint32_t *sat)
1208b3f15b0SRichard Henderson {
1218b3f15b0SRichard Henderson     if (shift <= -(bits + round)) {
1228b3f15b0SRichard Henderson         return 0;
1238b3f15b0SRichard Henderson     } else if (shift < 0) {
1248b3f15b0SRichard Henderson         if (round) {
1258b3f15b0SRichard Henderson             src >>= -shift - 1;
1268b3f15b0SRichard Henderson             return (src >> 1) + (src & 1);
1278b3f15b0SRichard Henderson         }
1288b3f15b0SRichard Henderson         return src >> -shift;
1298b3f15b0SRichard Henderson     } else if (shift < bits) {
1308b3f15b0SRichard Henderson         uint32_t val = src << shift;
1318b3f15b0SRichard Henderson         if (bits == 32) {
1328b3f15b0SRichard Henderson             if (!sat || val >> shift == src) {
1338b3f15b0SRichard Henderson                 return val;
1348b3f15b0SRichard Henderson             }
1358b3f15b0SRichard Henderson         } else {
1368b3f15b0SRichard Henderson             uint32_t extval = extract32(val, 0, bits);
1378b3f15b0SRichard Henderson             if (!sat || val == extval) {
1388b3f15b0SRichard Henderson                 return extval;
1398b3f15b0SRichard Henderson             }
1408b3f15b0SRichard Henderson         }
1418b3f15b0SRichard Henderson     } else if (!sat || src == 0) {
1428b3f15b0SRichard Henderson         return 0;
1438b3f15b0SRichard Henderson     }
1448b3f15b0SRichard Henderson 
1458b3f15b0SRichard Henderson     *sat = 1;
1468b3f15b0SRichard Henderson     return MAKE_64BIT_MASK(0, bits);
1478b3f15b0SRichard Henderson }
1488b3f15b0SRichard Henderson 
do_suqrshl_bhs(int32_t src,int32_t shift,int bits,bool round,uint32_t * sat)1498b3f15b0SRichard Henderson static inline int32_t do_suqrshl_bhs(int32_t src, int32_t shift, int bits,
1508b3f15b0SRichard Henderson                                      bool round, uint32_t *sat)
1518b3f15b0SRichard Henderson {
1528b3f15b0SRichard Henderson     if (sat && src < 0) {
1538b3f15b0SRichard Henderson         *sat = 1;
1548b3f15b0SRichard Henderson         return 0;
1558b3f15b0SRichard Henderson     }
1568b3f15b0SRichard Henderson     return do_uqrshl_bhs(src, shift, bits, round, sat);
1578b3f15b0SRichard Henderson }
1588b3f15b0SRichard Henderson 
do_sqrshl_d(int64_t src,int64_t shift,bool round,uint32_t * sat)1598b3f15b0SRichard Henderson static inline int64_t do_sqrshl_d(int64_t src, int64_t shift,
1608b3f15b0SRichard Henderson                                   bool round, uint32_t *sat)
1618b3f15b0SRichard Henderson {
1628b3f15b0SRichard Henderson     if (shift <= -64) {
1638b3f15b0SRichard Henderson         /* Rounding the sign bit always produces 0. */
1648b3f15b0SRichard Henderson         if (round) {
1658b3f15b0SRichard Henderson             return 0;
1668b3f15b0SRichard Henderson         }
1678b3f15b0SRichard Henderson         return src >> 63;
1688b3f15b0SRichard Henderson     } else if (shift < 0) {
1698b3f15b0SRichard Henderson         if (round) {
1708b3f15b0SRichard Henderson             src >>= -shift - 1;
1718b3f15b0SRichard Henderson             return (src >> 1) + (src & 1);
1728b3f15b0SRichard Henderson         }
1738b3f15b0SRichard Henderson         return src >> -shift;
1748b3f15b0SRichard Henderson     } else if (shift < 64) {
1758b3f15b0SRichard Henderson         int64_t val = src << shift;
1768b3f15b0SRichard Henderson         if (!sat || val >> shift == src) {
1778b3f15b0SRichard Henderson             return val;
1788b3f15b0SRichard Henderson         }
1798b3f15b0SRichard Henderson     } else if (!sat || src == 0) {
1808b3f15b0SRichard Henderson         return 0;
1818b3f15b0SRichard Henderson     }
1828b3f15b0SRichard Henderson 
1838b3f15b0SRichard Henderson     *sat = 1;
1848b3f15b0SRichard Henderson     return src < 0 ? INT64_MIN : INT64_MAX;
1858b3f15b0SRichard Henderson }
1868b3f15b0SRichard Henderson 
do_uqrshl_d(uint64_t src,int64_t shift,bool round,uint32_t * sat)1878b3f15b0SRichard Henderson static inline uint64_t do_uqrshl_d(uint64_t src, int64_t shift,
1888b3f15b0SRichard Henderson                                    bool round, uint32_t *sat)
1898b3f15b0SRichard Henderson {
1908b3f15b0SRichard Henderson     if (shift <= -(64 + round)) {
1918b3f15b0SRichard Henderson         return 0;
1928b3f15b0SRichard Henderson     } else if (shift < 0) {
1938b3f15b0SRichard Henderson         if (round) {
1948b3f15b0SRichard Henderson             src >>= -shift - 1;
1958b3f15b0SRichard Henderson             return (src >> 1) + (src & 1);
1968b3f15b0SRichard Henderson         }
1978b3f15b0SRichard Henderson         return src >> -shift;
1988b3f15b0SRichard Henderson     } else if (shift < 64) {
1998b3f15b0SRichard Henderson         uint64_t val = src << shift;
2008b3f15b0SRichard Henderson         if (!sat || val >> shift == src) {
2018b3f15b0SRichard Henderson             return val;
2028b3f15b0SRichard Henderson         }
2038b3f15b0SRichard Henderson     } else if (!sat || src == 0) {
2048b3f15b0SRichard Henderson         return 0;
2058b3f15b0SRichard Henderson     }
2068b3f15b0SRichard Henderson 
2078b3f15b0SRichard Henderson     *sat = 1;
2088b3f15b0SRichard Henderson     return UINT64_MAX;
2098b3f15b0SRichard Henderson }
2108b3f15b0SRichard Henderson 
do_suqrshl_d(int64_t src,int64_t shift,bool round,uint32_t * sat)2118b3f15b0SRichard Henderson static inline int64_t do_suqrshl_d(int64_t src, int64_t shift,
2128b3f15b0SRichard Henderson                                    bool round, uint32_t *sat)
2138b3f15b0SRichard Henderson {
2148b3f15b0SRichard Henderson     if (sat && src < 0) {
2158b3f15b0SRichard Henderson         *sat = 1;
2168b3f15b0SRichard Henderson         return 0;
2178b3f15b0SRichard Henderson     }
2188b3f15b0SRichard Henderson     return do_uqrshl_d(src, shift, round, sat);
2198b3f15b0SRichard Henderson }
2208b3f15b0SRichard Henderson 
221d782d3caSRichard Henderson int8_t do_sqrdmlah_b(int8_t, int8_t, int8_t, bool, bool);
222d782d3caSRichard Henderson int16_t do_sqrdmlah_h(int16_t, int16_t, int16_t, bool, bool, uint32_t *);
223d782d3caSRichard Henderson int32_t do_sqrdmlah_s(int32_t, int32_t, int32_t, bool, bool, uint32_t *);
224d782d3caSRichard Henderson int64_t do_sqrdmlah_d(int64_t, int64_t, int64_t, bool, bool);
225d782d3caSRichard Henderson 
22672db2aa3SRichard Henderson /**
22772db2aa3SRichard Henderson  * bfdotadd:
22872db2aa3SRichard Henderson  * @sum: addend
22972db2aa3SRichard Henderson  * @e1, @e2: multiplicand vectors
23009b0d9e0SPeter Maydell  * @fpst: floating-point status to use
23172db2aa3SRichard Henderson  *
23272db2aa3SRichard Henderson  * BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum.
23372db2aa3SRichard Henderson  * The @e1 and @e2 operands correspond to the 32-bit source vector
23472db2aa3SRichard Henderson  * slots and contain two Bfloat16 values each.
23572db2aa3SRichard Henderson  *
23609b0d9e0SPeter Maydell  * Corresponds to the ARM pseudocode function BFDotAdd, specialized
23709b0d9e0SPeter Maydell  * for the FPCR.EBF == 0 case.
23872db2aa3SRichard Henderson  */
23909b0d9e0SPeter Maydell float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst);
24009b0d9e0SPeter Maydell /**
24109b0d9e0SPeter Maydell  * bfdotadd_ebf:
24209b0d9e0SPeter Maydell  * @sum: addend
24309b0d9e0SPeter Maydell  * @e1, @e2: multiplicand vectors
24409b0d9e0SPeter Maydell  * @fpst: floating-point status to use
24509b0d9e0SPeter Maydell  * @fpst_odd: floating-point status to use for round-to-odd operations
24609b0d9e0SPeter Maydell  *
24709b0d9e0SPeter Maydell  * BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum.
24809b0d9e0SPeter Maydell  * The @e1 and @e2 operands correspond to the 32-bit source vector
24909b0d9e0SPeter Maydell  * slots and contain two Bfloat16 values each.
25009b0d9e0SPeter Maydell  *
25109b0d9e0SPeter Maydell  * Corresponds to the ARM pseudocode function BFDotAdd, specialized
25209b0d9e0SPeter Maydell  * for the FPCR.EBF == 1 case.
25309b0d9e0SPeter Maydell  */
25409b0d9e0SPeter Maydell float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2,
25509b0d9e0SPeter Maydell                      float_status *fpst, float_status *fpst_odd);
25609b0d9e0SPeter Maydell 
25709b0d9e0SPeter Maydell /**
25809b0d9e0SPeter Maydell  * is_ebf:
25909b0d9e0SPeter Maydell  * @env: CPU state
26009b0d9e0SPeter Maydell  * @statusp: pointer to floating point status to fill in
26109b0d9e0SPeter Maydell  * @oddstatusp: pointer to floating point status to fill in for round-to-odd
26209b0d9e0SPeter Maydell  *
26309b0d9e0SPeter Maydell  * Determine whether a BFDotAdd operation should use FPCR.EBF = 0
26409b0d9e0SPeter Maydell  * or FPCR.EBF = 1 semantics. On return, has initialized *statusp
26509b0d9e0SPeter Maydell  * and *oddstatusp to suitable float_status arguments to use with either
26609b0d9e0SPeter Maydell  * bfdotadd() or bfdotadd_ebf().
26709b0d9e0SPeter Maydell  * Returns true for EBF = 1, false for EBF = 0. (The caller should use this
26809b0d9e0SPeter Maydell  * to decide whether to call bfdotadd() or bfdotadd_ebf().)
26909b0d9e0SPeter Maydell  */
27009b0d9e0SPeter Maydell bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp);
27172db2aa3SRichard Henderson 
27228048a3dSPeter Maydell /*
27328048a3dSPeter Maydell  * Negate as for FPCR.AH=1 -- do not negate NaNs.
27428048a3dSPeter Maydell  */
float16_ah_chs(float16 a)27528048a3dSPeter Maydell static inline float16 float16_ah_chs(float16 a)
27628048a3dSPeter Maydell {
27728048a3dSPeter Maydell     return float16_is_any_nan(a) ? a : float16_chs(a);
27828048a3dSPeter Maydell }
27928048a3dSPeter Maydell 
float32_ah_chs(float32 a)28028048a3dSPeter Maydell static inline float32 float32_ah_chs(float32 a)
28128048a3dSPeter Maydell {
28228048a3dSPeter Maydell     return float32_is_any_nan(a) ? a : float32_chs(a);
28328048a3dSPeter Maydell }
28428048a3dSPeter Maydell 
float64_ah_chs(float64 a)28528048a3dSPeter Maydell static inline float64 float64_ah_chs(float64 a)
28628048a3dSPeter Maydell {
28728048a3dSPeter Maydell     return float64_is_any_nan(a) ? a : float64_chs(a);
28828048a3dSPeter Maydell }
28928048a3dSPeter Maydell 
float16_maybe_ah_chs(float16 a,bool fpcr_ah)290416650acSPeter Maydell static inline float16 float16_maybe_ah_chs(float16 a, bool fpcr_ah)
291416650acSPeter Maydell {
292416650acSPeter Maydell     return fpcr_ah && float16_is_any_nan(a) ? a : float16_chs(a);
293416650acSPeter Maydell }
294416650acSPeter Maydell 
float32_maybe_ah_chs(float32 a,bool fpcr_ah)295416650acSPeter Maydell static inline float32 float32_maybe_ah_chs(float32 a, bool fpcr_ah)
296416650acSPeter Maydell {
297416650acSPeter Maydell     return fpcr_ah && float32_is_any_nan(a) ? a : float32_chs(a);
298416650acSPeter Maydell }
299416650acSPeter Maydell 
float64_maybe_ah_chs(float64 a,bool fpcr_ah)300416650acSPeter Maydell static inline float64 float64_maybe_ah_chs(float64 a, bool fpcr_ah)
301416650acSPeter Maydell {
302416650acSPeter Maydell     return fpcr_ah && float64_is_any_nan(a) ? a : float64_chs(a);
303416650acSPeter Maydell }
304416650acSPeter Maydell 
30552581c71SMarkus Armbruster #endif /* TARGET_ARM_VEC_INTERNAL_H */
306