| 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 | } |