xref: /openbmc/qemu/tests/tcg/s390x/ex-relative-long.c (revision 4c6f44644d08f6f712474288d61deba601421988)
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