1 /*
2  * Test ADD LOGICAL WITH CARRY instructions.
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 #include <stdio.h>
7 #include <stdlib.h>
8 
9 static const struct test {
10     const char *name;
11     unsigned long values[3];
12     unsigned long exp_sum;
13     int exp_cc;
14 } tests[] = {
15     /*
16      * Each test starts with CC 0 and executes two chained ADD LOGICAL WITH
17      * CARRY instructions on three input values. The values must be compatible
18      * with both 32- and 64-bit test functions.
19      */
20 
21     /* NAME       VALUES       EXP_SUM EXP_CC */
22     { "cc0->cc0", {0, 0, 0},   0,      0, },
23     { "cc0->cc1", {0, 0, 42},  42,     1, },
24     /* cc0->cc2 is not possible */
25     /* cc0->cc3 is not possible */
26     /* cc1->cc0 is not possible */
27     { "cc1->cc1", {-3, 1, 1},  -1,     1, },
28     { "cc1->cc2", {-3, 1, 2},  0,      2, },
29     { "cc1->cc3", {-3, 1, -1}, -3,     3, },
30     /* cc2->cc0 is not possible */
31     { "cc2->cc1", {-1, 1, 1},  2,      1, },
32     { "cc2->cc2", {-1, 1, -1}, 0,      2, },
33     /* cc2->cc3 is not possible */
34     /* cc3->cc0 is not possible */
35     { "cc3->cc1", {-1, 2, 1},  3,      1, },
36     { "cc3->cc2", {-1, 2, -2}, 0,      2, },
37     { "cc3->cc3", {-1, 2, -1}, 1,      3, },
38 };
39 
40 /* Test ALCR (register variant) followed by ALC (memory variant). */
test32rm(unsigned long a,unsigned long b,unsigned long c,int * cc)41 static unsigned long test32rm(unsigned long a, unsigned long b,
42                               unsigned long c, int *cc)
43 {
44     unsigned int a32 = a, b32 = b, c32 = c;
45 
46     asm("xr %[cc],%[cc]\n"
47         "alcr %[a],%[b]\n"
48         "alc %[a],%[c]\n"
49         "ipm %[cc]"
50         : [a] "+&r" (a32), [cc] "+&r" (*cc)
51         : [b] "r" (b32), [c] "T" (c32)
52         : "cc");
53     *cc >>= 28;
54 
55     return (int)a32;
56 }
57 
58 /* Test ALC (memory variant) followed by ALCR (register variant). */
test32mr(unsigned long a,unsigned long b,unsigned long c,int * cc)59 static unsigned long test32mr(unsigned long a, unsigned long b,
60                               unsigned long c, int *cc)
61 {
62     unsigned int a32 = a, b32 = b, c32 = c;
63 
64     asm("xr %[cc],%[cc]\n"
65         "alc %[a],%[b]\n"
66         "alcr %[c],%[a]\n"
67         "ipm %[cc]"
68         : [a] "+&r" (a32), [c] "+&r" (c32), [cc] "+&r" (*cc)
69         : [b] "T" (b32)
70         : "cc");
71     *cc >>= 28;
72 
73     return (int)c32;
74 }
75 
76 /* Test ALCGR (register variant) followed by ALCG (memory variant). */
test64rm(unsigned long a,unsigned long b,unsigned long c,int * cc)77 static unsigned long test64rm(unsigned long a, unsigned long b,
78                               unsigned long c, int *cc)
79 {
80     asm("xr %[cc],%[cc]\n"
81         "alcgr %[a],%[b]\n"
82         "alcg %[a],%[c]\n"
83         "ipm %[cc]"
84         : [a] "+&r" (a), [cc] "+&r" (*cc)
85         : [b] "r" (b), [c] "T" (c)
86         : "cc");
87     *cc >>= 28;
88     return a;
89 }
90 
91 /* Test ALCG (memory variant) followed by ALCGR (register variant). */
test64mr(unsigned long a,unsigned long b,unsigned long c,int * cc)92 static unsigned long test64mr(unsigned long a, unsigned long b,
93                               unsigned long c, int *cc)
94 {
95     asm("xr %[cc],%[cc]\n"
96         "alcg %[a],%[b]\n"
97         "alcgr %[c],%[a]\n"
98         "ipm %[cc]"
99         : [a] "+&r" (a), [c] "+&r" (c), [cc] "+&r" (*cc)
100         : [b] "T" (b)
101         : "cc");
102     *cc >>= 28;
103     return c;
104 }
105 
106 static const struct test_func {
107     const char *name;
108     unsigned long (*ptr)(unsigned long, unsigned long, unsigned long, int *);
109 } test_funcs[] = {
110     { "test32rm", test32rm },
111     { "test32mr", test32mr },
112     { "test64rm", test64rm },
113     { "test64mr", test64mr },
114 };
115 
116 static const struct test_perm {
117     const char *name;
118     size_t a_idx, b_idx, c_idx;
119 } test_perms[] = {
120     { "a, b, c", 0, 1, 2 },
121     { "b, a, c", 1, 0, 2 },
122 };
123 
main(void)124 int main(void)
125 {
126     unsigned long a, b, c, sum;
127     int result = EXIT_SUCCESS;
128     const struct test_func *f;
129     const struct test_perm *p;
130     size_t i, j, k;
131     const struct test *t;
132     int cc;
133 
134     for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
135         t = &tests[i];
136         for (j = 0; j < sizeof(test_funcs) / sizeof(test_funcs[0]); j++) {
137             f = &test_funcs[j];
138             for (k = 0; k < sizeof(test_perms) / sizeof(test_perms[0]); k++) {
139                 p = &test_perms[k];
140                 a = t->values[p->a_idx];
141                 b = t->values[p->b_idx];
142                 c = t->values[p->c_idx];
143                 sum = f->ptr(a, b, c, &cc);
144                 if (sum != t->exp_sum || cc != t->exp_cc) {
145                     fprintf(stderr,
146                             "[  FAILED  ] %s %s(0x%lx, 0x%lx, 0x%lx) returned 0x%lx cc %d, expected 0x%lx cc %d\n",
147                             t->name, f->name, a, b, c, sum, cc,
148                             t->exp_sum, t->exp_cc);
149                     result = EXIT_FAILURE;
150                 }
151             }
152         }
153     }
154 
155     return result;
156 }
157