Browse code

- alpha, armv6 and mip isa2+ atomic_add and atomic_cmpxchg (armv6 & alpha not tested at all due to lacking hardware or emulators)

Andrei Pelinescu-Onciul authored on 10/05/2007 18:27:07
Showing 3 changed files
... ...
@@ -36,6 +36,7 @@
36 36
  * History:
37 37
  * --------
38 38
  *  2006-03-31  created by andrei
39
+ *  2007-05-10  added atomic_add & atomic_cmpxchg (andrei)
39 40
  */
40 41
 
41 42
 
... ...
@@ -125,7 +126,7 @@
125 125
 		P_TYPE ret; \
126 126
 		asm volatile( \
127 127
 			ATOMIC_ASM_OP01_##P_TYPE(OP) \
128
-			: "=&r"(ret), "=r"(v), "=m"(*var), "0"(v)  : "m"(*var) \
128
+			: "=&r"(ret), "=r"(v), "=m"(*var)  : "m"(*var), "1"(v) \
129 129
 			); \
130 130
 		return RET_EXPR; \
131 131
 	}
... ...
@@ -170,6 +171,26 @@
170 170
 		return RET_EXPR; \
171 171
 	}
172 172
 
173
+/* input in %0 and %3 (param), output in %0 */
174
+/* cmpxchg var in %1, old in %0, new_v in %
175
+ * makes the xchg if old==*var
176
+ * returns initial *var (so if ret==old => new_v was written into var)*/
177
+#define ATOMIC_CMPXCHG_DECL(NAME,  P_TYPE) \
178
+	inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
179
+														P_TYPE old, \
180
+														P_TYPE new_v) \
181
+	{ \
182
+		P_TYPE ret; \
183
+		P_TYPE tmp; \
184
+		asm volatile( \
185
+			ATOMIC_ASM_OP01_##P_TYPE("subq  %0, %5, %2 \n\t bne %2, 3f")\
186
+			"3:    \n\t" \
187
+			: "=&r"(ret), "=&r"(new_v), "=r"(tmp), "=m"(*var)  :\
188
+				"m"(*var), "r"(old), "1"(new_v) :"cc" \
189
+			); \
190
+		return ret; \
191
+	}
192
+
173 193
 
174 194
 ATOMIC_FUNC_DECL0_0(inc, "addl %0, 1, %0", int, void, /* no return */ )
175 195
 ATOMIC_FUNC_DECL0_0(dec, "subl %0, 1, %0", int, void, /* no return */ )
... ...
@@ -178,6 +199,8 @@ ATOMIC_FUNC_DECL03_0(or,  "bis %0, %3, %0", int, void, /* no return */ )
178 178
 ATOMIC_FUNC_DECL0_1(inc_and_test, "addl %0, 1, %1", int, int, (ret+1)==0 )
179 179
 ATOMIC_FUNC_DECL0_1(dec_and_test, "subl %0, 1, %1", int, int, (ret-1)==0 )
180 180
 ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, int, int, ret )
181
+ATOMIC_CMPXCHG_DECL(cmpxchg, int )
182
+ATOMIC_FUNC_DECL01_1(add, "addl %1, %0, %1", int, int, ret+v)
181 183
 
182 184
 ATOMIC_FUNC_DECL0_0(inc, "addq %0, 1, %0", long, void, /* no return */ )
183 185
 ATOMIC_FUNC_DECL0_0(dec, "subq %0, 1, %0", long, void, /* no return */ )
... ...
@@ -186,6 +209,8 @@ ATOMIC_FUNC_DECL03_0(or,  "bis %0, %3, %0", long, void, /* no return */ )
186 186
 ATOMIC_FUNC_DECL0_1(inc_and_test, "addq %0, 1, %1", long, long, (ret+1)==0 )
187 187
 ATOMIC_FUNC_DECL0_1(dec_and_test, "subq %0, 1, %1", long, long, (ret-1)==0 )
188 188
 ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, long, long, ret )
189
+ATOMIC_CMPXCHG_DECL(cmpxchg, long )
190
+ATOMIC_FUNC_DECL01_1(add, "addq %1, %0, %1", long, long, ret+v)
189 191
 
190 192
 
191 193
 #define atomic_inc(var) atomic_inc_int(&(var)->val)
... ...
@@ -195,6 +220,9 @@ ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, long, long, ret )
195 195
 #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
196 196
 #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
197 197
 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
