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