Warning: That file was not part of the compilation database. It may have many parsing errors.

1 | /* Atomic operations used inside libc. Linux/SH version. |
---|---|

2 | Copyright (C) 2003-2019 Free Software Foundation, Inc. |

3 | This file is part of the GNU C Library. |

4 | |

5 | The GNU C Library is free software; you can redistribute it and/or |

6 | modify it under the terms of the GNU Lesser General Public |

7 | License as published by the Free Software Foundation; either |

8 | version 2.1 of the License, or (at your option) any later version. |

9 | |

10 | The GNU C Library is distributed in the hope that it will be useful, |

11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |

12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |

13 | Lesser General Public License for more details. |

14 | |

15 | You should have received a copy of the GNU Lesser General Public |

16 | License along with the GNU C Library; if not, see |

17 | <http://www.gnu.org/licenses/>. */ |

18 | |

19 | #include <stdint.h> |

20 | |

21 | |

22 | typedef int8_t atomic8_t; |

23 | typedef uint8_t uatomic8_t; |

24 | typedef int_fast8_t atomic_fast8_t; |

25 | typedef uint_fast8_t uatomic_fast8_t; |

26 | |

27 | typedef int16_t atomic16_t; |

28 | typedef uint16_t uatomic16_t; |

29 | typedef int_fast16_t atomic_fast16_t; |

30 | typedef uint_fast16_t uatomic_fast16_t; |

31 | |

32 | typedef int32_t atomic32_t; |

33 | typedef uint32_t uatomic32_t; |

34 | typedef int_fast32_t atomic_fast32_t; |

35 | typedef uint_fast32_t uatomic_fast32_t; |

36 | |

37 | typedef int64_t atomic64_t; |

38 | typedef uint64_t uatomic64_t; |

39 | typedef int_fast64_t atomic_fast64_t; |

40 | typedef uint_fast64_t uatomic_fast64_t; |

41 | |

42 | typedef intptr_t atomicptr_t; |

43 | typedef uintptr_t uatomicptr_t; |

44 | typedef intmax_t atomic_max_t; |

45 | typedef uintmax_t uatomic_max_t; |

46 | |

47 | #define __HAVE_64B_ATOMICS 0 |

48 | #define USE_ATOMIC_COMPILER_BUILTINS 0 |

49 | |

50 | /* XXX Is this actually correct? */ |

51 | #define ATOMIC_EXCHANGE_USES_CAS 1 |

52 | |

53 | /* SH kernel has implemented a gUSA ("g" User Space Atomicity) support |

54 | for the user space atomicity. The atomicity macros use this scheme. |

55 | |

56 | Reference: |

57 | Niibe Yutaka, "gUSA: Simple and Efficient User Space Atomicity |

58 | Emulation with Little Kernel Modification", Linux Conference 2002, |

59 | Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in |

60 | Japanese). |

61 | |

62 | B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for |

63 | Uniprocessors", Proceedings of the Fifth Architectural Support for |

64 | Programming Languages and Operating Systems (ASPLOS), pp. 223-233, |

65 | October 1992. http://www.cs.washington.edu/homes/bershad/Papers/Rcs.ps |

66 | |

67 | SuperH ABI: |

68 | r15: -(size of atomic instruction sequence) < 0 |

69 | r0: end point |

70 | r1: saved stack pointer |

71 | */ |

72 | |

73 | #define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ |

74 | ({ __typeof (*(mem)) __result; \ |

75 | __asm __volatile ("\ |

76 | mova 1f,r0\n\ |

77 | .align 2\n\ |

78 | mov r15,r1\n\ |

79 | mov #(0f-1f),r15\n\ |

80 | 0: mov.b @%1,%0\n\ |

81 | cmp/eq %0,%3\n\ |

82 | bf 1f\n\ |

83 | mov.b %2,@%1\n\ |

84 | 1: mov r1,r15"\ |

85 | : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \ |

86 | : "r0", "r1", "t", "memory"); \ |

87 | __result; }) |

88 | |

89 | #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ |

90 | ({ __typeof (*(mem)) __result; \ |

91 | __asm __volatile ("\ |

92 | mova 1f,r0\n\ |

93 | mov r15,r1\n\ |

94 | .align 2\n\ |

95 | mov #(0f-1f),r15\n\ |

96 | mov #-8,r15\n\ |

97 | 0: mov.w @%1,%0\n\ |

98 | cmp/eq %0,%3\n\ |

99 | bf 1f\n\ |

100 | mov.w %2,@%1\n\ |

101 | 1: mov r1,r15"\ |

102 | : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \ |

103 | : "r0", "r1", "t", "memory"); \ |

104 | __result; }) |

105 | |

106 | #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ |

