| /* |
| * 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; |
| } |