xref: /qemu/tests/tcg/s390x/ex-relative-long.c (revision 86d063fa)
1 /* Check EXECUTE with relative long instructions as targets. */
2 #include <stdlib.h>
3 #include <stdio.h>
4 
5 struct test {
6     const char *name;
7     long (*func)(long reg, long *cc);
8     long exp_reg;
9     long exp_mem;
10     long exp_cc;
11 };
12 
13 /*
14  * Each test sets the MEM_IDXth element of the mem array to MEM and uses a
15  * single relative long instruction on it. The other elements remain zero.
16  * This is in order to prevent stumbling upon MEM in random memory in case
17  * there is an off-by-a-small-value bug.
18  *
19  * Note that while gcc supports the ZL constraint for relative long operands,
20  * clang doesn't, so the assembly code accesses mem[MEM_IDX] using MEM_ASM.
21  */
22 static long mem[0x1000];
23 #define MEM_IDX 0x800
24 #define MEM_ASM "mem+0x800*8"
25 
26 /* Initial %r2 value. */
27 #define REG 0x1234567887654321
28 
29 /* Initial mem[MEM_IDX] value. */
30 #define MEM 0xfedcba9889abcdef
31 
32 /* Initial cc value. */
33 #define CC 0
34 
35 /* Relative long instructions and their expected effects. */
36 #define FOR_EACH_INSN(F)                                                       \
37     F(cgfrl,  REG,                 MEM,                2)                      \
38     F(cghrl,  REG,                 MEM,                2)                      \
39     F(cgrl,   REG,                 MEM,                2)                      \
40     F(chrl,   REG,                 MEM,                1)                      \
41     F(clgfrl, REG,                 MEM,                2)                      \
42     F(clghrl, REG,                 MEM,                2)                      \
43     F(clgrl,  REG,                 MEM,                1)                      \
44     F(clhrl,  REG,                 MEM,                2)                      \
45     F(clrl,   REG,                 MEM,                1)                      \
46     F(crl,    REG,                 MEM,                1)                      \
47     F(larl,   (long)&mem[MEM_IDX], MEM,                CC)                     \
48     F(lgfrl,  0xfffffffffedcba98,  MEM,                CC)                     \
49     F(lghrl,  0xfffffffffffffedc,  MEM,                CC)                     \
50     F(lgrl,   MEM,                 MEM,                CC)                     \
51     F(lhrl,   0x12345678fffffedc,  MEM,                CC)                     \
52     F(llghrl, 0x000000000000fedc,  MEM,                CC)                     \
53     F(llhrl,  0x123456780000fedc,  MEM,                CC)                     \
54     F(lrl,    0x12345678fedcba98,  MEM,                CC)                     \
55     F(stgrl,  REG,                 REG,                CC)                     \
56     F(sthrl,  REG,                 0x4321ba9889abcdef, CC)                     \
57     F(strl,   REG,                 0x8765432189abcdef, CC)
58 
59 /* Test functions. */
60 #define DEFINE_EX_TEST(insn, exp_reg, exp_mem, exp_cc)                         \
61     static long test_ex_ ## insn(long reg, long *cc)                           \
62     {                                                                          \
63         register long r2 asm("r2");                                            \
64         char mask = 0x20;  /* make target use %r2 */                           \
65         long pm, target;                                                       \
66                                                                                \
67         r2 = reg;                                                              \
68         asm("larl %[target],0f\n"                                              \
69             "cr %%r0,%%r0\n"  /* initial cc */                                 \
70             "ex %[mask],0(%[target])\n"                                        \
71             "jg 1f\n"                                                          \
72             "0: " #insn " %%r0," MEM_ASM "\n"                                  \
73             "1: ipm %[pm]\n"                                                   \
74             : [target] "=&a" (target), [r2] "+r" (r2), [pm] "=r" (pm)          \
75             : [mask] "a" (mask)                                                \
76             : "cc", "memory");                                                 \
77         reg = r2;                                                              \
78         *cc = (pm >> 28) & 3;                                                  \
79                                                                                \
80         return reg;                                                            \
81     }
82 
83 #define DEFINE_EXRL_TEST(insn, exp_reg, exp_mem, exp_cc)                       \
84     static long test_exrl_ ## insn(long reg, long *cc)                         \
85     {                                                                          \
86         register long r2 asm("r2");                                            \
87         char mask = 0x20;  /* make target use %r2 */                           \
88         long pm;                                                               \
89                                                                                \
90         r2 = reg;                                                              \
91         asm("cr %%r0,%%r0\n"  /* initial cc */                                 \
92             "exrl %[mask],0f\n"                                                \
93             "jg 1f\n"                                                          \
94             "0: " #insn " %%r0," MEM_ASM "\n"                                  \
95             "1: ipm %[pm]\n"                                                   \
96             : [r2] "+r" (r2), [pm] "=r" (pm)                                   \
97             : [mask] "a" (mask)                                                \
98             : "cc", "memory");                                                 \
99         reg = r2;                                                              \
100         *cc = (pm >> 28) & 3;                                                  \
101                                                                                \
102         return reg;                                                            \
103     }
104 
105 FOR_EACH_INSN(DEFINE_EX_TEST)
106 FOR_EACH_INSN(DEFINE_EXRL_TEST)
107 
108 /* Test definitions. */
109 #define REGISTER_EX_EXRL_TEST(ex_insn, insn, _exp_reg, _exp_mem, _exp_cc)      \
110     {                                                                          \
111         .name = #ex_insn " " #insn,                                            \
112         .func = test_ ## ex_insn ## _ ## insn,                                 \
113         .exp_reg = (_exp_reg),                                                 \
114         .exp_mem = (_exp_mem),                                                 \
115         .exp_cc = (_exp_cc),                                                   \
116     },
117 
118 #define REGISTER_EX_TEST(insn, exp_reg, exp_mem, exp_cc)                       \
119     REGISTER_EX_EXRL_TEST(ex, insn, exp_reg, exp_mem, exp_cc)
120 
121 #define REGISTER_EXRL_TEST(insn, exp_reg, exp_mem, exp_cc)                     \
122     REGISTER_EX_EXRL_TEST(exrl, insn, exp_reg, exp_mem, exp_cc)
123 
124 static const struct test tests[] = {
125     FOR_EACH_INSN(REGISTER_EX_TEST)
126     FOR_EACH_INSN(REGISTER_EXRL_TEST)
127 };
128 
129 /* Loop over all tests and run them. */
130 int main(void)
131 {
132     const struct test *test;
133     int ret = EXIT_SUCCESS;
134     long reg, cc;
135     size_t i;
136 
137     for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
138         test = &tests[i];
139         mem[MEM_IDX] = MEM;
140         cc = -1;
141         reg = test->func(REG, &cc);
142 #define ASSERT_EQ(expected, actual) do {                                       \
143     if (expected != actual) {                                                  \
144         fprintf(stderr, "%s: " #expected " (0x%lx) != " #actual " (0x%lx)\n",  \
145                 test->name, expected, actual);                                 \
146         ret = EXIT_FAILURE;                                                    \
147     }                                                                          \
148 } while (0)
149         ASSERT_EQ(test->exp_reg, reg);
150         ASSERT_EQ(test->exp_mem, mem[MEM_IDX]);
151         ASSERT_EQ(test->exp_cc, cc);
152 #undef ASSERT_EQ
153     }
154 
155     return ret;
156 }
157