107 | ({ __typeof (*(mem)) __result; \ |

108 | __asm __volatile ("\ |

109 | mova 1f,r0\n\ |

110 | .align 2\n\ |

111 | mov r15,r1\n\ |

112 | mov #(0f-1f),r15\n\ |

113 | 0: mov.l @%1,%0\n\ |

114 | cmp/eq %0,%3\n\ |

115 | bf 1f\n\ |

116 | mov.l %2,@%1\n\ |

117 | 1: mov r1,r15"\ |

118 | : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \ |

119 | : "r0", "r1", "t", "memory"); \ |

120 | __result; }) |

121 | |

122 | /* XXX We do not really need 64-bit compare-and-exchange. At least |

123 | not in the moment. Using it would mean causing portability |

124 | problems since not many other 32-bit architectures have support for |

125 | such an operation. So don't define any code for now. */ |

126 | |

127 | # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ |

128 | (abort (), (__typeof (*mem)) 0) |

129 | |

130 | #define atomic_exchange_and_add(mem, value) \ |

131 | ({ __typeof (*(mem)) __result, __tmp, __value = (value); \ |

132 | if (sizeof (*(mem)) == 1) \ |

133 | __asm __volatile ("\ |

134 | mova 1f,r0\n\ |

135 | .align 2\n\ |

136 | mov r15,r1\n\ |

137 | mov #(0f-1f),r15\n\ |

138 | 0: mov.b @%2,%0\n\ |

139 | mov %1,r2\n\ |

140 | add %0,r2\n\ |

141 | mov.b r2,@%2\n\ |

142 | 1: mov r1,r15"\ |

143 | : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

144 | : "r0", "r1", "r2", "memory"); \ |

145 | else if (sizeof (*(mem)) == 2) \ |

146 | __asm __volatile ("\ |

147 | mova 1f,r0\n\ |

148 | .align 2\n\ |

149 | mov r15,r1\n\ |

150 | mov #(0f-1f),r15\n\ |

151 | 0: mov.w @%2,%0\n\ |

152 | mov %1,r2\n\ |

153 | add %0,r2\n\ |

154 | mov.w r2,@%2\n\ |

155 | 1: mov r1,r15"\ |

156 | : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

157 | : "r0", "r1", "r2", "memory"); \ |

158 | else if (sizeof (*(mem)) == 4) \ |

159 | __asm __volatile ("\ |

160 | mova 1f,r0\n\ |

161 | .align 2\n\ |

162 | mov r15,r1\n\ |

163 | mov #(0f-1f),r15\n\ |

164 | 0: mov.l @%2,%0\n\ |

165 | mov %1,r2\n\ |

166 | add %0,r2\n\ |

167 | mov.l r2,@%2\n\ |

168 | 1: mov r1,r15"\ |

169 | : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

170 | : "r0", "r1", "r2", "memory"); \ |

171 | else \ |

172 | { \ |

173 | __typeof (mem) memp = (mem); \ |

174 | do \ |

175 | __result = *memp; \ |

176 | while (__arch_compare_and_exchange_val_64_acq \ |

177 | (memp, __result + __value, __result) == __result); \ |

178 | (void) __value; \ |

179 | } \ |

180 | __result; }) |

181 | |

182 | #define atomic_add(mem, value) \ |

183 | (void) ({ __typeof (*(mem)) __tmp, __value = (value); \ |

184 | if (sizeof (*(mem)) == 1) \ |

185 | __asm __volatile ("\ |

186 | mova 1f,r0\n\ |

187 | mov r15,r1\n\ |

188 | .align 2\n\ |

189 | mov #(0f-1f),r15\n\ |

190 | 0: mov.b @%1,r2\n\ |

191 | add %0,r2\n\ |

192 | mov.b r2,@%1\n\ |

193 | 1: mov r1,r15"\ |

194 | : "=&r" (__tmp) : "u" (mem), "0" (__value) \ |

195 | : "r0", "r1", "r2", "memory"); \ |

196 | else if (sizeof (*(mem)) == 2) \ |

197 | __asm __volatile ("\ |

198 | mova 1f,r0\n\ |

199 | mov r15,r1\n\ |

200 | .align 2\n\ |

201 | mov #(0f-1f),r15\n\ |

202 | 0: mov.w @%1,r2\n\ |

203 | add %0,r2\n\ |

204 | mov.w r2,@%1\n\ |

205 | 1: mov r1,r15"\ |

206 | : "=&r" (__tmp) : "u" (mem), "0" (__value) \ |

207 | : "r0", "r1", "r2", "memory"); \ |

208 | else if (sizeof (*(mem)) == 4) \ |

209 | __asm __volatile ("\ |

210 | mova 1f,r0\n\ |

211 | mov r15,r1\n\ |

212 | .align 2\n\ |

213 | mov #(0f-1f),r15\n\ |

214 | 0: mov.l @%1,r2\n\ |

215 | add %0,r2\n\ |

216 | mov.l r2,@%1\n\ |

217 | 1: mov r1,r15"\ |

218 | : "=&r" (__tmp) : "u" (mem), "0" (__value) \ |

219 | : "r0", "r1", "r2", "memory"); \ |

220 | else \ |

221 | { \ |

222 | __typeof (*(mem)) oldval; \ |

223 | __typeof (mem) memp = (mem); \ |

224 | do \ |

225 | oldval = *memp; \ |

226 | while (__arch_compare_and_exchange_val_64_acq \ |

227 | (memp, oldval + __value, oldval) == oldval); \ |

228 | (void) __value; \ |

229 | } \ |

230 | }) |

