OSDN Git Service

2012-11-07 Vladimir Makarov <vmakarov@redhat.com>
[pf3gnuchains/gcc-fork.git] / libatomic / fop_n.c
1 /* Copyright (C) 2012 Free Software Foundation, Inc.
2    Contributed by Richard Henderson <rth@redhat.com>.
3
4    This file is part of the GNU Atomic Library (libatomic).
5
6    Libatomic is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    Libatomic is distributed in the hope that it will be useful, but WITHOUT ANY
12    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14    more details.
15
16    Under Section 7 of GPL version 3, you are granted additional
17    permissions described in the GCC Runtime Library Exception, version
18    3.1, as published by the Free Software Foundation.
19
20    You should have received a copy of the GNU General Public License and
21    a copy of the GCC Runtime Library Exception along with this program;
22    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23    <http://www.gnu.org/licenses/>.  */
24
25 #include <libatomic_i.h>
26
27
28 /* This file is included multiple times with required defines:
29      NAME       the name of the operation that we're implementing; 
30      OP         a two-operand functional macro the implements the operation.
31 */
32
33
34 /* If we support the builtin, just use it.  */
35 #if !DONE && SIZE(HAVE_ATOMIC_FETCH_OP)
36 UTYPE
37 SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
38 {
39   if (maybe_specialcase_relaxed(smodel))
40     return C2(__atomic_fetch_,NAME) (mptr, opval, __ATOMIC_RELAXED);
41   else if (maybe_specialcase_acqrel(smodel))
42     return C2(__atomic_fetch_,NAME) (mptr, opval, __ATOMIC_ACQ_REL);
43   else
44     return C2(__atomic_fetch_,NAME) (mptr, opval, __ATOMIC_SEQ_CST);
45 }
46
47 UTYPE
48 SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
49 {
50   if (maybe_specialcase_relaxed(smodel))
51     return C3(__atomic_,NAME,_fetch) (mptr, opval, __ATOMIC_RELAXED);
52   else if (maybe_specialcase_acqrel(smodel))
53     return C3(__atomic_,NAME,_fetch) (mptr, opval, __ATOMIC_ACQ_REL);
54   else
55     return C3(__atomic_,NAME,_fetch) (mptr, opval, __ATOMIC_SEQ_CST);
56 }
57
58 #define DONE 1
59 #endif /* HAVE_ATOMIC_FETCH_OP */
60
61
62 #if !DONE && defined(atomic_compare_exchange_n)
63 UTYPE
64 SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
65 {
66   UTYPE oldval, t;
67
68   pre_barrier (smodel);
69
70   oldval = *mptr;
71   do
72     {
73       t = OP(oldval, opval);
74     }
75   while (!atomic_compare_exchange_n (mptr, &oldval, t, true,
76                                      __ATOMIC_RELAXED, __ATOMIC_RELAXED));
77
78   post_barrier (smodel);
79   return oldval;
80 }
81
82 UTYPE
83 SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
84 {
85   UTYPE oldval, t;
86
87   pre_barrier (smodel);
88
89   oldval = *mptr;
90   do
91     {
92       t = OP(oldval, opval);
93     }
94   while (!atomic_compare_exchange_n (mptr, &oldval, t, true,
95                                      __ATOMIC_RELAXED, __ATOMIC_RELAXED));
96
97   post_barrier (smodel);
98   return t;
99 }
100
101 #define DONE 1
102 #endif /* atomic_compare_exchange_n */
103
104
105 /* If this type is no larger than word-sized, fall back to a word-sized
106    compare-and-swap loop.  */
107 #if !DONE && N < WORDSIZE && defined(atomic_compare_exchange_w)
108 UTYPE
109 SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
110 {
111   UWORD mask, shift, woldval, wopval, t, *wptr;
112
113   pre_barrier (smodel);
114
115   wptr = (UWORD *)mptr;
116   shift = 0;
117   mask = -1;
118
119   wopval = (UWORD)opval << shift;
120   woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
121   do
122     {
123       t = (woldval & ~mask) | (OP(woldval, wopval) & mask);
124     }
125   while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
126                                      __ATOMIC_RELAXED, __ATOMIC_RELAXED));
127
128   post_barrier (smodel);
129   return woldval >> shift;
130 }
131
132 UTYPE
133 SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
134 {
135   UWORD mask, shift, woldval, wopval, t, *wptr;
136
137   pre_barrier (smodel);
138
139   wptr = (UWORD *)mptr;
140   shift = 0;
141   mask = -1;
142
143   wopval = (UWORD)opval << shift;
144   woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
145   do
146     {
147       t = (woldval & ~mask) | (OP(woldval, wopval) & mask);
148     }
149   while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
150                                      __ATOMIC_RELAXED, __ATOMIC_RELAXED));
151
152   post_barrier (smodel);
153   return t >> shift;
154 }
155
156 #define DONE 1
157 #endif /* atomic_compare_exchange_w */
158
159
160 /* Otherwise, fall back to some sort of protection mechanism.  */
161 #if !DONE
162 UTYPE
163 SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel UNUSED)
164 {
165   UTYPE ret;
166   UWORD magic;
167
168   pre_seq_barrier (smodel);
169   magic = protect_start (mptr);
170
171   ret = *mptr;
172   *mptr = OP(ret, opval);
173
174   protect_end (mptr, magic);
175   post_seq_barrier (smodel);
176
177   return ret;
178 }
179
180 UTYPE
181 SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel UNUSED)
182 {
183   UTYPE ret;
184   UWORD magic;
185
186   pre_seq_barrier (smodel);
187   magic = protect_start (mptr);
188
189   ret = OP (*mptr, opval);
190   *mptr = ret;
191
192   protect_end (mptr, magic);
193   post_seq_barrier (smodel);
194
195   return ret;
196 }
197 #endif
198
199 EXPORT_ALIAS (SIZE(C2(fetch_,NAME)));
200 EXPORT_ALIAS (SIZE(C2(NAME,_fetch)));