xref: /openbmc/qemu/tests/tcg/ppc64/vsx_f2i_nan.c (revision 2e1cacfb)
1 #include <stdio.h>
2 #include "qemu/compiler.h"
3 
4 typedef vector float vsx_float32_vec_t;
5 typedef vector double vsx_float64_vec_t;
6 typedef vector signed int vsx_int32_vec_t;
7 typedef vector unsigned int vsx_uint32_vec_t;
8 typedef vector signed long long vsx_int64_vec_t;
9 typedef vector unsigned long long vsx_uint64_vec_t;
10 
11 #define DEFINE_VSX_F2I_FUNC(SRC_T, DEST_T, INSN)                       \
12 static inline vsx_##DEST_T##_vec_t                                     \
13     vsx_convert_##SRC_T##_vec_to_##DEST_T##_vec(vsx_##SRC_T##_vec_t v) \
14 {                                                                      \
15     vsx_##DEST_T##_vec_t result;                                       \
16     asm(#INSN " %x0, %x1" : "=wa" (result) : "wa" (v));                \
17     return result;                                                     \
18 }
19 
20 DEFINE_VSX_F2I_FUNC(float32, int32, xvcvspsxws)
21 DEFINE_VSX_F2I_FUNC(float32, uint32, xvcvspuxws)
22 DEFINE_VSX_F2I_FUNC(float32, int64, xvcvspsxds)
23 DEFINE_VSX_F2I_FUNC(float32, uint64, xvcvspuxds)
24 DEFINE_VSX_F2I_FUNC(float64, int32, xvcvdpsxws)
25 DEFINE_VSX_F2I_FUNC(float64, uint32, xvcvdpuxws)
26 DEFINE_VSX_F2I_FUNC(float64, int64, xvcvdpsxds)
27 DEFINE_VSX_F2I_FUNC(float64, uint64, xvcvdpuxds)
28 
29 static inline vsx_float32_vec_t vsx_float32_is_nan(vsx_float32_vec_t v)
30 {
31     vsx_float32_vec_t abs_v;
32     vsx_float32_vec_t result_mask;
33     const vsx_uint32_vec_t f32_pos_inf_bits = {0x7F800000U, 0x7F800000U,
34                                                0x7F800000U, 0x7F800000U};
35 
36     asm("xvabssp %x0, %x1" : "=wa" (abs_v) : "wa" (v));
37     asm("vcmpgtuw %0, %1, %2"
38         : "=v" (result_mask)
39         : "v" (abs_v), "v" (f32_pos_inf_bits));
40     return result_mask;
41 }
42 
43 static inline vsx_float64_vec_t vsx_float64_is_nan(vsx_float64_vec_t v)
44 {
45     vsx_float64_vec_t abs_v;
46     vsx_float64_vec_t result_mask;
47     const vsx_uint64_vec_t f64_pos_inf_bits = {0x7FF0000000000000ULL,
48                                                0x7FF0000000000000ULL};
49 
50     asm("xvabsdp %x0, %x1" : "=wa" (abs_v) : "wa" (v));
51     asm("vcmpgtud %0, %1, %2"
52         : "=v" (result_mask)
53         : "v" (abs_v), "v" (f64_pos_inf_bits));
54     return result_mask;
55 }
56 
57 #define DEFINE_VSX_BINARY_LOGICAL_OP_INSN(LANE_TYPE, OP_NAME, OP_INSN)    \
58 static inline vsx_##LANE_TYPE##_vec_t vsx_##LANE_TYPE##_##OP_NAME(        \
59     vsx_##LANE_TYPE##_vec_t a, vsx_##LANE_TYPE##_vec_t b)                 \
60 {                                                                         \
61     vsx_##LANE_TYPE##_vec_t result;                                       \
62     asm(#OP_INSN " %x0, %x1, %x2" : "=wa" (result) : "wa" (a), "wa" (b)); \
63     return result;                                                        \
64 }
65 
66 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(float32, logical_and, xxland)
67 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(float64, logical_and, xxland)
68 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(int32, logical_and, xxland)
69 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(uint32, logical_and, xxland)
70 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(int64, logical_and, xxland)
71 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(uint64, logical_and, xxland)
72 
73 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(float32, logical_andc, xxlandc)
74 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(float64, logical_andc, xxlandc)
75 
76 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(float32, logical_or, xxlor)
77 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(float64, logical_or, xxlor)
78 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(int32, logical_or, xxlor)
79 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(uint32, logical_or, xxlor)
80 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(int64, logical_or, xxlor)
81 DEFINE_VSX_BINARY_LOGICAL_OP_INSN(uint64, logical_or, xxlor)
82 
83 static inline vsx_int32_vec_t vsx_mask_out_float32_vec_to_int32_vec(
84     vsx_int32_vec_t v)
85 {
86     return v;
87 }
88 static inline vsx_uint32_vec_t vsx_mask_out_float32_vec_to_uint32_vec(
89     vsx_uint32_vec_t v)
90 {
91     return v;
92 }
93 static inline vsx_int64_vec_t vsx_mask_out_float32_vec_to_int64_vec(
94     vsx_int64_vec_t v)
95 {
96     return v;
97 }
98 static inline vsx_uint64_vec_t vsx_mask_out_float32_vec_to_uint64_vec(
99     vsx_uint64_vec_t v)
100 {
101     return v;
102 }
103 
104 static inline vsx_int32_vec_t vsx_mask_out_float64_vec_to_int32_vec(
105     vsx_int32_vec_t v)
106 {
107 #if HOST_BIG_ENDIAN
108     const vsx_int32_vec_t valid_lanes_mask = {-1, 0, -1, 0};
109 #else
110     const vsx_int32_vec_t valid_lanes_mask = {0, -1, 0, -1};
111 #endif
112 
113     return vsx_int32_logical_and(v, valid_lanes_mask);
114 }
115 
116 static inline vsx_uint32_vec_t vsx_mask_out_float64_vec_to_uint32_vec(
117     vsx_uint32_vec_t v)
118 {
119     return (vsx_uint32_vec_t)vsx_mask_out_float64_vec_to_int32_vec(
120         (vsx_int32_vec_t)v);
121 }
122 
123 static inline vsx_int64_vec_t vsx_mask_out_float64_vec_to_int64_vec(
124     vsx_int64_vec_t v)
125 {
126     return v;
127 }
128 static inline vsx_uint64_vec_t vsx_mask_out_float64_vec_to_uint64_vec(
129     vsx_uint64_vec_t v)
130 {
131     return v;
132 }
133 
134 static inline void print_vsx_float32_vec_elements(FILE *stream,
135                                                   vsx_float32_vec_t vec)
136 {
137     fprintf(stream, "%g, %g, %g, %g", (double)vec[0], (double)vec[1],
138             (double)vec[2], (double)vec[3]);
139 }
140 
141 static inline void print_vsx_float64_vec_elements(FILE *stream,
142                                                   vsx_float64_vec_t vec)
143 {
144     fprintf(stream, "%.17g, %.17g", vec[0], vec[1]);
145 }
146 
147 static inline void print_vsx_int32_vec_elements(FILE *stream,
148                                                 vsx_int32_vec_t vec)
149 {
150     fprintf(stream, "%d, %d, %d, %d", vec[0], vec[1], vec[2], vec[3]);
151 }
152 
153 static inline void print_vsx_uint32_vec_elements(FILE *stream,
154                                                  vsx_uint32_vec_t vec)
155 {
156     fprintf(stream, "%u, %u, %u, %u", vec[0], vec[1], vec[2], vec[3]);
157 }
158 
159 static inline void print_vsx_int64_vec_elements(FILE *stream,
160                                                 vsx_int64_vec_t vec)
161 {
162     fprintf(stream, "%lld, %lld", vec[0], vec[1]);
163 }
164 
165 static inline void print_vsx_uint64_vec_elements(FILE *stream,
166                                                  vsx_uint64_vec_t vec)
167 {
168     fprintf(stream, "%llu, %llu", vec[0], vec[1]);
169 }
170 
171 #define DEFINE_VSX_ALL_EQ_FUNC(LANE_TYPE, CMP_INSN)                   \
172 static inline int vsx_##LANE_TYPE##_all_eq(vsx_##LANE_TYPE##_vec_t a, \
173                                            vsx_##LANE_TYPE##_vec_t b) \
174 {                                                                     \
175     unsigned result;                                                  \
176     vsx_##LANE_TYPE##_vec_t is_eq_mask_vec;                           \
177     asm(#CMP_INSN ". %0, %2, %3\n\t"                                  \
178         "mfocrf %1, 2"                                                \
179         : "=v" (is_eq_mask_vec), "=r" (result)                        \
180         : "v" (a), "v" (b)                                            \
181         : "cr6");                                                     \
182     return (int)((result >> 7) & 1u);                                 \
183 }
184 
185 DEFINE_VSX_ALL_EQ_FUNC(int32, vcmpequw)
186 DEFINE_VSX_ALL_EQ_FUNC(uint32, vcmpequw)
187 DEFINE_VSX_ALL_EQ_FUNC(int64, vcmpequd)
188 DEFINE_VSX_ALL_EQ_FUNC(uint64, vcmpequd)
189 
190 #define DEFINE_VSX_F2I_TEST_FUNC(SRC_T, DEST_T)                          \
191 static inline int test_vsx_conv_##SRC_T##_vec_to_##DEST_T##_vec(         \
192     vsx_##SRC_T##_vec_t src_v)                                           \
193 {                                                                        \
194     const vsx_##SRC_T##_vec_t is_nan_mask = vsx_##SRC_T##_is_nan(src_v); \
195     const vsx_##SRC_T##_vec_t nan_src_v =                                \
196         vsx_##SRC_T##_logical_and(src_v, is_nan_mask);                   \
197     const vsx_##SRC_T##_vec_t non_nan_src_v =                            \
198         vsx_##SRC_T##_logical_andc(src_v, is_nan_mask);                  \
199                                                                          \
200     const vsx_##DEST_T##_vec_t expected_result =                         \
201         vsx_mask_out_##SRC_T##_vec_to_##DEST_T##_vec(                    \
202             vsx_##DEST_T##_logical_or(                                   \
203                 vsx_convert_##SRC_T##_vec_to_##DEST_T##_vec(nan_src_v),  \
204                 vsx_convert_##SRC_T##_vec_to_##DEST_T##_vec(             \
205                     non_nan_src_v)));                                    \
206     const vsx_##DEST_T##_vec_t actual_result =                           \
207         vsx_mask_out_##SRC_T##_vec_to_##DEST_T##_vec(                    \
208             vsx_convert_##SRC_T##_vec_to_##DEST_T##_vec(src_v));         \
209     const int test_result =                                              \
210         vsx_##DEST_T##_all_eq(expected_result, actual_result);           \
211                                                                          \
212     if (unlikely(test_result == 0)) {                                    \
213         fputs("FAIL: Conversion of " #SRC_T " vector to " #DEST_T        \
214               " vector failed\n", stdout);                               \
215         fputs("Source values: ", stdout);                                \
216         print_vsx_##SRC_T##_vec_elements(stdout, src_v);                 \
217         fputs("\nExpected result: ", stdout);                            \
218         print_vsx_##DEST_T##_vec_elements(stdout, expected_result);      \
219         fputs("\nActual result: ", stdout);                              \
220         print_vsx_##DEST_T##_vec_elements(stdout, actual_result);        \
221         fputs("\n\n", stdout);                                           \
222     }                                                                    \
223                                                                          \
224     return test_result;                                                  \
225 }
226 
227 
228 DEFINE_VSX_F2I_TEST_FUNC(float32, int32)
229 DEFINE_VSX_F2I_TEST_FUNC(float32, uint32)
230 DEFINE_VSX_F2I_TEST_FUNC(float32, int64)
231 DEFINE_VSX_F2I_TEST_FUNC(float32, uint64)
232 DEFINE_VSX_F2I_TEST_FUNC(float64, int32)
233 DEFINE_VSX_F2I_TEST_FUNC(float64, uint32)
234 DEFINE_VSX_F2I_TEST_FUNC(float64, int64)
235 DEFINE_VSX_F2I_TEST_FUNC(float64, uint64)
236 
237 static inline vsx_int32_vec_t vsx_int32_vec_from_mask(int mask)
238 {
239     const vsx_int32_vec_t bits_to_test = {1, 2, 4, 8};
240     const vsx_int32_vec_t vec_mask = {mask, mask, mask, mask};
241     vsx_int32_vec_t result;
242 
243     asm("vcmpequw %0, %1, %2"
244         : "=v" (result)
245         : "v" (vsx_int32_logical_and(vec_mask, bits_to_test)),
246           "v" (bits_to_test));
247     return result;
248 }
249 
250 static inline vsx_int64_vec_t vsx_int64_vec_from_mask(int mask)
251 {
252     const vsx_int64_vec_t bits_to_test = {1, 2};
253     const vsx_int64_vec_t vec_mask = {mask, mask};
254     vsx_int64_vec_t result;
255 
256     asm("vcmpequd %0, %1, %2"
257         : "=v" (result)
258         : "v" (vsx_int64_logical_and(vec_mask, bits_to_test)),
259           "v" (bits_to_test));
260     return result;
261 }
262 
263 int main(void)
264 {
265     const vsx_float32_vec_t f32_iota1 = {1.0f, 2.0f, 3.0f, 4.0f};
266     const vsx_float64_vec_t f64_iota1 = {1.0, 2.0};
267 
268     int num_of_tests_failed = 0;
269 
270     for (int i = 0; i < 16; i++) {
271         const vsx_int32_vec_t nan_mask = vsx_int32_vec_from_mask(i);
272         const vsx_float32_vec_t f32_v =
273             vsx_float32_logical_or(f32_iota1, (vsx_float32_vec_t)nan_mask);
274         num_of_tests_failed +=
275             (int)(!test_vsx_conv_float32_vec_to_int32_vec(f32_v));
276         num_of_tests_failed +=
277             (int)(!test_vsx_conv_float32_vec_to_int64_vec(f32_v));
278         num_of_tests_failed +=
279             (int)(!test_vsx_conv_float32_vec_to_uint32_vec(f32_v));
280         num_of_tests_failed +=
281             (int)(!test_vsx_conv_float32_vec_to_uint64_vec(f32_v));
282     }
283 
284     for (int i = 0; i < 4; i++) {
285         const vsx_int64_vec_t nan_mask = vsx_int64_vec_from_mask(i);
286         const vsx_float64_vec_t f64_v =
287             vsx_float64_logical_or(f64_iota1, (vsx_float64_vec_t)nan_mask);
288         num_of_tests_failed +=
289             (int)(!test_vsx_conv_float64_vec_to_int32_vec(f64_v));
290         num_of_tests_failed +=
291             (int)(!test_vsx_conv_float64_vec_to_int64_vec(f64_v));
292         num_of_tests_failed +=
293             (int)(!test_vsx_conv_float64_vec_to_uint32_vec(f64_v));
294         num_of_tests_failed +=
295             (int)(!test_vsx_conv_float64_vec_to_uint64_vec(f64_v));
296     }
297 
298     printf("%d tests failed\n", num_of_tests_failed);
299     return (int)(num_of_tests_failed != 0);
300 }
301