198
+#define atomic_cmpxchg(var, old, new_v) \
199
+		atomic_cmpxchg_int(&(var)->val, old, new_v)
200
+#define atomic_add(var, v) atomic_add_int(&(var)->val, (v))
198 201
 
199 202
 
200 203
 /* with integrated membar */
... ...
@@ -37,6 +37,7 @@
37 37
  * History:
38 38
  * --------
39 39
  *  2006-03-31  created by andrei
40
+ *  2007-05-10  added atomic_add and atomic_cmpxchg (andrei)
40 41
  */
41 42
 
42 43
 
... ...
@@ -126,6 +127,44 @@
126 126
 	}
127 127
 
128 128
 
129
+#define ATOMIC_XCHG_DECL(NAME, P_TYPE) \
130
+	inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
131
+														P_TYPE v ) \
132
+	{ \
133
+		P_TYPE ret; \
134
+		asm volatile( \
135
+			"     swp %0, %2, [%3] \n\t" \
136
+			: "=&r"(ret),  "=m"(*var) :\
137
+				"r"(v), "r"(var) \
138
+			); \
139
+		return ret; \
140
+	}
141
+
142
+
143
+/* cmpxchg: %5=old, %4=new_v, %3=var
144
+ * if (*var==old) *var=new_v
145
+ * returns the original *var (can be used to check if it succeeded: 
146
+ *  if old==cmpxchg(var, old, new_v) -> success
147
+ */
148
+#define ATOMIC_CMPXCHG_DECL(NAME, P_TYPE) \
149
+	inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
150
+														P_TYPE old, \
151
+														P_TYPE new_v) \
152
+	{ \
153
+		P_TYPE ret, tmp; \
154
+		asm volatile( \
155
+			"1:   ldrex %0, [%3] \n\t" \
156
+			"     cmp %0, %5 \n\t" \
157
+			"     strexeq %1, %4, [%3] \n\t" \
158
+			"     cmp %1, #0 \n\t" \
159
+			"     bne 1b \n\t" \
160
+			: "=&r"(ret), "=&r"(tmp), "=m"(*var) :\
161
+				"r"(var), "r"(new_v), "r"(old) : "cc" \
162
+			); \
163
+		return ret; \
164
+	}
165
+
166
+
129 167
 
130 168
 ATOMIC_FUNC_DECL(inc,      "add  %1, %0, #1", int, void, /* no return */ )
131 169
 ATOMIC_FUNC_DECL(dec,      "sub  %1, %0, #1", int, void, /* no return */ )
... ...
@@ -133,7 +172,10 @@ ATOMIC_FUNC_DECL1(and,     "and  %1, %0, %4", int, void, /* no return */ )
133 133
 ATOMIC_FUNC_DECL1(or,      "orr  %1, %0, %4", int, void, /* no return */ )
134 134
 ATOMIC_FUNC_DECL(inc_and_test, "add  %1, %0, #1", int, int, ret )
135 135
 ATOMIC_FUNC_DECL(dec_and_test, "sub  %1, %0, #1", int, int, ret )
136
-ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , int, int,  ret)
136
+//ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , int, int,  ret)
137
+ATOMIC_XCHG_DECL(get_and_set, int)
138
+ATOMIC_CMPXCHG_DECL(cmpxchg, int)
139
+ATOMIC_FUNC_DECL1(add,     "add  %1, %0, %4", int, int, ret )
137 140
 
138 141
 ATOMIC_FUNC_DECL(inc,      "add  %1, %0, #1", long, void, /* no return */ )
139 142
 ATOMIC_FUNC_DECL(dec,      "sub  %1, %0, #1", long, void, /* no return */ )
... ...
@@ -141,7 +183,10 @@ ATOMIC_FUNC_DECL1(and,     "and  %1, %0, %4", long, void, /* no return */ )
141 141
 ATOMIC_FUNC_DECL1(or,      "orr  %1, %0, %4", long, void, /* no return */ )
142 142
 ATOMIC_FUNC_DECL(inc_and_test, "add  %1, %0, #1", long, long, ret )
143 143
 ATOMIC_FUNC_DECL(dec_and_test, "sub  %1, %0, #1", long, long, ret )
144
-ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , long, long,  ret)
144
+//ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , long, long,  ret)
145
+ATOMIC_XCHG_DECL(get_and_set, long)
146
+ATOMIC_CMPXCHG_DECL(cmpxchg, long)
147
+ATOMIC_FUNC_DECL1(add,     "add  %1, %0, %4", long, long, ret )
145 148
 
