Index: tests/simd/vector_extension.c |
diff --git a/tests/simd/vector_extension.c b/tests/simd/vector_extension.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c5e66b045e6ff6d1421a8a99e877850014e72825 |
--- /dev/null |
+++ b/tests/simd/vector_extension.c |
@@ -0,0 +1,253 @@ |
+/* |
+ * Copyright (c) 2014 The Native Client Authors. All rights reserved. |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+/* |
+ * Test that the GCC/LLVM vector extensions can be used from C code. |
+ * http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html |
+ * http://clang.llvm.org/docs/LanguageExtensions.html |
+ * |
+ * This test is thorough feature-wise, but not thorough in testing the |
+ * corner-case values. It tries to exercise all vector types and |
+ * operations that are supported, and verifies that test values generate |
+ * the right result by comparing to a golden output file. It does not |
+ * test all the MIN/MAX values, nor does it test undefined behavior. |
+ * |
+ * TODO(jfb) Add testing for vector conversion. |
+ * TODO(jfb) Add testing for vector shuffle once PNaCl supports it. |
+ */ |
+ |
+#include "native_client/src/include/nacl_macros.h" |
+ |
+#include <stdint.h> |
+#include <stdio.h> |
+ |
+/* |
+ * Basic types that are supported inside vectors. |
+ * |
+ * TODO(jfb) Handle 64-bit int and double. |
+ */ |
+typedef int8_t I8; |
+typedef uint8_t U8; |
+typedef int16_t I16; |
+typedef uint16_t U16; |
+typedef int32_t I32; |
+typedef uint32_t U32; |
+typedef float F32; |
+ |
+/* |
+ * |
+ * The GCC/LLVM vector extensions represent the results of comparisons |
+ * as a vector of all-ones or all-zeros with the same vector bit width |
+ * and number of elements. They must be treated differently than their |
+ * corresponding type because floating-point values change their bit |
+ * representation through assignments when they hold NaN values. |
+ */ |
+typedef int8_t I8_BOOL; |
+typedef int8_t U8_BOOL; |
+typedef int16_t I16_BOOL; |
+typedef int16_t U16_BOOL; |
+typedef int32_t I32_BOOL; |
+typedef int32_t U32_BOOL; |
+typedef int32_t F32_BOOL; |
+ |
+#define I8_FMT "i" |
+#define U8_FMT "u" |
+#define I16_FMT "i" |
+#define U16_FMT "u" |
+#define I32_FMT "i" |
+#define U32_FMT "u" |
+#define F32_FMT "f" |
+ |
+/* All elements in a boolean vector should print as 0 or -1. */ |
+#define I8_BOOL_FMT "i" |
+#define U8_BOOL_FMT "i" |
+#define I16_BOOL_FMT "i" |
+#define U16_BOOL_FMT "i" |
+#define I32_BOOL_FMT "i" |
+#define U32_BOOL_FMT "i" |
+#define F32_BOOL_FMT "i" |
+ |
+/* All supported vector types are currently 128-bit wide. */ |
+#define VEC_BYTES 16 |
+ |
+/* Vector types corresponding to each supported basic types. */ |
+typedef I8 VI8 __attribute__((vector_size(VEC_BYTES))); |
+typedef U8 VU8 __attribute__((vector_size(VEC_BYTES))); |
+typedef I16 VI16 __attribute__((vector_size(VEC_BYTES))); |
+typedef U16 VU16 __attribute__((vector_size(VEC_BYTES))); |
+typedef I32 VI32 __attribute__((vector_size(VEC_BYTES))); |
+typedef U32 VU32 __attribute__((vector_size(VEC_BYTES))); |
+typedef F32 VF32 __attribute__((vector_size(VEC_BYTES))); |
+ |
+/* Boolean vector types generate by comparisons on each vector type. */ |
+typedef I8 VI8_BOOL __attribute__((vector_size(VEC_BYTES))); |
+typedef I8 VU8_BOOL __attribute__((vector_size(VEC_BYTES))); |
+typedef I16 VI16_BOOL __attribute__((vector_size(VEC_BYTES))); |
+typedef I16 VU16_BOOL __attribute__((vector_size(VEC_BYTES))); |
+typedef I32 VI32_BOOL __attribute__((vector_size(VEC_BYTES))); |
+typedef I32 VU32_BOOL __attribute__((vector_size(VEC_BYTES))); |
+typedef I32 VF32_BOOL __attribute__((vector_size(VEC_BYTES))); |
+ |
+#define PRINT(TYPE, VEC) \ |
+ do { \ |
+ NACL_COMPILE_TIME_ASSERT(sizeof(V##TYPE) == \ |
+ VEC_BYTES); /* Vector must be 128 bits. */ \ |
+ NACL_COMPILE_TIME_ASSERT(sizeof(TYPE) == \ |
+ sizeof(VEC[0])); /* Type must match. */ \ |
+ printf("{"); \ |
+ for (size_t i = 0; i != sizeof(V##TYPE) / sizeof(VEC[0]); ++i) \ |
+ printf("%" TYPE##_FMT ",", VEC[i]); \ |
+ printf("}"); \ |
+ } while (0) |
+ |
+#define TEST_BINARY(TYPE, LHS, OP, RHS) \ |
+ do { \ |
+ NACL_COMPILE_TIME_ASSERT(sizeof(TYPE) == \ |
+ sizeof(LHS[0])); /* Types must match. */ \ |
+ NACL_COMPILE_TIME_ASSERT(sizeof(TYPE) == \ |
+ sizeof(RHS[0])); /* Types must match. */ \ |
+ const V##TYPE result = LHS OP RHS; \ |
+ printf(#TYPE " "); \ |
+ PRINT(TYPE, LHS); \ |
+ printf(" %s ", #OP); \ |
+ PRINT(TYPE, RHS); \ |
+ printf(" = "); \ |
+ PRINT(TYPE, result); \ |
+ printf("\n"); \ |
+ } while (0) |
+ |
+#define TEST_BINARY_COMPARISON(TYPE, LHS, OP, RHS) \ |
+ do { \ |
+ NACL_COMPILE_TIME_ASSERT(sizeof(TYPE) == \ |
+ sizeof(LHS[0])); /* Types must match. */ \ |
+ NACL_COMPILE_TIME_ASSERT(sizeof(TYPE) == \ |
+ sizeof(RHS[0])); /* Types must match. */ \ |
+ const V##TYPE##_BOOL result = LHS OP RHS; \ |
+ printf(#TYPE " "); \ |
+ PRINT(TYPE, LHS); \ |
+ printf(" %s ", #OP); \ |
+ PRINT(TYPE, RHS); \ |
+ printf(" = "); \ |
+ PRINT(TYPE##_BOOL, result); \ |
+ printf("\n"); \ |
+ } while (0) |
+ |
+#define TEST_UNARY(TYPE, OP, VAL) \ |
+ do { \ |
+ NACL_COMPILE_TIME_ASSERT(sizeof(TYPE) == \ |
+ sizeof(VAL[0])); /* Types must match. */ \ |
+ const V##TYPE result = OP VAL; \ |
+ printf(#TYPE " %s ", #OP); \ |
+ PRINT(TYPE, VAL); \ |
+ printf(" = "); \ |
+ PRINT(TYPE, result); \ |
+ printf("\n"); \ |
+ } while (0) |
+ |
+#define TEST_BINARY_FP(TYPE, LHS, RHS) \ |
+ do { \ |
+ TEST_BINARY(TYPE, LHS, +, RHS); \ |
+ TEST_BINARY(TYPE, LHS, -, RHS); \ |
+ TEST_BINARY(TYPE, LHS, *, RHS); \ |
+ TEST_BINARY(TYPE, LHS, /, RHS); \ |
+ TEST_BINARY_COMPARISON(TYPE, LHS, ==, RHS); \ |
+ TEST_BINARY_COMPARISON(TYPE, LHS, !=, RHS); \ |
+ TEST_BINARY_COMPARISON(TYPE, LHS, <, RHS); \ |
+ TEST_BINARY_COMPARISON(TYPE, LHS, >, RHS); \ |
+ TEST_BINARY_COMPARISON(TYPE, LHS, <=, RHS); \ |
+ TEST_BINARY_COMPARISON(TYPE, LHS, >=, RHS); \ |
+ } while (0) |
+ |
+#define TEST_BINARY_INT(TYPE, LHS, RHS) \ |
+ do { \ |
+ TEST_BINARY_FP(TYPE, LHS, RHS); \ |
+ TEST_BINARY(TYPE, LHS, %, RHS); \ |
+ TEST_BINARY(TYPE, LHS, &, RHS); \ |
+ TEST_BINARY(TYPE, LHS, |, RHS); \ |
+ TEST_BINARY(TYPE, LHS, ^, RHS); \ |
+ TEST_BINARY(TYPE, LHS, <<, RHS); \ |
+ TEST_BINARY(TYPE, LHS, >>, RHS); \ |
+ } while (0) |
+ |
+/* |
+ * TODO(jfb) Pre/post ++/-- don't seem to be supported. Neither does !. |
+ */ |
+#define TEST_UNARY_FP(TYPE, VAL) \ |
+ do { \ |
+ TEST_UNARY(TYPE, +, VAL); \ |
+ TEST_UNARY(TYPE, -, VAL); \ |
+ } while (0) |
+ |
+#define TEST_UNARY_INT(TYPE, VAL) \ |
+ do { \ |
+ TEST_UNARY_FP(TYPE, VAL); \ |
+ TEST_UNARY(TYPE, ~, VAL); \ |
+ } while (0) |
+ |
+/* |
+ * Vector values used in tests. |
+ * |
+ * Initialize everything in a non-inlined function to make sure that |
+ * nothing gets pre-computed. |
+ */ |
+VI8 vi8[2]; |
+VU8 vu8[2]; |
+VI16 vi16[2]; |
+VU16 vu16[2]; |
+VI32 vi32[2]; |
+VU32 vu32[2]; |
+VF32 vf32[2]; |
+__attribute__((noinline)) void init(void) { |
+ /* |
+ * TODO(jfb) Test undefined behavior: shift bit bitwidth or larger, |
+ * and divide by zero. |
+ */ |
+ vi8[0] = (VI8) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; |
+ vi8[1] = (VI8) {2, 1, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1}; |
+ |
+ vu8[0] = (VU8) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; |
+ vu8[1] = (VU8) {2, 1, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1}; |
+ |
+ vi16[0] = (VI16) {1, 2, 3, 4, 5, 6, 7, 8}; |
+ vi16[1] = (VI16) {1, 15, 14, 13, 12, 11, 10, 9}; |
+ |
+ vu16[0] = (VU16) {1, 2, 3, 4, 5, 6, 7, 8}; |
+ vu16[1] = (VU16) {1, 15, 14, 13, 12, 11, 10, 9}; |
+ |
+ vi32[0] = (VI32) {1, 2, 3, 4}; |
+ vi32[1] = (VI32) {16, 15, 14, 13}; |
+ |
+ vu32[0] = (VU32) {1, 2, 3, 4}; |
+ vu32[1] = (VU32) {16, 15, 14, 13}; |
+ |
+ vf32[0] = (VF32) {1, 2, 3, 4}; |
+ vf32[1] = (VF32) {16, 15, 14, 13}; |
+} |
+ |
+__attribute__((noinline)) void test(void) { |
+ TEST_BINARY_INT(I8, vi8[0], vi8[1]); |
+ TEST_BINARY_INT(U8, vu8[0], vu8[1]); |
+ TEST_BINARY_INT(I16, vi16[0], vi16[1]); |
+ TEST_BINARY_INT(U16, vu16[0], vu16[1]); |
+ TEST_BINARY_INT(I32, vi32[0], vi32[1]); |
+ TEST_BINARY_INT(U32, vu32[0], vu32[1]); |
+ TEST_BINARY_FP(F32, vf32[0], vf32[1]); |
+ |
+ TEST_UNARY_INT(I8, vi8[0]); |
+ TEST_UNARY_INT(U8, vu8[0]); |
+ TEST_UNARY_INT(I16, vi16[0]); |
+ TEST_UNARY_INT(U16, vu16[0]); |
+ TEST_UNARY_INT(I32, vi32[0]); |
+ TEST_UNARY_INT(U32, vu32[0]); |
+ TEST_UNARY_FP(F32, vf32[0]); |
+} |
+ |
+int main(void) { |
+ init(); |
+ test(); |
+ |
+ return 0; |
+} |