| 1 | /* |
| 2 | * Floating point intermediate representation |
| 3 | * |
| 4 | * The code in this source file is derived from release 2a of the SoftFloat |
| 5 | * IEC/IEEE Floating-point Arithmetic Package. Those parts of the code (and |
| 6 | * some later contributions) are provided under that license, as detailed below. |
| 7 | * It has subsequently been modified by contributors to the QEMU Project, |
| 8 | * so some portions are provided under: |
| 9 | * the SoftFloat-2a license |
| 10 | * the BSD license |
| 11 | * GPL-v2-or-later |
| 12 | * |
| 13 | * Any future contributions to this file after December 1st 2014 will be |
| 14 | * taken to be licensed under the Softfloat-2a license unless specifically |
| 15 | * indicated otherwise. |
| 16 | */ |
| 17 | |
| 18 | #ifndef SOFTFLOAT_PARTS_H |
| 19 | #define SOFTFLOAT_PARTS_H |
| 20 | |
| 21 | /* Format-specific handling of exp == exp_max */ |
| 22 | typedef enum __attribute__((__packed__)) { |
| 23 | /* exp==max, frac==0 ? infinity : nan; this is ieee standard. */ |
| 24 | float_expmax_ieee, |
| 25 | /* exp==max is a normal number; no infinity or nan representation. */ |
| 26 | float_expmax_normal, |
| 27 | /* exp==max, frac==max ? nan : normal; no infinity representation. */ |
| 28 | float_expmax_e4m3, |
| 29 | } FloatFmtExpMaxKind; |
| 30 | |
| 31 | /* |
| 32 | * Structure holding all of the relevant parameters for a format. |
| 33 | * exp_size: the size of the exponent field |
| 34 | * exp_bias: the offset applied to the exponent field |
| 35 | * exp_max: the maximum normalised exponent |
| 36 | * frac_size: the size of the fraction field |
| 37 | * frac_shift: shift to normalise the fraction with DECOMPOSED_BINARY_POINT |
| 38 | * The following are computed based the size of fraction |
| 39 | * round_mask: bits below lsb which must be rounded |
| 40 | * The following optional modifiers are available: |
| 41 | * exp_max_kind: affects how exp == exp_max is interpreted |
| 42 | * has_explicit_bit: has an explicit integer bit; this affects whether |
| 43 | * the float_status floatx80_behaviour handling applies |
| 44 | * overflow_raises_invalid: for float_expmax_normal, raise invalid |
| 45 | * instead of overflow. |
| 46 | */ |
| 47 | typedef struct { |
| 48 | int exp_size; |
| 49 | int exp_bias; |
| 50 | int exp_re_bias; |
| 51 | int exp_max; |
| 52 | int frac_size; |
| 53 | int frac_shift; |
| 54 | FloatFmtExpMaxKind exp_max_kind; |
| 55 | bool has_explicit_bit; |
| 56 | bool overflow_raises_invalid; |
| 57 | uint64_t round_mask; |
| 58 | } FloatFmt; |
| 59 | |
| 60 | extern const FloatFmt float4_e2m1_params; |
| 61 | extern const FloatFmt float8_e4m3_params; |
| 62 | extern const FloatFmt float8_e5m2_params; |
| 63 | extern const FloatFmt float16_params; |
| 64 | extern const FloatFmt bfloat16_params; |
| 65 | extern const FloatFmt float32_params; |
| 66 | extern const FloatFmt float64_params; |
| 67 | extern const FloatFmt float128_params; |
| 68 | |
| 69 | /* |
| 70 | * Classify a floating point number. Everything above float_class_qnan |
| 71 | * is a NaN so cls >= float_class_qnan is any NaN. |
| 72 | * |
| 73 | * Note that we canonicalize denormals, so most code should treat |
| 74 | * class_normal and class_denormal identically. |
| 75 | */ |
| 76 | |
| 77 | typedef enum __attribute__ ((__packed__)) { |
| 78 | float_class_unclassified, |
| 79 | float_class_zero, |
| 80 | float_class_normal, |
| 81 | float_class_denormal, /* input was a non-squashed denormal */ |
| 82 | float_class_inf, |
| 83 | float_class_qnan, /* all NaNs from here */ |
| 84 | float_class_snan, |
| 85 | } FloatClass; |
| 86 | |
| 87 | #define float_cmask(bit) (1u << (bit)) |
| 88 | |
| 89 | enum { |
| 90 | float_cmask_zero = float_cmask(float_class_zero), |
| 91 | float_cmask_normal = float_cmask(float_class_normal), |
| 92 | float_cmask_denormal = float_cmask(float_class_denormal), |
| 93 | float_cmask_inf = float_cmask(float_class_inf), |
| 94 | float_cmask_qnan = float_cmask(float_class_qnan), |
| 95 | float_cmask_snan = float_cmask(float_class_snan), |
| 96 | |
| 97 | float_cmask_infzero = float_cmask_zero | float_cmask_inf, |
| 98 | float_cmask_anynan = float_cmask_qnan | float_cmask_snan, |
| 99 | float_cmask_anynorm = float_cmask_normal | float_cmask_denormal, |
| 100 | }; |
| 101 | |
| 102 | /* |
| 103 | * Structure holding all of the decomposed parts of a float. |
| 104 | * The exponent is unbiased and the fraction is normalized. |
| 105 | * |
| 106 | * The fraction words are stored in big-endian word ordering, |
| 107 | * so that truncation from a larger format to a smaller format |
| 108 | * can be done simply by ignoring subsequent elements. |
| 109 | */ |
| 110 | |
| 111 | typedef struct { |
| 112 | FloatClass cls; |
| 113 | bool sign; |
| 114 | int32_t exp; |
| 115 | union { |
| 116 | /* Routines that know the structure may reference the singular name. */ |
| 117 | uint64_t frac; |
| 118 | /* |
| 119 | * Routines expanded with multiple structures reference "hi" and "lo" |
| 120 | * depending on the operation. In FloatParts64, "hi" and "lo" are |
| 121 | * both the same word and aliased here. |
| 122 | */ |
| 123 | uint64_t frac_hi; |
| 124 | uint64_t frac_lo; |
| 125 | }; |
| 126 | } FloatParts64; |
| 127 | |
| 128 | typedef struct { |
| 129 | FloatClass cls; |
| 130 | bool sign; |
| 131 | int32_t exp; |
| 132 | uint64_t frac_hi; |
| 133 | uint64_t frac_lo; |
| 134 | } FloatParts128; |
| 135 | |
| 136 | /* |
| 137 | * Unpack routines from a specific floating-point format. |
| 138 | */ |
| 139 | |
| 140 | FloatParts64 float4_e2m1_unpack_canonical(float4_e2m1 f, float_status *s); |
| 141 | FloatParts64 float8_e4m3_unpack_canonical(float8_e4m3 f, float_status *s); |
| 142 | FloatParts64 float8_e5m2_unpack_canonical(float8_e5m2 f, float_status *s); |
| 143 | FloatParts64 float16_unpack_canonical(float16 f, float_status *s); |
| 144 | FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s); |
| 145 | FloatParts64 float32_unpack_canonical(float32 f, float_status *s); |
| 146 | FloatParts64 float64_unpack_canonical(float64 f, float_status *s); |
| 147 | FloatParts128 float128_unpack_canonical(float128 f, float_status *s); |
| 148 | /* Returns false if the encoding is invalid. */ |
| 149 | bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f, float_status *s); |
| 150 | |
| 151 | /* |
| 152 | * Pack routines to a specific floating-point format. |
| 153 | */ |
| 154 | |
| 155 | float8_e4m3 float8_e4m3_round_pack_canonical(FloatParts64 *p, float_status *s, |
| 156 | bool saturate); |
| 157 | float8_e5m2 float8_e5m2_round_pack_canonical(FloatParts64 *p, float_status *s, |
| 158 | bool saturate); |
| 159 | float16 float16_round_pack_canonical(FloatParts64 *p, float_status *s); |
| 160 | bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, float_status *s); |
| 161 | float32 float32_round_pack_canonical(FloatParts64 *p, float_status *s); |
| 162 | float64 float64_round_pack_canonical(FloatParts64 *p, float_status *s); |
| 163 | float128 float128_round_pack_canonical(FloatParts128 *p, float_status *s); |
| 164 | floatx80 floatx80_round_pack_canonical(FloatParts128 *p, float_status *s); |
| 165 | |
| 166 | /* |
| 167 | * NaN handling |
| 168 | */ |
| 169 | |
| 170 | FloatParts64 parts64_default_nan(float_status *status); |
| 171 | FloatParts128 parts128_default_nan(float_status *status); |
| 172 | |
| 173 | FloatParts64 parts64_pick_nan(const FloatParts64 *, const FloatParts64 *, |
| 174 | float_status *); |
| 175 | FloatParts128 parts128_pick_nan(const FloatParts128 *, const FloatParts128 *, |
| 176 | float_status *); |
| 177 | |
| 178 | FloatParts64 parts64_return_nan(const FloatParts64 *a, float_status *s); |
| 179 | FloatParts128 parts128_return_nan(const FloatParts128 *a, float_status *s); |
| 180 | |
| 181 | /* |
| 182 | * Operations |
| 183 | */ |
| 184 | |
| 185 | FloatParts64 parts64_addsub(const FloatParts64 *a, const FloatParts64 *b, |
| 186 | float_status *s, bool subtract); |
| 187 | FloatParts128 parts128_addsub(const FloatParts128 *a, const FloatParts128 *b, |
| 188 | float_status *s, bool subtract); |
| 189 | |
| 190 | FloatRelation parts64_compare(const FloatParts64 *a, const FloatParts64 *b, |
| 191 | float_status *s, bool quiet); |
| 192 | FloatRelation parts128_compare(const FloatParts128 *a, const FloatParts128 *b, |
| 193 | float_status *s, bool quiet); |
| 194 | |
| 195 | FloatParts64 parts64_div(const FloatParts64 *a, const FloatParts64 *b, |
| 196 | float_status *s); |
| 197 | FloatParts128 parts128_div(const FloatParts128 *a, const FloatParts128 *b, |
| 198 | float_status *s); |
| 199 | |
| 200 | FloatParts64 parts64_mul(const FloatParts64 *a, const FloatParts64 *b, |
| 201 | float_status *s); |
| 202 | FloatParts128 parts128_mul(const FloatParts128 *a, const FloatParts128 *b, |
| 203 | float_status *s); |
| 204 | |
| 205 | FloatParts64 parts64_muladd(const FloatParts64 *a, |
| 206 | const FloatParts64 *b, |
| 207 | const FloatParts64 *c, |
| 208 | int flags, float_status *s); |
| 209 | FloatParts128 parts128_muladd(const FloatParts128 *a, |
| 210 | const FloatParts128 *b, |
| 211 | const FloatParts128 *c, |
| 212 | int flags, float_status *s); |
| 213 | |
| 214 | FloatParts64 parts64_round_to_int(const FloatParts64 *a, |
| 215 | FloatRoundMode rmode, |
| 216 | int scale, float_status *s, |
| 217 | const FloatFmt *fmt); |
| 218 | FloatParts128 parts128_round_to_int(const FloatParts128 *a, |
| 219 | FloatRoundMode rmode, |
| 220 | int scale, float_status *s, |
| 221 | const FloatFmt *fmt); |
| 222 | |
| 223 | FloatParts64 parts64_round_to_fmt(const FloatParts64 *p, float_status *s, |
| 224 | const FloatFmt *fmt); |
| 225 | |
| 226 | FloatParts64 parts64_scalbn(const FloatParts64 *a, int n, float_status *s); |
| 227 | FloatParts128 parts128_scalbn(const FloatParts128 *a, int n, float_status *s); |
| 228 | |
| 229 | #endif |