231 | |

232 | #define atomic_add_negative(mem, value) \ |

233 | ({ unsigned char __result; \ |

234 | __typeof (*(mem)) __tmp, __value = (value); \ |

235 | if (sizeof (*(mem)) == 1) \ |

236 | __asm __volatile ("\ |

237 | mova 1f,r0\n\ |

238 | mov r15,r1\n\ |

239 | .align 2\n\ |

240 | mov #(0f-1f),r15\n\ |

241 | 0: mov.b @%2,r2\n\ |

242 | add %1,r2\n\ |

243 | mov.b r2,@%2\n\ |

244 | 1: mov r1,r15\n\ |

245 | shal r2\n\ |

246 | movt %0"\ |

247 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

248 | : "r0", "r1", "r2", "t", "memory"); \ |

249 | else if (sizeof (*(mem)) == 2) \ |

250 | __asm __volatile ("\ |

251 | mova 1f,r0\n\ |

252 | mov r15,r1\n\ |

253 | .align 2\n\ |

254 | mov #(0f-1f),r15\n\ |

255 | 0: mov.w @%2,r2\n\ |

256 | add %1,r2\n\ |

257 | mov.w r2,@%2\n\ |

258 | 1: mov r1,r15\n\ |

259 | shal r2\n\ |

260 | movt %0"\ |

261 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

262 | : "r0", "r1", "r2", "t", "memory"); \ |

263 | else if (sizeof (*(mem)) == 4) \ |

264 | __asm __volatile ("\ |

265 | mova 1f,r0\n\ |

266 | mov r15,r1\n\ |

267 | .align 2\n\ |

268 | mov #(0f-1f),r15\n\ |

269 | 0: mov.l @%2,r2\n\ |

270 | add %1,r2\n\ |

271 | mov.l r2,@%2\n\ |

272 | 1: mov r1,r15\n\ |

273 | shal r2\n\ |

274 | movt %0"\ |

275 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

276 | : "r0", "r1", "r2", "t", "memory"); \ |

277 | else \ |

278 | abort (); \ |

279 | __result; }) |

280 | |

281 | #define atomic_add_zero(mem, value) \ |

282 | ({ unsigned char __result; \ |

283 | __typeof (*(mem)) __tmp, __value = (value); \ |

284 | if (sizeof (*(mem)) == 1) \ |

285 | __asm __volatile ("\ |

286 | mova 1f,r0\n\ |

287 | mov r15,r1\n\ |

288 | .align 2\n\ |

289 | mov #(0f-1f),r15\n\ |

290 | 0: mov.b @%2,r2\n\ |

291 | add %1,r2\n\ |

292 | mov.b r2,@%2\n\ |

293 | 1: mov r1,r15\n\ |

294 | tst r2,r2\n\ |

295 | movt %0"\ |

296 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

297 | : "r0", "r1", "r2", "t", "memory"); \ |

298 | else if (sizeof (*(mem)) == 2) \ |

299 | __asm __volatile ("\ |

300 | mova 1f,r0\n\ |

301 | mov r15,r1\n\ |

302 | .align 2\n\ |

303 | mov #(0f-1f),r15\n\ |

304 | 0: mov.w @%2,r2\n\ |

305 | add %1,r2\n\ |

306 | mov.w r2,@%2\n\ |

307 | 1: mov r1,r15\n\ |

308 | tst r2,r2\n\ |

309 | movt %0"\ |

310 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

311 | : "r0", "r1", "r2", "t", "memory"); \ |

312 | else if (sizeof (*(mem)) == 4) \ |

313 | __asm __volatile ("\ |

314 | mova 1f,r0\n\ |

315 | mov r15,r1\n\ |

316 | .align 2\n\ |

317 | mov #(0f-1f),r15\n\ |

318 | 0: mov.l @%2,r2\n\ |

319 | add %1,r2\n\ |

320 | mov.l r2,@%2\n\ |

321 | 1: mov r1,r15\n\ |

322 | tst r2,r2\n\ |

323 | movt %0"\ |

324 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |

325 | : "r0", "r1", "r2", "t", "memory"); \ |

326 | else \ |

327 | abort (); \ |

328 | __result; }) |

