1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
/* Check EXECUTE with relative branch instructions as targets. */
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct test {
const char *name;
void (*func)(long *link, long *magic);
long exp_link;
};
/* Branch instructions and their expected effects. */
#define LINK_64(test) ((long)test ## _exp_link)
#define LINK_NONE(test) -1L
#define FOR_EACH_INSN(F) \
F(bras, "%[link]", LINK_64) \
F(brasl, "%[link]", LINK_64) \
F(brc, "0x8", LINK_NONE) \
F(brcl, "0x8", LINK_NONE) \
F(brct, "%%r0", LINK_NONE) \
F(brctg, "%%r0", LINK_NONE) \
F(brxh, "%%r2,%%r0", LINK_NONE) \
F(brxhg, "%%r2,%%r0", LINK_NONE) \
F(brxle, "%%r0,%%r1", LINK_NONE) \
F(brxlg, "%%r0,%%r1", LINK_NONE) \
F(crj, "%%r0,%%r0,8", LINK_NONE) \
F(cgrj, "%%r0,%%r0,8", LINK_NONE) \
F(cij, "%%r0,0,8", LINK_NONE) \
F(cgij, "%%r0,0,8", LINK_NONE) \
F(clrj, "%%r0,%%r0,8", LINK_NONE) \
F(clgrj, "%%r0,%%r0,8", LINK_NONE) \
F(clij, "%%r0,0,8", LINK_NONE) \
F(clgij, "%%r0,0,8", LINK_NONE)
#define INIT_TEST \
"xgr %%r0,%%r0\n" /* %r0 = 0; %cc = 0 */ \
"lghi %%r1,1\n" /* %r1 = 1 */ \
"lghi %%r2,2\n" /* %r2 = 2 */
#define CLOBBERS_TEST "cc", "0", "1", "2"
#define DEFINE_TEST(insn, args, exp_link) \
extern char insn ## _exp_link[]; \
static void test_ ## insn(long *link, long *magic) \
{ \
asm(INIT_TEST \
#insn " " args ",0f\n" \
".globl " #insn "_exp_link\n" \
#insn "_exp_link:\n" \
".org . + 90\n" \
"0: lgfi %[magic],0x12345678\n" \
: [link] "+r" (*link) \
, [magic] "+r" (*magic) \
: : CLOBBERS_TEST); \
} \
extern char ex_ ## insn ## _exp_link[]; \
static void test_ex_ ## insn(long *link, long *magic) \
{ \
unsigned long target; \
\
asm(INIT_TEST \
"larl %[target],0f\n" \
"ex %%r0,0(%[target])\n" \
".globl ex_" #insn "_exp_link\n" \
"ex_" #insn "_exp_link:\n" \
".org . + 60\n" \
"0: " #insn " " args ",1f\n" \
".org . + 120\n" \
"1: lgfi %[magic],0x12345678\n" \
: [target] "=r" (target) \
, [link] "+r" (*link) \
, [magic] "+r" (*magic) \
: : CLOBBERS_TEST); \
} \
extern char exrl_ ## insn ## _exp_link[]; \
static void test_exrl_ ## insn(long *link, long *magic) \
{ \
asm(INIT_TEST \
"exrl %%r0,0f\n" \
".globl exrl_" #insn "_exp_link\n" \
"exrl_" #insn "_exp_link:\n" \
".org . + 60\n" \
"0: " #insn " " args ",1f\n" \
".org . + 120\n" \
"1: lgfi %[magic],0x12345678\n" \
: [link] "+r" (*link) \
, [magic] "+r" (*magic) \
: : CLOBBERS_TEST); \
}
/* Test functions. */
FOR_EACH_INSN(DEFINE_TEST)
/* Test definitions. */
#define REGISTER_TEST(insn, args, _exp_link) \
{ \
.name = #insn, \
.func = test_ ## insn, \
.exp_link = (_exp_link(insn)), \
}, \
{ \
.name = "ex " #insn, \
.func = test_ex_ ## insn, \
.exp_link = (_exp_link(ex_ ## insn)), \
}, \
{ \
.name = "exrl " #insn, \
.func = test_exrl_ ## insn, \
.exp_link = (_exp_link(exrl_ ## insn)), \
},
static const struct test tests[] = {
FOR_EACH_INSN(REGISTER_TEST)
};
int main(int argc, char **argv)
{
const struct test *test;
int ret = EXIT_SUCCESS;
bool verbose = false;
long link, magic;
size_t i;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
verbose = true;
}
}
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
test = &tests[i];
if (verbose) {
fprintf(stderr, "[ RUN ] %s\n", test->name);
}
link = -1;
magic = -1;
test->func(&link, &magic);
#define ASSERT_EQ(expected, actual) do { \
if (expected != actual) { \
fprintf(stderr, "%s: " #expected " (0x%lx) != " #actual " (0x%lx)\n", \
test->name, expected, actual); \
ret = EXIT_FAILURE; \
} \
} while (0)
ASSERT_EQ(test->exp_link, link);
ASSERT_EQ(0x12345678L, magic);
#undef ASSERT_EQ
}
if (verbose) {
fprintf(stderr, ret == EXIT_SUCCESS ? "[ PASSED ]\n" :
"[ FAILED ]\n");
}
return ret;
}
|