tests/tcg/s390x: Test ADD LOGICAL WITH CARRY
Add a test that tries different combinations of ADD LOGICAL WITH CARRY instructions. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-ID: <20231106093605.1349201-6-iii@linux.ibm.com> Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
		
							parent
							
								
									ebc14107f1
								
							
						
					
					
						commit
						d7e61d6b39
					
				| @ -43,6 +43,7 @@ TESTS+=cgebra | |||||||
| TESTS+=clgebr | TESTS+=clgebr | ||||||
| TESTS+=clc | TESTS+=clc | ||||||
| TESTS+=laalg | TESTS+=laalg | ||||||
|  | TESTS+=add-logical-with-carry | ||||||
| 
 | 
 | ||||||
| cdsg: CFLAGS+=-pthread | cdsg: CFLAGS+=-pthread | ||||||
| cdsg: LDFLAGS+=-pthread | cdsg: LDFLAGS+=-pthread | ||||||
|  | |||||||
							
								
								
									
										156
									
								
								tests/tcg/s390x/add-logical-with-carry.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								tests/tcg/s390x/add-logical-with-carry.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,156 @@ | |||||||
|  | /*
 | ||||||
|  |  * Test ADD LOGICAL WITH CARRY instructions. | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  */ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | 
 | ||||||
|  | static const struct test { | ||||||
|  |     const char *name; | ||||||
|  |     unsigned long values[3]; | ||||||
|  |     unsigned long exp_sum; | ||||||
|  |     int exp_cc; | ||||||
|  | } tests[] = { | ||||||
|  |     /*
 | ||||||
|  |      * Each test starts with CC 0 and executes two chained ADD LOGICAL WITH | ||||||
|  |      * CARRY instructions on three input values. The values must be compatible | ||||||
|  |      * with both 32- and 64-bit test functions. | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     /* NAME       VALUES       EXP_SUM EXP_CC */ | ||||||
|  |     { "cc0->cc0", {0, 0, 0},   0,      0, }, | ||||||
|  |     { "cc0->cc1", {0, 0, 42},  42,     1, }, | ||||||
|  |     /* cc0->cc2 is not possible */ | ||||||
|  |     /* cc0->cc3 is not possible */ | ||||||
|  |     /* cc1->cc0 is not possible */ | ||||||
|  |     { "cc1->cc1", {-3, 1, 1},  -1,     1, }, | ||||||
|  |     { "cc1->cc2", {-3, 1, 2},  0,      2, }, | ||||||
|  |     { "cc1->cc3", {-3, 1, -1}, -3,     3, }, | ||||||
|  |     /* cc2->cc0 is not possible */ | ||||||
|  |     { "cc2->cc1", {-1, 1, 1},  2,      1, }, | ||||||
|  |     { "cc2->cc2", {-1, 1, -1}, 0,      2, }, | ||||||
|  |     /* cc2->cc3 is not possible */ | ||||||
|  |     /* cc3->cc0 is not possible */ | ||||||
|  |     { "cc3->cc1", {-1, 2, 1},  3,      1, }, | ||||||
|  |     { "cc3->cc2", {-1, 2, -2}, 0,      2, }, | ||||||
|  |     { "cc3->cc3", {-1, 2, -1}, 1,      3, }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Test ALCR (register variant) followed by ALC (memory variant). */ | ||||||
|  | static unsigned long test32rm(unsigned long a, unsigned long b, | ||||||
|  |                               unsigned long c, int *cc) | ||||||
|  | { | ||||||
|  |     unsigned int a32 = a, b32 = b, c32 = c; | ||||||
|  | 
 | ||||||
|  |     asm("xr %[cc],%[cc]\n" | ||||||
|  |         "alcr %[a],%[b]\n" | ||||||
|  |         "alc %[a],%[c]\n" | ||||||
|  |         "ipm %[cc]" | ||||||
|  |         : [a] "+&r" (a32), [cc] "+&r" (*cc) | ||||||
|  |         : [b] "r" (b32), [c] "T" (c32) | ||||||
|  |         : "cc"); | ||||||
|  |     *cc >>= 28; | ||||||
|  | 
 | ||||||
|  |     return (int)a32; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Test ALC (memory variant) followed by ALCR (register variant). */ | ||||||
|  | static unsigned long test32mr(unsigned long a, unsigned long b, | ||||||
|  |                               unsigned long c, int *cc) | ||||||
|  | { | ||||||
|  |     unsigned int a32 = a, b32 = b, c32 = c; | ||||||
|  | 
 | ||||||
|  |     asm("xr %[cc],%[cc]\n" | ||||||
|  |         "alc %[a],%[b]\n" | ||||||
|  |         "alcr %[c],%[a]\n" | ||||||
|  |         "ipm %[cc]" | ||||||
|  |         : [a] "+&r" (a32), [c] "+&r" (c32), [cc] "+&r" (*cc) | ||||||
|  |         : [b] "T" (b32) | ||||||
|  |         : "cc"); | ||||||
|  |     *cc >>= 28; | ||||||
|  | 
 | ||||||
|  |     return (int)c32; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Test ALCGR (register variant) followed by ALCG (memory variant). */ | ||||||
|  | static unsigned long test64rm(unsigned long a, unsigned long b, | ||||||
|  |                               unsigned long c, int *cc) | ||||||
|  | { | ||||||
|  |     asm("xr %[cc],%[cc]\n" | ||||||
|  |         "alcgr %[a],%[b]\n" | ||||||
|  |         "alcg %[a],%[c]\n" | ||||||
|  |         "ipm %[cc]" | ||||||
|  |         : [a] "+&r" (a), [cc] "+&r" (*cc) | ||||||
|  |         : [b] "r" (b), [c] "T" (c) | ||||||
|  |         : "cc"); | ||||||
|  |     *cc >>= 28; | ||||||
|  |     return a; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Test ALCG (memory variant) followed by ALCGR (register variant). */ | ||||||
|  | static unsigned long test64mr(unsigned long a, unsigned long b, | ||||||
|  |                               unsigned long c, int *cc) | ||||||
|  | { | ||||||
|  |     asm("xr %[cc],%[cc]\n" | ||||||
|  |         "alcg %[a],%[b]\n" | ||||||
|  |         "alcgr %[c],%[a]\n" | ||||||
|  |         "ipm %[cc]" | ||||||
|  |         : [a] "+&r" (a), [c] "+&r" (c), [cc] "+&r" (*cc) | ||||||
|  |         : [b] "T" (b) | ||||||
|  |         : "cc"); | ||||||
|  |     *cc >>= 28; | ||||||
|  |     return c; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct test_func { | ||||||
|  |     const char *name; | ||||||
|  |     unsigned long (*ptr)(unsigned long, unsigned long, unsigned long, int *); | ||||||
|  | } test_funcs[] = { | ||||||
|  |     { "test32rm", test32rm }, | ||||||
|  |     { "test32mr", test32mr }, | ||||||
|  |     { "test64rm", test64rm }, | ||||||
|  |     { "test64mr", test64mr }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct test_perm { | ||||||
|  |     const char *name; | ||||||
|  |     size_t a_idx, b_idx, c_idx; | ||||||
|  | } test_perms[] = { | ||||||
|  |     { "a, b, c", 0, 1, 2 }, | ||||||
|  |     { "b, a, c", 1, 0, 2 }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | int main(void) | ||||||
|  | { | ||||||
|  |     unsigned long a, b, c, sum; | ||||||
|  |     int result = EXIT_SUCCESS; | ||||||
|  |     const struct test_func *f; | ||||||
|  |     const struct test_perm *p; | ||||||
|  |     size_t i, j, k; | ||||||
|  |     const struct test *t; | ||||||
|  |     int cc; | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { | ||||||
|  |         t = &tests[i]; | ||||||
|  |         for (j = 0; j < sizeof(test_funcs) / sizeof(test_funcs[0]); j++) { | ||||||
|  |             f = &test_funcs[j]; | ||||||
|  |             for (k = 0; k < sizeof(test_perms) / sizeof(test_perms[0]); k++) { | ||||||
|  |                 p = &test_perms[k]; | ||||||
|  |                 a = t->values[p->a_idx]; | ||||||
|  |                 b = t->values[p->b_idx]; | ||||||
|  |                 c = t->values[p->c_idx]; | ||||||
|  |                 sum = f->ptr(a, b, c, &cc); | ||||||
|  |                 if (sum != t->exp_sum || cc != t->exp_cc) { | ||||||
|  |                     fprintf(stderr, | ||||||
|  |                             "[  FAILED  ] %s %s(0x%lx, 0x%lx, 0x%lx) returned 0x%lx cc %d, expected 0x%lx cc %d\n", | ||||||
|  |                             t->name, f->name, a, b, c, sum, cc, | ||||||
|  |                             t->exp_sum, t->exp_cc); | ||||||
|  |                     result = EXIT_FAILURE; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Ilya Leoshkevich
						Ilya Leoshkevich