Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp
40930 views
1
/*
2
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2012, 2019 SAP SE. All rights reserved.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation.
9
*
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* version 2 for more details (a copy is included in the LICENSE file that
14
* accompanied this code).
15
*
16
* You should have received a copy of the GNU General Public License version
17
* 2 along with this work; if not, write to the Free Software Foundation,
18
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
*
20
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
* or visit www.oracle.com if you need additional information or have any
22
* questions.
23
*
24
*/
25
26
#ifndef OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP
27
#define OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP
28
29
#ifndef PPC64
30
#error "Atomic currently only implemented for PPC64"
31
#endif
32
33
#include "orderAccess_aix_ppc.hpp"
34
#include "utilities/debug.hpp"
35
36
// Implementation of class atomic
37
38
//
39
// machine barrier instructions:
40
//
41
// - sync two-way memory barrier, aka fence
42
// - lwsync orders Store|Store,
43
// Load|Store,
44
// Load|Load,
45
// but not Store|Load
46
// - eieio orders memory accesses for device memory (only)
47
// - isync invalidates speculatively executed instructions
48
// From the POWER ISA 2.06 documentation:
49
// "[...] an isync instruction prevents the execution of
50
// instructions following the isync until instructions
51
// preceding the isync have completed, [...]"
52
// From IBM's AIX assembler reference:
53
// "The isync [...] instructions causes the processor to
54
// refetch any instructions that might have been fetched
55
// prior to the isync instruction. The instruction isync
56
// causes the processor to wait for all previous instructions
57
// to complete. Then any instructions already fetched are
58
// discarded and instruction processing continues in the
59
// environment established by the previous instructions."
60
//
61
// semantic barrier instructions:
62
// (as defined in orderAccess.hpp)
63
//
64
// - release orders Store|Store, (maps to lwsync)
65
// Load|Store
66
// - acquire orders Load|Store, (maps to lwsync)
67
// Load|Load
68
// - fence orders Store|Store, (maps to sync)
69
// Load|Store,
70
// Load|Load,
71
// Store|Load
72
//
73
74
inline void pre_membar(atomic_memory_order order) {
75
switch (order) {
76
case memory_order_relaxed:
77
case memory_order_acquire: break;
78
case memory_order_release:
79
case memory_order_acq_rel: __asm__ __volatile__ ("lwsync" : : : "memory"); break;
80
default /*conservative*/ : __asm__ __volatile__ ("sync" : : : "memory"); break;
81
}
82
}
83
84
inline void post_membar(atomic_memory_order order) {
85
switch (order) {
86
case memory_order_relaxed:
87
case memory_order_release: break;
88
case memory_order_acquire:
89
case memory_order_acq_rel: __asm__ __volatile__ ("isync" : : : "memory"); break;
90
default /*conservative*/ : __asm__ __volatile__ ("sync" : : : "memory"); break;
91
}
92
}
93
94
95
template<size_t byte_size>
96
struct Atomic::PlatformAdd {
97
template<typename D, typename I>
98
D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const;
99
100
template<typename D, typename I>
101
D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const {
102
return add_and_fetch(dest, add_value, order) - add_value;
103
}
104
};
105
106
template<>
107
template<typename D, typename I>
108
inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value,
109
atomic_memory_order order) const {
110
STATIC_ASSERT(4 == sizeof(I));
111
STATIC_ASSERT(4 == sizeof(D));
112
113
D result;
114
115
pre_membar(order);
116
117
__asm__ __volatile__ (
118
"1: lwarx %0, 0, %2 \n"
119
" add %0, %0, %1 \n"
120
" stwcx. %0, 0, %2 \n"
121
" bne- 1b \n"
122
: /*%0*/"=&r" (result)
123
: /*%1*/"r" (add_value), /*%2*/"r" (dest)
124
: "cc", "memory" );
125
126
post_membar(order);
127
128
return result;
129
}
130
131
132
template<>
133
template<typename D, typename I>
134
inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value,
135
atomic_memory_order order) const {
136
STATIC_ASSERT(8 == sizeof(I));
137
STATIC_ASSERT(8 == sizeof(D));
138
139
D result;
140
141
pre_membar(order);
142
143
__asm__ __volatile__ (
144
"1: ldarx %0, 0, %2 \n"
145
" add %0, %0, %1 \n"
146
" stdcx. %0, 0, %2 \n"
147
" bne- 1b \n"
148
: /*%0*/"=&r" (result)
149
: /*%1*/"r" (add_value), /*%2*/"r" (dest)
150
: "cc", "memory" );
151
152
post_membar(order);
153
154
return result;
155
}
156
157
template<>
158
template<typename T>
159
inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest,
160
T exchange_value,
161
atomic_memory_order order) const {
162
// Note that xchg doesn't necessarily do an acquire
163
// (see synchronizer.cpp).
164
165
T old_value;
166
const uint64_t zero = 0;
167
168
pre_membar(order);
169
170
__asm__ __volatile__ (
171
/* atomic loop */
172
"1: \n"
173
" lwarx %[old_value], %[dest], %[zero] \n"
174
" stwcx. %[exchange_value], %[dest], %[zero] \n"
175
" bne- 1b \n"
176
/* exit */
177
"2: \n"
178
/* out */
179
: [old_value] "=&r" (old_value),
180
"=m" (*dest)
181
/* in */
182
: [dest] "b" (dest),
183
[zero] "r" (zero),
184
[exchange_value] "r" (exchange_value),
185
"m" (*dest)
186
/* clobber */
187
: "cc",
188
"memory"
189
);
190
191
post_membar(order);
192
193
return old_value;
194
}
195
196
template<>
197
template<typename T>
198
inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest,
199
T exchange_value,
200
atomic_memory_order order) const {
201
STATIC_ASSERT(8 == sizeof(T));
202
// Note that xchg doesn't necessarily do an acquire
203
// (see synchronizer.cpp).
204
205
T old_value;
206
const uint64_t zero = 0;
207
208
pre_membar(order);
209
210
__asm__ __volatile__ (
211
/* atomic loop */
212
"1: \n"
213
" ldarx %[old_value], %[dest], %[zero] \n"
214
" stdcx. %[exchange_value], %[dest], %[zero] \n"
215
" bne- 1b \n"
216
/* exit */
217
"2: \n"
218
/* out */
219
: [old_value] "=&r" (old_value),
220
"=m" (*dest)
221
/* in */
222
: [dest] "b" (dest),
223
[zero] "r" (zero),
224
[exchange_value] "r" (exchange_value),
225
"m" (*dest)
226
/* clobber */
227
: "cc",
228
"memory"
229
);
230
231
post_membar(order);
232
233
return old_value;
234
}
235
236
template<>
237
template<typename T>
238
inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest,
239
T compare_value,
240
T exchange_value,
241
atomic_memory_order order) const {
242
STATIC_ASSERT(1 == sizeof(T));
243
244
// Note that cmpxchg guarantees a two-way memory barrier across
245
// the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
246
// specified otherwise (see atomic.hpp).
247
248
// Using 32 bit internally.
249
volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3);
250
251
#ifdef VM_LITTLE_ENDIAN
252
const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8;
253
#else
254
const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8;
255
#endif
256
const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value),
257
masked_exchange_val = ((unsigned int)(unsigned char)exchange_value),
258
xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount;
259
260
unsigned int old_value, value32;
261
262
pre_membar(order);
263
264
__asm__ __volatile__ (
265
/* simple guard */
266
" lbz %[old_value], 0(%[dest]) \n"
267
" cmpw %[masked_compare_val], %[old_value] \n"
268
" bne- 2f \n"
269
/* atomic loop */
270
"1: \n"
271
" lwarx %[value32], 0, %[dest_base] \n"
272
/* extract byte and compare */
273
" srd %[old_value], %[value32], %[shift_amount] \n"
274
" clrldi %[old_value], %[old_value], 56 \n"
275
" cmpw %[masked_compare_val], %[old_value] \n"
276
" bne- 2f \n"
277
/* replace byte and try to store */
278
" xor %[value32], %[xor_value], %[value32] \n"
279
" stwcx. %[value32], 0, %[dest_base] \n"
280
" bne- 1b \n"
281
/* exit */
282
"2: \n"
283
/* out */
284
: [old_value] "=&r" (old_value),
285
[value32] "=&r" (value32),
286
"=m" (*dest),
287
"=m" (*dest_base)
288
/* in */
289
: [dest] "b" (dest),
290
[dest_base] "b" (dest_base),
291
[shift_amount] "r" (shift_amount),
292
[masked_compare_val] "r" (masked_compare_val),
293
[xor_value] "r" (xor_value),
294
"m" (*dest),
295
"m" (*dest_base)
296
/* clobber */
297
: "cc",
298
"memory"
299
);
300
301
post_membar(order);
302
303
return PrimitiveConversions::cast<T>((unsigned char)old_value);
304
}
305
306
template<>
307
template<typename T>
308
inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest,
309
T compare_value,
310
T exchange_value,
311
atomic_memory_order order) const {
312
STATIC_ASSERT(4 == sizeof(T));
313
314
// Note that cmpxchg guarantees a two-way memory barrier across
315
// the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
316
// specified otherwise (see atomic.hpp).
317
318
T old_value;
319
const uint64_t zero = 0;
320
321
pre_membar(order);
322
323
__asm__ __volatile__ (
324
/* simple guard */
325
" lwz %[old_value], 0(%[dest]) \n"
326
" cmpw %[compare_value], %[old_value] \n"
327
" bne- 2f \n"
328
/* atomic loop */
329
"1: \n"
330
" lwarx %[old_value], %[dest], %[zero] \n"
331
" cmpw %[compare_value], %[old_value] \n"
332
" bne- 2f \n"
333
" stwcx. %[exchange_value], %[dest], %[zero] \n"
334
" bne- 1b \n"
335
/* exit */
336
"2: \n"
337
/* out */
338
: [old_value] "=&r" (old_value),
339
"=m" (*dest)
340
/* in */
341
: [dest] "b" (dest),
342
[zero] "r" (zero),
343
[compare_value] "r" (compare_value),
344
[exchange_value] "r" (exchange_value),
345
"m" (*dest)
346
/* clobber */
347
: "cc",
348
"memory"
349
);
350
351
post_membar(order);
352
353
return old_value;
354
}
355
356
template<>
357
template<typename T>
358
inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest,
359
T compare_value,
360
T exchange_value,
361
atomic_memory_order order) const {
362
STATIC_ASSERT(8 == sizeof(T));
363
364
// Note that cmpxchg guarantees a two-way memory barrier across
365
// the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
366
// specified otherwise (see atomic.hpp).
367
368
T old_value;
369
const uint64_t zero = 0;
370
371
pre_membar(order);
372
373
__asm__ __volatile__ (
374
/* simple guard */
375
" ld %[old_value], 0(%[dest]) \n"
376
" cmpd %[compare_value], %[old_value] \n"
377
" bne- 2f \n"
378
/* atomic loop */
379
"1: \n"
380
" ldarx %[old_value], %[dest], %[zero] \n"
381
" cmpd %[compare_value], %[old_value] \n"
382
" bne- 2f \n"
383
" stdcx. %[exchange_value], %[dest], %[zero] \n"
384
" bne- 1b \n"
385
/* exit */
386
"2: \n"
387
/* out */
388
: [old_value] "=&r" (old_value),
389
"=m" (*dest)
390
/* in */
391
: [dest] "b" (dest),
392
[zero] "r" (zero),
393
[compare_value] "r" (compare_value),
394
[exchange_value] "r" (exchange_value),
395
"m" (*dest)
396
/* clobber */
397
: "cc",
398
"memory"
399
);
400
401
post_membar(order);
402
403
return old_value;
404
}
405
406
template<size_t byte_size>
407
struct Atomic::PlatformOrderedLoad<byte_size, X_ACQUIRE> {
408
template <typename T>
409
T operator()(const volatile T* p) const {
410
T t = Atomic::load(p);
411
// Use twi-isync for load_acquire (faster than lwsync).
412
__asm__ __volatile__ ("twi 0,%0,0\n isync\n" : : "r" (t) : "memory");
413
return t;
414
}
415
};
416
417
#endif // OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP
418
419