1 #ifndef S390_TEST_VECTOR_H
2 #define S390_TEST_VECTOR_H
3
4 #include "stdbool.h"
5 #include "stdint.h"
6 #include "stdio.h"
7 #include "string.h"
8
9 /* How many times should every test be executed? */
10 #ifndef S390_TEST_COUNT
11 #define S390_TEST_COUNT 10
12 #endif
13
14 /* Test the instruction exactly one time. */
15 #define test_once(insn) test_##insn ()
16
17 /* Test the instruction exactly S390_TEST_COUNT times.
18 "..." arguments specifies code which must be executed after each tests
19 */
20 #define test(insn, ...) \
21 for(iteration = 0; iteration < S390_TEST_COUNT; iteration++) \
22 { test_once(insn); \
23 __VA_ARGS__; \
24 }
25
26 #define test_with_selective_printing(insn, info) \
27 for(iteration = 0; iteration < S390_TEST_COUNT; iteration++) \
28 { test_ ## insn ## _selective(info); }
29
30 #ifdef __GNUC__
31 /* GCC complains about __int128 with -pedantic */
32 /* Hope that we will have int128_t in C standard someday. */
33 #pragma GCC diagnostic ignored "-Wpedantic"
34 #endif
35
36 typedef union {
37 uint8_t u8[16];
38 int8_t s8[16];
39
40 uint16_t u16[8];
41 int16_t s16[8];
42
43 uint32_t u32[4];
44 int32_t s32[4];
45 float f32[4];
46
47 uint64_t u64[2];
48 int64_t s64[2];
49 double f64[2];
50
51 unsigned __int128 u128[1];
52 __int128 s128[1];
53 } V128;
54
55 typedef enum {
56 V128_NO_PRINTING = 0,
57 V128_V_RES_AS_INT = 1 << 0,
58 V128_V_ARG1_AS_INT = 1 << 1,
59 V128_V_ARG2_AS_INT = 1 << 2,
60 V128_V_ARG3_AS_INT = 1 << 3,
61 V128_V_RES_AS_FLOAT64 = 1 << 4,
62 V128_V_ARG1_AS_FLOAT64 = 1 << 5,
63 V128_V_ARG2_AS_FLOAT64 = 1 << 6,
64 V128_V_ARG3_AS_FLOAT64 = 1 << 7,
65 V128_V_RES_AS_FLOAT32 = 1 << 8,
66 V128_V_ARG1_AS_FLOAT32 = 1 << 9,
67 V128_V_ARG2_AS_FLOAT32 = 1 << 10,
68 V128_V_ARG3_AS_FLOAT32 = 1 << 11,
69 V128_R_RES = 1 << 12,
70 V128_R_ARG1 = 1 << 13,
71 V128_R_ARG2 = 1 << 14,
72 V128_R_ARG3 = 1 << 15,
73 V128_V_RES_EVEN_ONLY = 1 << 16,
74 V128_V_RES_ZERO_ONLY = 1 << 17,
75 V128_PRINT_ALL = (V128_V_RES_AS_INT |
76 V128_V_ARG1_AS_INT |
77 V128_V_ARG2_AS_INT |
78 V128_V_ARG3_AS_INT |
79 V128_R_RES |
80 V128_R_ARG1 |
81 V128_R_ARG2 |
82 V128_R_ARG3),
83 } s390x_test_usageInfo;
84
print_hex(const V128 value)85 void print_hex(const V128 value) {
86 printf("%016lx | %016lx\n", value.u64[0], value.u64[1]);
87 }
88
print_f32(const V128 value,int even_only,int zero_only)89 void print_f32(const V128 value, int even_only, int zero_only) {
90 if (zero_only)
91 printf("%a | -- | -- | --\n", value.f32[0]);
92 else if (even_only)
93 printf("%a | -- | %a | --\n", value.f32[0], value.f32[2]);
94 else
95 printf("%a | %a | %a | %a\n",
96 value.f32[0], value.f32[1], value.f32[2], value.f32[3]);
97 }
98
print_f64(const V128 value,int zero_only)99 void print_f64(const V128 value, int zero_only) {
100 if (zero_only)
101 printf("%a | --\n", value.f64[0]);
102 else
103 printf("%a | %a\n", value.f64[0], value.f64[1]);
104 }
105
print_uint64_t(const uint64_t value)106 void print_uint64_t(const uint64_t value) {
107 printf("%016lx\n", value);
108 }
109
random_element(void)110 uint8_t random_element ( void )
111 {
112 static uint32_t seed = 80021;
113 seed = 1103515245 * seed + 12345;
114 return (seed >> 17) & 0xFF;
115 }
116
random_V128(V128 * block)117 void random_V128 (V128 *block)
118 {
119 size_t i;
120 for(i = 0; i < 16; i++)
121 {
122 block->u8[i] = random_element();
123 }
124 }
125
random_uint64_t()126 uint64_t random_uint64_t()
127 {
128 uint64_t result = 0ULL;
129 uint8_t *ptr = (uint8_t *) &result;
130 size_t i;
131 for(i = 0; i < 8; i++)
132 {
133 ptr[i] = random_element();
134 }
135
136 return result;
137 }
138
139 /* Memory pool with some random data. Used for some instruction which need
140 an address to some memory chunk.
141 Pool should be large enough for all insn that use it.
142 (64 bytes and aligning are needed by VLBB insn)
143
144 Content of this pool must be updated every iteration but not from test to test.
145 */
146 uint8_t random_memory_pool[64] __attribute__ ((aligned (64)));
randomize_memory_pool()147 void randomize_memory_pool()
148 {
149 size_t i;
150 for(i = 0; i < sizeof(random_memory_pool) / sizeof(random_memory_pool[0]); i++)
151 {
152 random_memory_pool[i] = random_element();
153 }
154 }
155
156 /* Define a test for input. Takes up theese arguments:
157 insn -- instruction name
158 asm_string -- line (or multiple lines) with asm mnemonics for instruction
159
160 The folowing registers layout expected:
161 ("r" for register form and m for memory form)
162 v1 -- vector arg1
163 v2 -- vector arg2
164 v3 -- vector arg3
165 v5 -- vector result
166 [{r,m}_arg1] -- integer arg1
167 [{r,m}_arg2] -- integer arg2
168 [{r,m}_arg3] -- integer arg3
169 [{r,m}_result] -- integer result
170 [{r,m}_memory_pool] -- address of random memory pool. Usefull for some instructions
171
172 */
173 #define s390_test_generate(insn, asm_string) \
174 static void test_##insn##_selective(const s390x_test_usageInfo info) \
175 { \
176 V128 v_result = { .u64 = {0ULL, 0ULL} }; \
177 V128 v_arg1; \
178 V128 v_arg2; \
179 V128 v_arg3; \
180 uint64_t r_arg1 = random_uint64_t(); \
181 uint64_t r_arg2 = random_uint64_t(); \
182 uint64_t r_arg3 = random_uint64_t(); \
183 uint64_t r_result = 0ULL; \
184 \
185 random_V128(&v_arg1); \
186 random_V128(&v_arg2); \
187 random_V128(&v_arg3); \
188 \
189 __asm__ volatile( \
190 "vl %%v1, %[v_arg1]\n" \
191 "vl %%v2, %[v_arg2]\n" \
192 "vl %%v3, %[v_arg3]\n" \
193 "vone %%v5\n" \
194 "srnmb 1(0)\n " \
195 asm_string "\n"\
196 "vst %%v5, %[v_result]\n" \
197 "vst %%v1, %[v_arg1]\n" \
198 "vst %%v2, %[v_arg2]\n" \
199 "vst %%v3, %[v_arg3]\n" \
200 : [v_result] "=m" (v_result), \
201 [m_result] "=m" (r_result), \
202 [r_result] "+d" (r_result), \
203 [r_arg1] "+d" (r_arg1), \
204 [r_arg2] "+d" (r_arg2), \
205 [r_arg3] "+d" (r_arg3) \
206 : [v_arg1] "m" (v_arg1), \
207 [v_arg2] "m" (v_arg2), \
208 [v_arg3] "m" (v_arg3), \
209 [m_arg1] "m" (r_arg1), \
210 [m_arg2] "m" (r_arg2), \
211 [m_arg3] "m" (r_arg3), \
212 [r_memory_pool] "r" (random_memory_pool), \
213 [m_memory_pool] "m" (random_memory_pool) \
214 : "memory", "cc", \
215 "r1", "r2", "r3", "r5", \
216 "v1", "v2", "v3", "v5"); \
217 \
218 printf("insn %s:\n", #insn); \
219 if (info & V128_V_ARG1_AS_INT) \
220 {printf(" v_arg1 = "); print_hex(v_arg1);} \
221 if (info & V128_V_ARG2_AS_INT) \
222 {printf(" v_arg2 = "); print_hex(v_arg2);} \
223 if (info & V128_V_ARG3_AS_INT) \
224 {printf(" v_arg3 = "); print_hex(v_arg3);} \
225 if (info & V128_V_RES_AS_INT) \
226 {printf(" v_result = "); print_hex(v_result);} \
227 \
228 if (info & V128_V_ARG1_AS_FLOAT64) \
229 {printf(" v_arg1 = "); print_f64(v_arg1, 0);} \
230 if (info & V128_V_ARG2_AS_FLOAT64) \
231 {printf(" v_arg2 = "); print_f64(v_arg2, 0);} \
232 if (info & V128_V_ARG3_AS_FLOAT64) \
233 {printf(" v_arg3 = "); print_f64(v_arg3, 0);} \
234 if (info & V128_V_RES_AS_FLOAT64) { \
235 printf(" v_result = "); \
236 print_f64(v_result, info & V128_V_RES_ZERO_ONLY); \
237 } \
238 \
239 if (info & V128_V_ARG1_AS_FLOAT32) \
240 {printf(" v_arg1 = "); print_f32(v_arg1, 0, 0);} \
241 if (info & V128_V_ARG2_AS_FLOAT32) \
242 {printf(" v_arg2 = "); print_f32(v_arg2, 0, 0);} \
243 if (info & V128_V_ARG3_AS_FLOAT32) \
244 {printf(" v_arg3 = "); print_f32(v_arg3, 0, 0);} \
245 if (info & V128_V_RES_AS_FLOAT32) { \
246 printf(" v_result = "); \
247 print_f32(v_result, info & V128_V_RES_EVEN_ONLY, \
248 info & V128_V_RES_ZERO_ONLY); \
249 } \
250 if (info & V128_R_ARG1) \
251 {printf(" r_arg1 = "); print_uint64_t(r_arg1);} \
252 if (info & V128_R_ARG2) \
253 {printf(" r_arg2 = "); print_uint64_t(r_arg2);} \
254 if (info & V128_R_ARG3) \
255 {printf(" r_arg3 = "); print_uint64_t(r_arg3);} \
256 if (info & V128_R_RES) \
257 {printf(" r_result = "); print_uint64_t(r_result);} \
258 } \
259 __attribute__((unused)) static void test_##insn() \
260 { \
261 test_##insn##_selective (V128_PRINT_ALL); \
262 }
263
264 /* Stores CC to %[r_result].
265 Usefull when testing instructions which modify condition code.
266 */
267 #define S390_TEST_PUT_CC_TO_RESULT "ipm %[r_result] \n srl %[r_result], 28 \n"
268
269 #endif
270