xref: /qemu/tests/tcg/multiarch/test-plugin-mem-access.c (revision a5dd9ee060b0ad65239889a62e93a33276055981)
1*354b5c19SPierrick Bouvier /*
2*354b5c19SPierrick Bouvier  * SPDX-License-Identifier: GPL-2.0-or-later
3*354b5c19SPierrick Bouvier  *
4*354b5c19SPierrick Bouvier  * Check if we detect all memory accesses expected using plugin API.
5*354b5c19SPierrick Bouvier  * Used in conjunction with ./check-plugin-mem-access.sh check script.
6*354b5c19SPierrick Bouvier  * Output of this program is the list of patterns expected in plugin output.
7*354b5c19SPierrick Bouvier  *
8*354b5c19SPierrick Bouvier  * 8,16,32 load/store are tested for all arch.
9*354b5c19SPierrick Bouvier  * 64,128 load/store are tested for aarch64/x64.
10*354b5c19SPierrick Bouvier  * atomic operations (8,16,32,64) are tested for x64 only.
11*354b5c19SPierrick Bouvier  */
12*354b5c19SPierrick Bouvier 
13*354b5c19SPierrick Bouvier #include <pthread.h>
14*354b5c19SPierrick Bouvier #include <stdint.h>
15*354b5c19SPierrick Bouvier #include <stdio.h>
16*354b5c19SPierrick Bouvier #include <stdlib.h>
17*354b5c19SPierrick Bouvier 
18*354b5c19SPierrick Bouvier #if defined(__x86_64__)
19*354b5c19SPierrick Bouvier #include <emmintrin.h>
20*354b5c19SPierrick Bouvier #elif defined(__aarch64__)
21*354b5c19SPierrick Bouvier #include <arm_neon.h>
22*354b5c19SPierrick Bouvier #endif /* __x86_64__ */
23*354b5c19SPierrick Bouvier 
24*354b5c19SPierrick Bouvier static void *data;
25*354b5c19SPierrick Bouvier 
26*354b5c19SPierrick Bouvier /* ,store_u8,.*,8,store,0xf1 */
27*354b5c19SPierrick Bouvier #define PRINT_EXPECTED(function, type, value, action)                 \
28*354b5c19SPierrick Bouvier do {                                                                  \
29*354b5c19SPierrick Bouvier     printf(",%s,.*,%d,%s,%s\n",                                       \
30*354b5c19SPierrick Bouvier            #function, (int) sizeof(type) * 8, action, value);         \
31*354b5c19SPierrick Bouvier }                                                                     \
32*354b5c19SPierrick Bouvier while (0)
33*354b5c19SPierrick Bouvier 
34*354b5c19SPierrick Bouvier #define DEFINE_STORE(name, type, value)                  \
35*354b5c19SPierrick Bouvier                                                          \
36*354b5c19SPierrick Bouvier static void print_expected_store_##name(void)            \
37*354b5c19SPierrick Bouvier {                                                        \
38*354b5c19SPierrick Bouvier     PRINT_EXPECTED(store_##name, type, #value, "store"); \
39*354b5c19SPierrick Bouvier }                                                        \
40*354b5c19SPierrick Bouvier                                                          \
41*354b5c19SPierrick Bouvier static void store_##name(void)                           \
42*354b5c19SPierrick Bouvier {                                                        \
43*354b5c19SPierrick Bouvier     *((type *)data) = value;                             \
44*354b5c19SPierrick Bouvier     print_expected_store_##name();                       \
45*354b5c19SPierrick Bouvier }
46*354b5c19SPierrick Bouvier 
47*354b5c19SPierrick Bouvier #define DEFINE_ATOMIC_OP(name, type, value)                    \
48*354b5c19SPierrick Bouvier                                                                \
49*354b5c19SPierrick Bouvier static void print_expected_atomic_op_##name(void)              \
50*354b5c19SPierrick Bouvier {                                                              \
51*354b5c19SPierrick Bouvier     PRINT_EXPECTED(atomic_op_##name, type, "0x0*42", "load");  \
52*354b5c19SPierrick Bouvier     PRINT_EXPECTED(atomic_op_##name, type, #value, "store");   \
53*354b5c19SPierrick Bouvier }                                                              \
54*354b5c19SPierrick Bouvier                                                                \
55*354b5c19SPierrick Bouvier static void atomic_op_##name(void)                             \
56*354b5c19SPierrick Bouvier {                                                              \
57*354b5c19SPierrick Bouvier     *((type *)data) = 0x42;                                    \
58*354b5c19SPierrick Bouvier     __sync_val_compare_and_swap((type *)data, 0x42, value);    \
59*354b5c19SPierrick Bouvier     print_expected_atomic_op_##name();                         \
60*354b5c19SPierrick Bouvier }
61*354b5c19SPierrick Bouvier 
62*354b5c19SPierrick Bouvier #define DEFINE_LOAD(name, type, value)                  \
63*354b5c19SPierrick Bouvier                                                         \
64*354b5c19SPierrick Bouvier static void print_expected_load_##name(void)            \
65*354b5c19SPierrick Bouvier {                                                       \
66*354b5c19SPierrick Bouvier     PRINT_EXPECTED(load_##name, type, #value, "load");  \
67*354b5c19SPierrick Bouvier }                                                       \
68*354b5c19SPierrick Bouvier                                                         \
69*354b5c19SPierrick Bouvier static void load_##name(void)                           \
70*354b5c19SPierrick Bouvier {                                                       \
71*354b5c19SPierrick Bouvier                                                         \
72*354b5c19SPierrick Bouvier     /* volatile forces load to be generated. */         \
73*354b5c19SPierrick Bouvier     volatile type src = *((type *) data);               \
74*354b5c19SPierrick Bouvier     volatile type dest = src;                           \
75*354b5c19SPierrick Bouvier     (void)src, (void)dest;                              \
76*354b5c19SPierrick Bouvier     print_expected_load_##name();                       \
77*354b5c19SPierrick Bouvier }
78*354b5c19SPierrick Bouvier 
79*354b5c19SPierrick Bouvier DEFINE_STORE(u8, uint8_t, 0xf1)
80*354b5c19SPierrick Bouvier DEFINE_LOAD(u8, uint8_t, 0xf1)
81*354b5c19SPierrick Bouvier DEFINE_STORE(u16, uint16_t, 0xf123)
82*354b5c19SPierrick Bouvier DEFINE_LOAD(u16, uint16_t, 0xf123)
83*354b5c19SPierrick Bouvier DEFINE_STORE(u32, uint32_t, 0xff112233)
84*354b5c19SPierrick Bouvier DEFINE_LOAD(u32, uint32_t, 0xff112233)
85*354b5c19SPierrick Bouvier 
86*354b5c19SPierrick Bouvier #if defined(__x86_64__) || defined(__aarch64__)
87*354b5c19SPierrick Bouvier DEFINE_STORE(u64, uint64_t, 0xf123456789abcdef)
88*354b5c19SPierrick Bouvier DEFINE_LOAD(u64, uint64_t, 0xf123456789abcdef)
89*354b5c19SPierrick Bouvier 
print_expected_store_u128(void)90*354b5c19SPierrick Bouvier static void print_expected_store_u128(void)
91*354b5c19SPierrick Bouvier {
92*354b5c19SPierrick Bouvier     PRINT_EXPECTED(store_u128, __int128,
93*354b5c19SPierrick Bouvier                    "0xf122334455667788f123456789abcdef", "store");
94*354b5c19SPierrick Bouvier }
95*354b5c19SPierrick Bouvier 
store_u128(void)96*354b5c19SPierrick Bouvier static void store_u128(void)
97*354b5c19SPierrick Bouvier {
98*354b5c19SPierrick Bouvier #ifdef __x86_64__
99*354b5c19SPierrick Bouvier     _mm_store_si128(data, _mm_set_epi32(0xf1223344, 0x55667788,
100*354b5c19SPierrick Bouvier                                         0xf1234567, 0x89abcdef));
101*354b5c19SPierrick Bouvier #else
102*354b5c19SPierrick Bouvier     const uint32_t init[4] = {0x89abcdef, 0xf1234567, 0x55667788, 0xf1223344};
103*354b5c19SPierrick Bouvier     uint32x4_t vec = vld1q_u32(init);
104*354b5c19SPierrick Bouvier     vst1q_u32(data, vec);
105*354b5c19SPierrick Bouvier #endif /* __x86_64__ */
106*354b5c19SPierrick Bouvier     print_expected_store_u128();
107*354b5c19SPierrick Bouvier }
108*354b5c19SPierrick Bouvier 
print_expected_load_u128(void)109*354b5c19SPierrick Bouvier static void print_expected_load_u128(void)
110*354b5c19SPierrick Bouvier {
111*354b5c19SPierrick Bouvier     PRINT_EXPECTED(load_u128, __int128,
112*354b5c19SPierrick Bouvier                    "0xf122334455667788f123456789abcdef", "load");
113*354b5c19SPierrick Bouvier }
114*354b5c19SPierrick Bouvier 
load_u128(void)115*354b5c19SPierrick Bouvier static void load_u128(void)
116*354b5c19SPierrick Bouvier {
117*354b5c19SPierrick Bouvier #ifdef __x86_64__
118*354b5c19SPierrick Bouvier     __m128i var = _mm_load_si128(data);
119*354b5c19SPierrick Bouvier #else
120*354b5c19SPierrick Bouvier     uint32x4_t var = vld1q_u32(data);
121*354b5c19SPierrick Bouvier #endif
122*354b5c19SPierrick Bouvier     (void) var;
123*354b5c19SPierrick Bouvier     print_expected_load_u128();
124*354b5c19SPierrick Bouvier }
125*354b5c19SPierrick Bouvier #endif /* __x86_64__ || __aarch64__ */
126*354b5c19SPierrick Bouvier 
127*354b5c19SPierrick Bouvier #if defined(__x86_64__)
128*354b5c19SPierrick Bouvier DEFINE_ATOMIC_OP(u8, uint8_t, 0xf1)
129*354b5c19SPierrick Bouvier DEFINE_ATOMIC_OP(u16, uint16_t, 0xf123)
130*354b5c19SPierrick Bouvier DEFINE_ATOMIC_OP(u32, uint32_t, 0xff112233)
131*354b5c19SPierrick Bouvier DEFINE_ATOMIC_OP(u64, uint64_t, 0xf123456789abcdef)
132*354b5c19SPierrick Bouvier #endif /* __x86_64__ */
133*354b5c19SPierrick Bouvier 
f(void * p)134*354b5c19SPierrick Bouvier static void *f(void *p)
135*354b5c19SPierrick Bouvier {
136*354b5c19SPierrick Bouvier     return NULL;
137*354b5c19SPierrick Bouvier }
138*354b5c19SPierrick Bouvier 
main(void)139*354b5c19SPierrick Bouvier int main(void)
140*354b5c19SPierrick Bouvier {
141*354b5c19SPierrick Bouvier     /*
142*354b5c19SPierrick Bouvier      * We force creation of a second thread to enable cpu flag CF_PARALLEL.
143*354b5c19SPierrick Bouvier      * This will generate atomic operations when needed.
144*354b5c19SPierrick Bouvier      */
145*354b5c19SPierrick Bouvier     pthread_t thread;
146*354b5c19SPierrick Bouvier     pthread_create(&thread, NULL, &f, NULL);
147*354b5c19SPierrick Bouvier     pthread_join(thread, NULL);
148*354b5c19SPierrick Bouvier 
149*354b5c19SPierrick Bouvier     /* allocate storage up to 128 bits */
150*354b5c19SPierrick Bouvier     data = malloc(16);
151*354b5c19SPierrick Bouvier 
152*354b5c19SPierrick Bouvier     store_u8();
153*354b5c19SPierrick Bouvier     load_u8();
154*354b5c19SPierrick Bouvier 
155*354b5c19SPierrick Bouvier     store_u16();
156*354b5c19SPierrick Bouvier     load_u16();
157*354b5c19SPierrick Bouvier 
158*354b5c19SPierrick Bouvier     store_u32();
159*354b5c19SPierrick Bouvier     load_u32();
160*354b5c19SPierrick Bouvier 
161*354b5c19SPierrick Bouvier #if defined(__x86_64__) || defined(__aarch64__)
162*354b5c19SPierrick Bouvier     store_u64();
163*354b5c19SPierrick Bouvier     load_u64();
164*354b5c19SPierrick Bouvier 
165*354b5c19SPierrick Bouvier     store_u128();
166*354b5c19SPierrick Bouvier     load_u128();
167*354b5c19SPierrick Bouvier #endif /* __x86_64__ || __aarch64__ */
168*354b5c19SPierrick Bouvier 
169*354b5c19SPierrick Bouvier #if defined(__x86_64__)
170*354b5c19SPierrick Bouvier     atomic_op_u8();
171*354b5c19SPierrick Bouvier     atomic_op_u16();
172*354b5c19SPierrick Bouvier     atomic_op_u32();
173*354b5c19SPierrick Bouvier     atomic_op_u64();
174*354b5c19SPierrick Bouvier #endif /* __x86_64__ */
175*354b5c19SPierrick Bouvier 
176*354b5c19SPierrick Bouvier     free(data);
177*354b5c19SPierrick Bouvier }
178