bfa72590df
Add a small test to prevent regressions. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Acked-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230426235813.198183-3-iii@linux.ibm.com> Signed-off-by: Thomas Huth <thuth@redhat.com>
159 lines
8.5 KiB
C
159 lines
8.5 KiB
C
/* 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;
|
|
}
|