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