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
DEFINE_VSX_F2I_FUNC(float32,int32,xvcvspsxws)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
vsx_float64_is_nan(vsx_float64_vec_t v)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
DEFINE_VSX_BINARY_LOGICAL_OP_INSN(float32,logical_and,xxland)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 }
vsx_mask_out_float32_vec_to_uint32_vec(vsx_uint32_vec_t v)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 }
vsx_mask_out_float32_vec_to_int64_vec(vsx_int64_vec_t v)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 }
vsx_mask_out_float32_vec_to_uint64_vec(vsx_uint64_vec_t v)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
vsx_mask_out_float64_vec_to_int32_vec(vsx_int32_vec_t v)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
vsx_mask_out_float64_vec_to_uint32_vec(vsx_uint32_vec_t v)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
vsx_mask_out_float64_vec_to_int64_vec(vsx_int64_vec_t v)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 }
vsx_mask_out_float64_vec_to_uint64_vec(vsx_uint64_vec_t v)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
print_vsx_float32_vec_elements(FILE * stream,vsx_float32_vec_t vec)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
print_vsx_float64_vec_elements(FILE * stream,vsx_float64_vec_t vec)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
print_vsx_int32_vec_elements(FILE * stream,vsx_int32_vec_t vec)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
print_vsx_uint32_vec_elements(FILE * stream,vsx_uint32_vec_t vec)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
print_vsx_int64_vec_elements(FILE * stream,vsx_int64_vec_t vec)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
print_vsx_uint64_vec_elements(FILE * stream,vsx_uint64_vec_t vec)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
DEFINE_VSX_ALL_EQ_FUNC(int32,vcmpequw)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
vsx_int64_vec_from_mask(int mask)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
main(void)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