tests/tcg/s390x: Test EXECUTE of relative branches
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>
This commit is contained in:
parent
e8ecdfeb30
commit
bfa72590df
@ -34,6 +34,7 @@ TESTS+=cdsg
|
||||
TESTS+=chrl
|
||||
TESTS+=rxsbg
|
||||
TESTS+=ex-relative-long
|
||||
TESTS+=ex-branch
|
||||
|
||||
cdsg: CFLAGS+=-pthread
|
||||
cdsg: LDFLAGS+=-pthread
|
||||
|
158
tests/tcg/s390x/ex-branch.c
Normal file
158
tests/tcg/s390x/ex-branch.c
Normal file
@ -0,0 +1,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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user