1This directory contains executable tests for ARM/AArch64 Advanced SIMD
2(Neon) intrinsics.
3
4It is meant to cover execution cases of all the Advanced SIMD
5intrinsics, but does not scan the generated assembler code.
6
7The general framework is composed as follows:
8- advsimd-intrinsics.exp: main dejagnu driver
9- *.c: actual tests, generally one per intrinsinc family
10- arm-neon-ref.h: contains macro definitions to save typing in actual
11  test files
12- compute-ref-data.h: contains input vectors definitions
13- *.inc: generic tests, shared by several families of intrinsics. For
14   instance, unary or binary operators
15
16A typical .c test file starts with the following contents (look at
17vld1.c and vaba.c for sample cases):
18#include <arm_neon.h>
19#include "arm-neon-ref.h"
20#include "compute-ref-data.h"
21
22Then, definitions of expected results, based on common input values,
23as defined in compute-ref-data.h.
24For example:
25VECT_VAR_DECL(expected,int,16,4) [] = { 0x16, 0x17, 0x18, 0x19 };
26defines the expected results of an operator generating int16x4 values.
27
28The common input values defined in compute-ref-data.h have been chosen
29to avoid corner-case values for most operators, yet exposing negative
30values for signed operators. For this reason, their range is also
31limited. For instance, the initialization of buffer_int16x4 will be
32{ -16, -15, -14, -13 }.
33
34The initialization of floating-point values is done via hex notation,
35to avoid potential rounding problems.
36
37To test special values and corner cases, specific initialization
38values should be used in dedicated tests, to ensure proper coverage.
39An example of this is vshl.
40
41When a variant of an intrinsic is not available, its expected result
42should be defined to the value of CLEAN_PATTERN_8 as defined in
43arm-neon-ref.h. For example:
44VECT_VAR_DECL(expected,int,64,1) [] = { 0x3333333333333333 };
45if the given intrinsic has no variant producing an int64x1 result,
46like the vcmp family (eg. vclt).
47
48This is because the helper function (check_results(), defined in
49arm-neon-ref.h), iterates over all the possible variants, to save
50typing in each individual test file. Alternatively, one can directly
51call the CHECK/CHECK_FP macros to check only a few expected results
52(see vabs.c for an example).
53
54Then, define the TEST_MSG string, which will be used when reporting errors.
55
56Next, define the function performing the actual tests, in general
57relying on the helpers provided by arm-neon-ref.h, which means:
58
59* declare necessary vectors of suitable types: using
60  DECL_VARIABLE_ALL_VARIANTS when all variants are supported, or the
61  relevant of subset calls to DECL_VARIABLE.
62
63* call clean_results() to initialize the 'results' buffers.
64
65* initialize the input vectors, using VLOAD, VDUP or VSET_LANE (vld*
66  tests do not need this step, since their actual purpose is to
67  initialize vectors).
68
69* execute the intrinsic on relevant variants, for instance using
70  TEST_MACRO_ALL_VARIANTS_2_5.
71
72* call check_results() to check that the results match the expected
73  values.
74
75A template test file could be:
76=================================================================
77#include <arm_neon.h>
78#include "arm-neon-ref.h"
79#include "compute-ref-data.h"
80
81/* Expected results.  */
82VECT_VAR_DECL(expected,int,8,8) [] = { 0xf6, 0xf7, 0xf8, 0xf9,
83				       0xfa, 0xfb, 0xfc, 0xfd };
84/* and as many others as necessary.  */
85
86#define TEST_MSG "VMYINTRINSIC"
87void exec_myintrinsic (void)
88{
89  /* my test: v4=vmyintrinsic(v1,v2,v3), then store the result.  */
90#define TEST_VMYINTR(Q, T1, T2, W, N)					\
91  VECT_VAR(vector_res, T1, W, N) =					\
92    vmyintr##Q##_##T2##W(VECT_VAR(vector1, T1, W, N),			\
93			 VECT_VAR(vector2, T1, W, N),			\
94			 VECT_VAR(vector3, T1, W, N));			\
95  vst1##Q##_##T2##W(VECT_VAR(result, T1, W, N), VECT_VAR(vector_res, T1, W, N))
96
97#define DECL_VMYINTR_VAR(VAR)			\
98  DECL_VARIABLE(VAR, int, 8, 8);
99/* And as many others as necessary.  */
100
101  DECL_VMYINTR_VAR(vector1);
102  DECL_VMYINTR_VAR(vector2);
103  DECL_VMYINTR_VAR(vector3);
104  DECL_VMYINTR_VAR(vector_res);
105
106  clean_results ();
107
108  /* Initialize input "vector1" from "buffer".  */
109  VLOAD(vector1, buffer, , int, s, 8, 8);
110/* And as many others as necessary.  */
111
112  /* Choose init value arbitrarily.  */
113  VDUP(vector2, , int, s, 8, 8, 1);
114/* And as many others as necessary.  */
115
116  /* Choose init value arbitrarily.  */
117  VDUP(vector3, , int, s, 8, 8, -5);
118/* And as many others as necessary.  */
119
120  /* Execute the tests.  */
121  TEST_VMYINTR(, int, s, 8, 8);
122/* And as many others as necessary.  */
123
124  check_results (TEST_MSG, "");
125}
126
127int main (void)
128{
129  exec_vmyintrinsic ();
130  return 0;
131}
132=================================================================
133