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. */
main(void)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