2 * s390x z13 instructions test
4 * Copyright (c) 2017 Vadim Barkov
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
27 /* Colors for output */
28 #ifndef S390_TESTS_NOCOLOR
29 # define RED "\033[31m"
30 # define GREEN "\033[32m"
31 # define RESET "\033[0m"
38 #define printPassed(insn) \
39 printf(RESET "%15s :\t " GREEN "PASSED" RESET "\n", #insn)
40 #define printFailed(insn) \
41 printf(RESET "%15s :\t " RED "FAILED" RESET "\n", #insn)
51 #define SMART_RETURN_R64(insn) \
52 bool result = after == expected; \
54 printf("[ERROR] %s:\n", #insn); \
55 printf("after: %lx\n", (uint64_t) after); \
56 printf("expected: %lx\n", (uint64_t) expected); \
60 /* Constant value for immediate instructions' tests */
61 #define IMMEDIATE_VALUE 0x0abc
62 #define IMMEDIATE_VALUE_STR "0x0abc"
64 /* Useful macros for testing many input values
65 and printing message after test execution
67 #define test_each(type, var, instruction) \
69 type##_foreach((var), test_##instruction((var))); \
72 #define test_range(var, from, to, instruction) \
75 __int_foreach(var, from, to, result &= (test_##instruction((var)))); \
77 printPassed(instruction); \
79 printFailed(instruction); \
82 #define __int_foreach(var, minValue, maxValue, statement) \
84 for (var = minValue; var < maxValue; var++) { \
91 #define uint32_foreach(var, statement) \
92 __int_foreach(var, 0, UINT32_MAX, statement)
93 #define int32_foreach(var, statement) \
94 __int_foreach(var, INT32_MIN, INT32_MAX, statement)
95 #define uint64_foreach(var, statement) \
96 __int_foreach(var, 0, UINT64_MAX, statement)
98 /* load and zero rightmost byte */
99 static bool test_lzrf(const uint32_t testedValue
)
102 uint32_t expected
= testedValue
& 0xffffff00;
104 __asm__
volatile("lzrf %0, %1" : "=d"(after
) : "T"(testedValue
) : );
105 SMART_RETURN_R64(lzrf
);
108 /* load and zero rightmost byte 64bit*/
109 static bool test_lzrg(const uint64_t testedValue
)
111 uint64_t after
= testedValue
;
112 uint64_t expected
= testedValue
& 0xffffffffffffff00UL
;
114 __asm__
volatile("lzrg %0, %1" : "=d"(after
) : "T"(testedValue
) : );
115 SMART_RETURN_R64(lzrg
);
118 /* load logical and zero rightmost byte */
119 static bool test_llzrgf(const uint32_t testedValue
)
122 uint32_t expected
= testedValue
& 0xffffff00;
124 __asm__
volatile("llzrgf %0, %1" : "=d"(after
) : "T"(testedValue
) : );
125 SMART_RETURN_R64(llzrgf
);
128 /* compare instructions */
129 #define __compare_r "cr"
130 #define __compare_m "c"
132 /* load high on condition */
133 #define declare_load_high_on_condition(TESTED_INSTRUCTION, CONDITION_SYMBOL, \
135 bool test_##TESTED_INSTRUCTION(const int32_t testedValue) \
138 const uint64_t valueBeforeTest = 0x6666666699999999UL; \
139 const uint64_t overrideValue = 0xeeeeeeeeeeeeeeeeUL; \
140 const int32_t invertedValue = testedValue ^ 0xffffffff; \
141 uint64_t after = valueBeforeTest; \
142 if (testedValue CONDITION_SYMBOL invertedValue) { \
143 expected = 0xeeeeeeee99999999UL; \
145 expected = valueBeforeTest; \
149 "cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION \
150 " %[after], %[overrideValue]\n" \
151 : [after] "+d"(after) \
152 : [testedValue] "d"(testedValue), \
153 [invertedValue] "d"(invertedValue), \
154 [overrideValue] #ARGUMENT_ASM_TYPE(overrideValue) \
157 SMART_RETURN_R64(TESTED_INSTRUCTION); \
160 declare_load_high_on_condition(locfhre
, ==, d
)
161 declare_load_high_on_condition(locfhrne
, !=, d
)
162 declare_load_high_on_condition(locfhrh
, >, d
)
163 declare_load_high_on_condition(locfhrl
, <, d
)
164 declare_load_high_on_condition(locfhe
, ==, Q
)
165 declare_load_high_on_condition(locfhne
, !=, Q
)
166 declare_load_high_on_condition(locfhh
, >, Q
)
167 declare_load_high_on_condition(locfhl
, <, Q
)
169 /* store high on condition */
170 #define declare_store_high_on_condition(TESTED_INSTRUCTION, CONDITION_SYMBOL, \
172 bool test_##TESTED_INSTRUCTION(const int32_t testedValue) \
175 const uint64_t valueBeforeTest = 0x6666666699999999UL; \
176 const uint64_t overrideValue = 0xeeeeeeeeeeeeeeeeUL; \
177 const int32_t invertedValue = testedValue ^ 0xffffffff; \
178 uint64_t after = valueBeforeTest; \
179 if (testedValue CONDITION_SYMBOL invertedValue) { \
180 expected = 0xeeeeeeee99999999UL; \
182 expected = valueBeforeTest; \
186 "cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION \
187 " %[overrideValue], %[after]\n" \
188 : [after] "+" #ARGUMENT_ASM_TYPE(after) \
189 : [testedValue] "d"(testedValue), \
190 [invertedValue] "d"(invertedValue), \
191 [overrideValue] "d"(overrideValue) \
194 SMART_RETURN_R64(TESTED_INSTRUCTION); \
197 declare_store_high_on_condition(stocfhe
, ==, Q
)
198 declare_store_high_on_condition(stocfhne
, !=, Q
)
199 declare_store_high_on_condition(stocfhh
, >, Q
)
200 declare_store_high_on_condition(stocfhl
, <, Q
)
202 #define __format_uint32_t "%x"
203 #define __format_uint64_t "%lx"
204 #define __halfword_valueBefore_uint32_t 0x66669999
205 #define __halfword_valueBefore_uint64_t 0x6666666699999999UL
206 /* load halfword immediate on condition */
207 #define declare_load_halfword_immediate_on_condition( \
208 TESTED_INSTRUCTION, ARGUMENT_TYPE, CONDITION_SYMBOL, ARGUMENT_ASM_TYPE) \
209 bool test_##TESTED_INSTRUCTION(const int32_t testedValue) \
211 ARGUMENT_TYPE expected; \
212 const ARGUMENT_TYPE valueBeforeTest = \
213 __halfword_valueBefore_##ARGUMENT_TYPE; \
214 const int32_t invertedValue = testedValue ^ 0xffffffff; \
215 ARGUMENT_TYPE after = valueBeforeTest; \
216 if (testedValue CONDITION_SYMBOL invertedValue) { \
217 expected = IMMEDIATE_VALUE; \
219 expected = valueBeforeTest; \
223 "cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION \
224 " %[after], " IMMEDIATE_VALUE_STR "\n" \
225 : [after] "+d"(after) \
226 : [testedValue] "d"(testedValue), \
227 [invertedValue] "d"(invertedValue) \
230 SMART_RETURN_R64(TESTED_INSTRUCTION); \
233 declare_load_halfword_immediate_on_condition(lochie
, uint32_t, ==, r
)
234 declare_load_halfword_immediate_on_condition(lochine
, uint32_t, !=, r
)
235 declare_load_halfword_immediate_on_condition(lochih
, uint32_t, >, r
)
236 declare_load_halfword_immediate_on_condition(lochil
, uint32_t, <, r
)
237 declare_load_halfword_immediate_on_condition(locghie
, uint64_t, ==, r
)
238 declare_load_halfword_immediate_on_condition(locghine
, uint64_t, !=, r
)
239 declare_load_halfword_immediate_on_condition(locghih
, uint64_t, >, r
)
240 declare_load_halfword_immediate_on_condition(locghil
, uint64_t, <, r
)
242 /* load halfword high immediate on condition */
243 #define declare_load_halfword_high_immediate_on_condition( \
244 TESTED_INSTRUCTION, CONDITION_SYMBOL, ARGUMENT_ASM_TYPE) \
245 bool test_##TESTED_INSTRUCTION(const int32_t testedValue) \
248 const uint64_t valueBeforeTest = __halfword_valueBefore_uint64_t; \
249 const int32_t invertedValue = testedValue ^ 0xffffffff; \
250 uint64_t after = valueBeforeTest; \
251 if (testedValue CONDITION_SYMBOL invertedValue) { \
252 expected = IMMEDIATE_VALUE; \
255 __halfword_valueBefore_uint64_t & 0x00000000ffffffffUL; \
257 expected = valueBeforeTest; \
261 "cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION \
262 " %[after], " IMMEDIATE_VALUE_STR "\n" \
263 : [after] "+d"(after) \
264 : [testedValue] "d"(testedValue), \
265 [invertedValue] "d"(invertedValue) \
268 SMART_RETURN_R64(TESTED_INSTRUCTION); \
271 declare_load_halfword_high_immediate_on_condition(lochhie
, ==, r
)
272 declare_load_halfword_high_immediate_on_condition(lochhine
, !=, r
)
273 declare_load_halfword_high_immediate_on_condition(lochhih
, >, r
)
274 declare_load_halfword_high_immediate_on_condition(lochhil
, <, r
)
276 static void test_all_locfh()
278 int32_t signed32bit
= 0;
280 test_each(int32
, signed32bit
, locfhe
);
281 test_each(int32
, signed32bit
, locfhne
);
282 test_each(int32
, signed32bit
, locfhh
);
283 test_each(int32
, signed32bit
, locfhl
);
285 test_each(int32
, signed32bit
, locfhre
);
286 test_each(int32
, signed32bit
, locfhrne
);
287 test_each(int32
, signed32bit
, locfhrh
);
288 test_each(int32
, signed32bit
, locfhrl
);
291 /* load count to block boundary */
292 #define declare_load_count_to_block_boundary(M_FIELD) \
293 bool test_lcbb##M_FIELD(const uint32_t testedValue) \
295 const size_t boundary = 64 * (1UL << (M_FIELD)); \
296 const uint32_t *testedPointer = \
297 (uint32_t *)(boundary - \
298 ((testedValue < boundary) ? testedValue : 0)); \
299 uint32_t after = 0; \
300 uint32_t expected = boundary - ((size_t)testedPointer % boundary); \
304 __asm__ volatile("lcbb %[after], %[testedPointer], " #M_FIELD \
306 : [after] "=d"(after) \
307 : [testedPointer] "R"(*testedPointer) \
310 SMART_RETURN_R64(lcbb##M_FIELD); \
313 declare_load_count_to_block_boundary(0)
314 declare_load_count_to_block_boundary(1)
315 declare_load_count_to_block_boundary(2)
316 declare_load_count_to_block_boundary(3)
317 declare_load_count_to_block_boundary(4)
318 declare_load_count_to_block_boundary(5)
319 declare_load_count_to_block_boundary(6)
321 static bool test_lcbb0_cc(const uint32_t testedValue
)
323 const size_t boundary
= 64;
324 const uint32_t *testedPointer
=
325 (uint32_t *)(boundary
-
326 ((testedValue
< boundary
) ? testedValue
: 0));
327 uint32_t expectedForLCBB
= boundary
- ((size_t)testedPointer
% boundary
);
330 uint32_t expected
= (expectedForLCBB
>= 16) ? 0 : 3;
331 __asm__
volatile("lcbb %[cc], %[testedPointer], 0 \n"
335 : [testedPointer
] "R"(*testedPointer
)
337 SMART_RETURN_R64(lcbb0_cc
);
341 static void test_all_lzr()
343 uint32_t unsigned32bit
= 0;
345 test_each(uint32
, unsigned32bit
, lzrf
);
346 test_each(uint32
, unsigned32bit
, lzrg
);
349 static void test_all_stocfh()
351 int32_t signed32bit
= 0;
353 test_each(int32
, signed32bit
, stocfhne
);
354 test_each(int32
, signed32bit
, stocfhe
);
355 test_each(int32
, signed32bit
, stocfhh
);
356 test_each(int32
, signed32bit
, stocfhl
);
359 static void test_all_lochi()
361 int32_t signed32bit
= 0;
363 test_each(int32
, signed32bit
, locghine
);
364 test_each(int32
, signed32bit
, locghine
);
365 test_each(int32
, signed32bit
, locghih
);
366 test_each(int32
, signed32bit
, locghil
);
368 test_each(int32
, signed32bit
, lochine
);
369 test_each(int32
, signed32bit
, lochie
);
370 test_each(int32
, signed32bit
, lochil
);
371 test_each(int32
, signed32bit
, lochih
);
374 static void test_all_lochhi()
376 int32_t signed32bit
= 0;
378 test_each(int32
, signed32bit
, lochhine
);
379 test_each(int32
, signed32bit
, lochhie
);
380 test_each(int32
, signed32bit
, lochhih
);
381 test_each(int32
, signed32bit
, lochhil
);
384 static void test_all_lcbb()
388 test_range(tested
, 0, 64, lcbb0
);
389 test_range(tested
, 0, 128, lcbb1
);
390 test_range(tested
, 0, 256, lcbb2
);
391 test_range(tested
, 0, 512, lcbb3
);
392 test_range(tested
, 0, 1024, lcbb4
);
393 test_range(tested
, 0, 2048, lcbb5
);
394 test_range(tested
, 0, 4096, lcbb6
);
395 test_range(tested
, 0, 64, lcbb0_cc
);
398 void test_long_all() {
399 uint64_t unsigned64bit
= 0;
407 test_each(uint64
, unsigned64bit
, llzrgf
);
410 #define SHORT_TESTS_UNSIGNED_FROM 0
411 #define SHORT_TESTS_SIGNED_FROM -0xffff
412 #define SHORT_TESTS_TO 0xffff
414 void test_short_all()
416 uint32_t unsigned32bit
= 0;
417 int32_t signed32bit
= 0;
418 uint64_t unsigned64bit
= 0;
420 test_range(unsigned32bit
, SHORT_TESTS_UNSIGNED_FROM
, SHORT_TESTS_TO
, lzrf
);
421 test_range(unsigned64bit
, SHORT_TESTS_UNSIGNED_FROM
, SHORT_TESTS_TO
, lzrg
);
422 test_range(unsigned64bit
, SHORT_TESTS_UNSIGNED_FROM
, SHORT_TESTS_TO
, llzrgf
);
425 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, stocfhne
);
426 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, stocfhe
);
427 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, stocfhh
);
428 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, stocfhl
);
431 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locfhe
);
432 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locfhne
);
433 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locfhh
);
434 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locfhl
);
437 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locfhre
);
438 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locfhrne
);
439 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locfhrh
);
440 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locfhrl
);
443 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, lochhine
);
444 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, lochhie
);
445 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, lochhih
);
446 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, lochhil
);
449 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, lochine
);
450 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, lochie
);
451 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, lochih
);
452 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, lochil
);
455 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locghine
);
456 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locghie
);
457 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locghih
);
458 test_range(signed32bit
, SHORT_TESTS_SIGNED_FROM
, SHORT_TESTS_TO
, locghil
);
460 test_all_lcbb(); /* These test is not long, so we can run it on all range */
463 int main(int argc
, char *argv
[])
465 bool shouldRunLongTests
= false;
467 /* --long option forces to test all possible values (it is very long)*/
469 if (strcmp(argv
[1], "--long") == 0)
470 shouldRunLongTests
= true;
472 printf("Tests started:\n");
473 if (shouldRunLongTests
)
478 printf("Tests ended.\n");