146 149
 #define atomic_inc(var) atomic_inc_int(&(var)->val)
147 150
 #define atomic_dec(var) atomic_dec_int(&(var)->val)
... ...
@@ -150,6 +195,9 @@ ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , long, long,  ret)
150 150
 #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
151 151
 #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
152 152
 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
153
+#define atomic_cmpxchg(var, old, new_v) \
154
+	atomic_cmpxchg_int(&(var)->val, old, new_v)
155
+#define atomic_add(var, v) atomic_add_int(&(var)->val, (v))
153 156
 
154 157
 
155 158
 /* with integrated membar */
... ...
@@ -42,6 +42,7 @@
42 42
  * History:
43 43
  * --------
44 44
  *  2006-03-08  created by andrei
45
+ *  2007-05-10  added atomic_add & atomic_cmpxchg (andrei)
45 46
  */
46 47
 
47 48
 
... ...
@@ -167,6 +168,23 @@
167 167
 	}
168 168
 
169 169
 
170
+/* %0=var, %1=*var, %2=new, %3=old :
171
+ * ret=*var; if *var==old  then *var=new; return ret
172
+ * => if succesfull (changed var to new)  ret==old */
173
+#define ATOMIC_CMPXCHG_DECL(NAME, P_TYPE) \
174
+	inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
175
+														P_TYPE old, \
176
+														P_TYPE new_v) \
177
+	{ \
178
+		asm volatile( \
179
+			ATOMIC_ASM_OP_##P_TYPE("bne %1, %3, 2f \n\t nop") \
180
+			"2:    \n\t" \
181
+			: "=m"(*var), "=&r"(old), "=r"(new_v)  \
182
+			: "r"(old), "m"(*var), "2"(new_v) \
183
+			 \
184
+			); \
185
+		return old; \
186
+	}
170 187
 
171 188
 ATOMIC_FUNC_DECL(inc,      "addiu %2, %1, 1", int, void, /* no return */ )
172 189
 ATOMIC_FUNC_DECL_CT(dec,   "subu %2, %1, %3", 1,  int, void, /* no return */ )
... ...
@@ -175,6 +193,8 @@ ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", int, void,  /* no return */ )
175 175
 ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", int, int, (ret+1)==0 )
176 176
 ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1, int, int, (ret-1)==0 )
177 177
 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, int, int, ret )
178
+ATOMIC_CMPXCHG_DECL(cmpxchg, int)
179
+ATOMIC_FUNC_DECL1(add, "addu %2, %1, %3 \n\t move %1, %2", int, int, ret )
178 180
 
179 181
 #ifdef __CPU_mips64
180 182
 
... ...
@@ -185,6 +205,8 @@ ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", long, void,  /* no return */ )
185 185
 ATOMIC_FUNC_DECL(inc_and_test, "daddiu %2, %1, 1", long, long, (ret+1)==0 )
186 186
 ATOMIC_FUNC_DECL_CT(dec_and_test, "dsubu %2, %1, %3", 1,long, long, (ret-1)==0 )
187 187
 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
188
+ATOMIC_CMPXCHG_DECL(cmpxchg, long)
189
+ATOMIC_FUNC_DECL1(add, "daddu %2, %1, %3 \n\t move %1, %2", long, long, ret )
188 190
 
189 191
 #else /* ! __CPU_mips64 => __CPU_mips2 or __CPU_mips */
190 192
 
... ...
@@ -195,6 +217,8 @@ ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", long, void,  /* no return */ )
195 195
 ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", long, long, (ret+1)==0 )
196 196
 ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1,long, long, (ret-1)==0 )
197 197
 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
198
+ATOMIC_CMPXCHG_DECL(cmpxchg, long)
199
+ATOMIC_FUNC_DECL1(add, "addu %2, %1, %3 \n\t move %1, %2", long, long, ret )
198 200
 
199 201
 #endif /* __CPU_mips64 */
200 202
 
... ...
@@ -205,6 +229,9 @@ ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
205 205
 #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
206 206
 #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
207 207
 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
208
+#define atomic_add(var, i) atomic_add_int(&(var)->val, i)
209
+#define atomic_cmpxchg(var, old, new_v)  \
210
+	atomic_cmpxchg_int(&(var)->val, old, new_v)
208 211
 
209 212
 
210 213
 /* with integrated membar */