master
c 137 lines 4.28 KB
Raw
1 /*
2 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "qemu/osdep.h"
8 #include "hvx_ieee_fp.h"
9
10 float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status)
11 {
12 return float32_mul(float16_to_float32(a1, true, fp_status),
13 float16_to_float32(a2, true, fp_status), fp_status);
14 }
15
16 float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4,
17 float_status *fp_status)
18 {
19 return float32_add(fp_mult_sf_hf(a1, a3, fp_status),
20 fp_mult_sf_hf(a2, a4, fp_status), fp_status);
21 }
22
23 #define float32_is_pos_nan(X) (float32_is_any_nan(X) && !float32_is_neg(X))
24 #define float32_is_neg_nan(X) (float32_is_any_nan(X) && float32_is_neg(X))
25 #define float16_is_pos_nan(X) (float16_is_any_nan(X) && !float16_is_neg(X))
26 #define float16_is_neg_nan(X) (float16_is_any_nan(X) && float16_is_neg(X))
27
28 /* Qfloat min/max treat +NaN as greater than +INF and -NaN as smaller than -INF */
29 float32 qf_max_sf(float32 a1, float32 a2, float_status *fp_status)
30 {
31 if (float32_is_pos_nan(a1) || float32_is_neg_nan(a2)) {
32 return a1;
33 }
34 if (float32_is_pos_nan(a2) || float32_is_neg_nan(a1)) {
35 return a2;
36 }
37 return float32_max(a1, a2, fp_status);
38 }
39
40 float32 qf_min_sf(float32 a1, float32 a2, float_status *fp_status)
41 {
42 if (float32_is_pos_nan(a1) || float32_is_neg_nan(a2)) {
43 return a2;
44 }
45 if (float32_is_pos_nan(a2) || float32_is_neg_nan(a1)) {
46 return a1;
47 }
48 return float32_min(a1, a2, fp_status);
49 }
50
51 float16 qf_max_hf(float16 a1, float16 a2, float_status *fp_status)
52 {
53 if (float16_is_pos_nan(a1) || float16_is_neg_nan(a2)) {
54 return a1;
55 }
56 if (float16_is_pos_nan(a2) || float16_is_neg_nan(a1)) {
57 return a2;
58 }
59 return float16_max(a1, a2, fp_status);
60 }
61
62 float16 qf_min_hf(float16 a1, float16 a2, float_status *fp_status)
63 {
64 if (float16_is_pos_nan(a1) || float16_is_neg_nan(a2)) {
65 return a2;
66 }
67 if (float16_is_pos_nan(a2) || float16_is_neg_nan(a1)) {
68 return a1;
69 }
70 return float16_min(a1, a2, fp_status);
71 }
72
73 int32_t conv_w_sf(float32 a, float_status *fp_status)
74 {
75 /* float32_to_int32 converts any NaN to MAX, hexagon looks at the sign. */
76 if (float32_is_any_nan(a)) {
77 return float32_is_neg(a) ? INT32_MIN : INT32_MAX;
78 }
79 return float32_to_int32_round_to_zero(a, fp_status);
80 }
81
82 int16_t conv_h_hf(float16 a, float_status *fp_status)
83 {
84 /* float16_to_int16 converts any NaN to MAX, hexagon looks at the sign. */
85 if (float16_is_any_nan(a)) {
86 return float16_is_neg(a) ? INT16_MIN : INT16_MAX;
87 }
88 return float16_to_int16_round_to_zero(a, fp_status);
89 }
90
91 /*
92 * Returns true if f1 > f2, where at least one of the elements is guaranteed
93 * to be NaN.
94 * Up to v73, Hexagon HVX IEEE FP follows this order:
95 * QNaN > SNaN > +Inf > numbers > -Inf > SNaN_neg > QNaN_neg
96 */
97 static bool float32_nan_compare(float32 f1, float32 f2, float_status *fp_status)
98 {
99 /* opposite signs case */
100 if (float32_is_neg(f1) != float32_is_neg(f2)) {
101 return !float32_is_neg(f1);
102 }
103
104 /* same sign case */
105 bool result = (float32_is_any_nan(f1) && !float32_is_any_nan(f2)) ||
106 (float32_is_quiet_nan(f1, fp_status) && !float32_is_quiet_nan(f2, fp_status));
107 return float32_is_neg(f1) ? !result : result;
108 }
109
110 static bool float16_nan_compare(float16 f1, float16 f2, float_status *fp_status)
111 {
112 /* opposite signs case */
113 if (float16_is_neg(f1) != float16_is_neg(f2)) {
114 return !float16_is_neg(f1);
115 }
116
117 /* same sign case */
118 bool result = (float16_is_any_nan(f1) && !float16_is_any_nan(f2)) ||
119 (float16_is_quiet_nan(f1, fp_status) && !float16_is_quiet_nan(f2, fp_status));
120 return float16_is_neg(f1) ? !result : result;
121 }
122
123 uint32_t cmpgt_sf(float32 a1, float32 a2, float_status *fp_status)
124 {
125 if (float32_is_any_nan(a1) || float32_is_any_nan(a2)) {
126 return float32_nan_compare(a1, a2, fp_status);
127 }
128 return float32_compare(a1, a2, fp_status) == float_relation_greater;
129 }
130
131 uint16_t cmpgt_hf(float16 a1, float16 a2, float_status *fp_status)
132 {
133 if (float16_is_any_nan(a1) || float16_is_any_nan(a2)) {
134 return float16_nan_compare(a1, a2, fp_status);
135 }
136 return float16_compare(a1, a2, fp_status) == float_relation_greater;
137 }