Library of Assembled Shared Sources
atomic_gcc_x86.h
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43namespace lass
44{
45namespace util
46{
47namespace impl
48{
49
50template <>
51struct AtomicOperations<1>
52{
53 template <typename T> inline
54 static bool LASS_CALL compareAndSwap(volatile T& dest, T expectedValue, T newValue)
55 {
56 bool result;
57 __asm__ __volatile__(
58 "lock; cmpxchgb %2, %0;"
59 "sete %1;"
60 : "=m"(dest), "=q"(result)
61 : "q"(newValue), "a"(expectedValue), "m"(dest)
62 : "cc", "memory");
63 return result;
64 }
65
66 template <typename T1, typename T2> inline
67 static bool LASS_CALL compareAndSwap(
68 volatile T1& dest1, T1 expected1, T2 expected2, T1 new1, T2 new2)
69 {
70 bool result;
71#if defined(__PIC__) && LASS_ADDRESS_SIZE == 32
72 __asm__ __volatile__(
73 "pushl %%ebx;"
74 "movb %4, %%ah;"
75 "movb %%cl, %%dh;"
76 "lock; cmpxchgw %%dx, %0;"
77 "sete %1;"
78 "popl %%ebx;"
79 : "=m"(dest1), "=q"(result)
80 : "a"(expected1), "d"(expected2), "m"(new1), "c"(new2), "m"(dest1)
81 : "cc", "memory");
82#else
83 __asm__ __volatile__(
84 "movb %%bl, %%ah;"
85 "movb %%cl, %%dh;"
86 "lock; cmpxchgw %%dx, %0;"
87 "sete %1;"
88 : "=m"(reinterpret_cast<volatile num::Tuint16&>(dest1)), "=q"(result)
89 : "a"(expected1), "d"(new1), "b"(expected2), "c"(new2),
90 "m"(reinterpret_cast<volatile num::Tuint16&>(dest1))
91 : "cc", "memory");
92#endif
93 return result;
94 }
95
96 template <typename T> inline
97 static void LASS_CALL increment(volatile T& value)
98 {
99 __asm__ __volatile__(
100 "lock; incb %0;"
101 : "=m"(value)
102 : "m"(value)
103 : "cc", "memory");
104 }
105
106 template <typename T> inline
107 static void LASS_CALL decrement(volatile T& value)
108 {
109 __asm__ __volatile__(
110 "lock; decb %0;"
111 : "=m"(value)
112 : "m"(value)
113 : "cc", "memory");
114 }
115};
116
117
118
119template <>
120struct AtomicOperations<2>
121{
122 template <typename T> inline
123 static bool LASS_CALL compareAndSwap(volatile T& dest, T expectedValue, T newValue)
124 {
125 bool result;
126 __asm__ __volatile__(
127 "lock; cmpxchgw %2, %0;"
128 "sete %1;"
129 : "=m"(dest), "=q"(result)
130 : "q"(newValue), "a"(expectedValue), "m"(dest)
131 : "cc", "memory");
132 return result;
133 }
134
135 template <typename T1, typename T2> inline
136 static bool LASS_CALL compareAndSwap(
137 volatile T1& dest1, T1 expected1, T2 expected2, T1 new1, T2 new2)
138 {
139 bool result;
140 __asm__ __volatile__(
141 "shll $16, %%eax;"
142 "shll $16, %%edx;"
143 "movw %4, %%ax;"
144 "movw %5, %%dx;"
145 "lock; cmpxchgl %%edx, %0;"
146 "sete %1;"
147 : "=m"(reinterpret_cast<volatile num::Tuint32&>(dest1)), "=q"(result)
148 : "a"(expected2), "d"(new2), "g"(expected1), "g"(new1),
149 "m"(reinterpret_cast<volatile num::Tuint32&>(dest1))
150 : "cc", "memory");
151 return result;
152 }
153
154 template <typename T> inline
155 static void LASS_CALL increment(volatile T& value)
156 {
157 __asm__ __volatile__(
158 "lock; incw %0;"
159 : "=m"(value)
160 : "m"(value)
161 : "cc", "memory");
162 }
163
164 template <typename T> inline
165 static void LASS_CALL decrement(volatile T& value)
166 {
167 __asm__ __volatile__(
168 "lock; decw %0;"
169 : "=m"(value)
170 : "m"(value)
171 : "cc", "memory");
172 }
173};
174
175
176
177template <>
178struct AtomicOperations<4>
179{
180 template <typename T> inline
181 static bool LASS_CALL compareAndSwap(volatile T& dest, T expectedValue, T newValue)
182 {
183 bool result;
184 __asm__ __volatile__(
185 "lock; cmpxchgl %2, %0;"
186 "sete %1;"
187 : "=m"(dest), "=q"(result)
188 : "q"(newValue), "a"(expectedValue), "m"(dest)
189 : "cc", "memory");
190 return result;
191 }
192
193 template <typename T1, typename T2> inline
194 static bool LASS_CALL compareAndSwap(
195 volatile T1& dest1, T1 expected1, T2 expected2, T1 new1, T2 new2)
196 {
197 bool result;
198
199 // cmpxchg8b and PIC mode don't play nice. Push ebx before use!
200 // see http://www.technovelty.org/code/arch/pic-cas.html
201 //
202#if defined(__PIC__) && LASS_ADDRESS_SIZE == 32
203 __asm__ __volatile__(
204 "pushl %%ebx;"
205 "movl %4,%%ebx;"
206 "lock; cmpxchg8b %0;"
207 "sete %1;"
208 "popl %%ebx;"
209 : "=m"(dest1), "=q"(result)
210 : "a"(expected1), "d"(expected2), "m"(new1), "c"(new2), "m"(dest1)
211 : "cc", "memory");
212#else
213 __asm__ __volatile__(
214 "lock; cmpxchg8b %0;"
215 "sete %1;"
216 : "=m"(dest1), "=q"(result)
217 : "a"(expected1), "d"(expected2), "b"(new1), "c"(new2), "m"(dest1)
218 : "cc", "memory");
219#endif
220 return result;
221 }
222
223 template <typename T> inline
224 static void LASS_CALL increment(volatile T& value)
225 {
226 __asm__ __volatile__(
227 "lock; incl %0;"
228 : "=m"(value)
229 : "m"(value)
230 : "cc", "memory");
231 }
232
233 template <typename T> inline
234 static void LASS_CALL decrement(volatile T& value)
235 {
236 __asm__ __volatile__(
237 "lock; decl %0;"
238 : "=m"(value)
239 : "m"(value)
240 : "cc", "memory");
241 }
242};
243
244
245
246template <>
247struct AtomicOperations<8>
248{
249 template <typename T> inline
250 static bool LASS_CALL compareAndSwap(volatile T& dest, T expectedValue, T newValue)
251 {
252 bool result;
253#if LASS_ADDRESS_SIZE == 32
254 // cmpxchg8b and PIC mode don't play nice. Push ebx before use!
255 // see http://www.technovelty.org/code/arch/pic-cas.html
256 //
257# ifdef __PIC__
258 __asm__ __volatile__(
259 "pushl %%ebx;"
260 "movl (%%ecx),%%ebx;"
261 "movl 4(%%ecx),%%ecx;"
262 "lock; cmpxchg8b %0;"
263 "sete %1;"
264 "pop %%ebx;"
265 : "=m"(dest), "=q"(result)
266 : "m"(dest),
267 "a"(reinterpret_cast<volatile num::Tuint32*>((void*)&expectedValue)[0]),
268 "d"(reinterpret_cast<volatile num::Tuint32*>((void*)&expectedValue)[1]),
269 "c"(&newValue)
270 : "cc", "memory");
271# else
272 __asm__ __volatile__(
273 "lock; cmpxchg8b %0;"
274 "sete %1;"
275 : "=m"(dest), "=q"(result)
276 : "m"(dest),
277 "a"(reinterpret_cast<volatile num::Tuint32*>((void*)&expectedValue)[0]),
278 "d"(reinterpret_cast<volatile num::Tuint32*>((void*)&expectedValue)[1]),
279 "b"(reinterpret_cast<volatile num::Tuint32*>((void*)&newValue)[0]),
280 "c"(reinterpret_cast<volatile num::Tuint32*>((void*)&newValue)[1])
281 : "cc", "memory");
282# endif
283#else
284 __asm__ __volatile__(
285 "lock; cmpxchgq %2, %0;"
286 "sete %1;"
287 : "=m"(dest), "=q"(result)
288 : "q"(newValue), "a"(expectedValue), "m"(dest)
289 : "cc", "memory");
290#endif
291 return result;
292 }
293
294#if LASS_ADDRESS_SIZE != 32
295 template <typename T1, typename T2> inline
296 static bool LASS_CALL compareAndSwap(
297 volatile T1& dest1, T1 expected1, T2 expected2, T1 new1, T2 new2)
298 {
299 LASS_ASSERT((reinterpret_cast<num::Tuint64>(&dest1) & 0xf) == 0); // dest needs to be 16-byte aligned.
300 bool result;
301 __asm__ __volatile__(
302 "lock; cmpxchg16b %0;"
303 "sete %1;"
304 : "=m"(dest1), "=q"(result)
305 : "a"(expected1), "d"(expected2), "b"(new1), "c"(new2), "m"(dest1)
306 : "cc", "memory");
307 return result;
308 }
309#endif
310
311 template <typename T> inline
312 static void LASS_CALL increment(volatile T& value)
313 {
314#if LASS_ADDRESS_SIZE == 32
315 // not knowing any better, we emulate incq with cas loop
316 T old, fresh;
317 do
318 {
319 old = value;
320 fresh = old + 1;
321 }
322 while (!atomicCompareAndSwap(value, old, fresh));
323#else
324 __asm__ __volatile__(
325 "lock; incq %0;"
326 : "=m"(value)
327 : "m"(value)
328 : "cc", "memory");
329#endif
330 }
331
332 template <typename T> inline
333 static void LASS_CALL decrement(volatile T& value)
334 {
335#if LASS_ADDRESS_SIZE == 32
336 // not knowing any better, we emulate decq with cas loop
337 T old, fresh;
338 do
339 {
340 old = value;
341 fresh = old - 1;
342 }
343 while (!atomicCompareAndSwap(value, old, fresh));
344#else
345 __asm__ __volatile__(
346 "lock; decq %0;"
347 : "=m"(value)
348 : "m"(value)
349 : "cc", "memory");
350#endif
351 }
352};
353
354}
355}
356}
357
358// EOF
bool atomicCompareAndSwap(volatile T &dest, T expectedValue, T newValue)
Performs the following pseudocode in an atomic way (no other threads can intervene):
Definition atomic.h:94
general utility, debug facilities, ...
Library for Assembled Shared Sources.
Definition config.h:53