329 | |

330 | #define atomic_increment_and_test(mem) atomic_add_zero((mem), 1) |

331 | #define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1) |

332 | |

333 | #define atomic_bit_set(mem, bit) \ |

334 | (void) ({ unsigned int __mask = 1 << (bit); \ |

335 | if (sizeof (*(mem)) == 1) \ |

336 | __asm __volatile ("\ |

337 | mova 1f,r0\n\ |

338 | mov r15,r1\n\ |

339 | .align 2\n\ |

340 | mov #(0f-1f),r15\n\ |

341 | 0: mov.b @%0,r2\n\ |

342 | or %1,r2\n\ |

343 | mov.b r2,@%0\n\ |

344 | 1: mov r1,r15"\ |

345 | : : "u" (mem), "u" (__mask) \ |

346 | : "r0", "r1", "r2", "memory"); \ |

347 | else if (sizeof (*(mem)) == 2) \ |

348 | __asm __volatile ("\ |

349 | mova 1f,r0\n\ |

350 | mov r15,r1\n\ |

351 | .align 2\n\ |

352 | mov #(0f-1f),r15\n\ |

353 | 0: mov.w @%0,r2\n\ |

354 | or %1,r2\n\ |

355 | mov.w r2,@%0\n\ |

356 | 1: mov r1,r15"\ |

357 | : : "u" (mem), "u" (__mask) \ |

358 | : "r0", "r1", "r2", "memory"); \ |

359 | else if (sizeof (*(mem)) == 4) \ |

360 | __asm __volatile ("\ |

361 | mova 1f,r0\n\ |

362 | mov r15,r1\n\ |

363 | .align 2\n\ |

364 | mov #(0f-1f),r15\n\ |

365 | 0: mov.l @%0,r2\n\ |

366 | or %1,r2\n\ |

367 | mov.l r2,@%0\n\ |

368 | 1: mov r1,r15"\ |

369 | : : "u" (mem), "u" (__mask) \ |

370 | : "r0", "r1", "r2", "memory"); \ |

371 | else \ |

372 | abort (); \ |

373 | }) |

374 | |

375 | #define atomic_bit_test_set(mem, bit) \ |

376 | ({ unsigned int __mask = 1 << (bit); \ |

377 | unsigned int __result = __mask; \ |

378 | if (sizeof (*(mem)) == 1) \ |

379 | __asm __volatile ("\ |

380 | mova 1f,r0\n\ |

381 | .align 2\n\ |

382 | mov r15,r1\n\ |

383 | mov #(0f-1f),r15\n\ |

384 | 0: mov.b @%2,r2\n\ |

385 | mov r2,r3\n\ |

386 | or %1,r2\n\ |

387 | mov.b r2,@%2\n\ |

388 | 1: mov r1,r15\n\ |

389 | and r3,%0"\ |

390 | : "=&r" (__result), "=&r" (__mask) \ |

391 | : "u" (mem), "0" (__result), "1" (__mask) \ |

392 | : "r0", "r1", "r2", "r3", "memory"); \ |

393 | else if (sizeof (*(mem)) == 2) \ |

394 | __asm __volatile ("\ |

395 | mova 1f,r0\n\ |

396 | .align 2\n\ |

397 | mov r15,r1\n\ |

398 | mov #(0f-1f),r15\n\ |

399 | 0: mov.w @%2,r2\n\ |

400 | mov r2,r3\n\ |

401 | or %1,r2\n\ |

402 | mov.w %1,@%2\n\ |

403 | 1: mov r1,r15\n\ |

404 | and r3,%0"\ |

405 | : "=&r" (__result), "=&r" (__mask) \ |

406 | : "u" (mem), "0" (__result), "1" (__mask) \ |

407 | : "r0", "r1", "r2", "r3", "memory"); \ |

408 | else if (sizeof (*(mem)) == 4) \ |

409 | __asm __volatile ("\ |

410 | mova 1f,r0\n\ |

411 | .align 2\n\ |

412 | mov r15,r1\n\ |

413 | mov #(0f-1f),r15\n\ |

414 | 0: mov.l @%2,r2\n\ |

415 | mov r2,r3\n\ |

416 | or r2,%1\n\ |

417 | mov.l %1,@%2\n\ |

418 | 1: mov r1,r15\n\ |

419 | and r3,%0"\ |

420 | : "=&r" (__result), "=&r" (__mask) \ |

421 | : "u" (mem), "0" (__result), "1" (__mask) \ |

422 | : "r0", "r1", "r2", "r3", "memory"); \ |

423 | else \ |

424 | abort (); \ |

425 | __result; }) |

426 |

Warning: That file was not part of the compilation database. It may have many parsing errors.