1 1.1 christos // SPDX-FileCopyrightText: 1991-1994 by Xerox Corporation. All rights reserved. 2 1.1 christos // SPDX-FileCopyrightText: 1996-1999 by Silicon Graphics. All rights reserved. 3 1.1 christos // SPDX-FileCopyrightText: 1999-2004 Hewlett-Packard Development Company, L.P. 4 1.1 christos // SPDX-FileCopyrightText: 2009 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com> 5 1.1 christos // 6 1.1 christos // SPDX-License-Identifier: LicenseRef-Boehm-GC 7 1.1 christos 8 1.1 christos #ifndef _URCU_ARCH_UATOMIC_X86_H 9 1.1 christos #define _URCU_ARCH_UATOMIC_X86_H 10 1.1 christos 11 1.1 christos #include <stdlib.h> /* For abort(3). */ 12 1.1 christos 13 1.1 christos /* 14 1.1 christos * Code inspired from libuatomic_ops-1.2, inherited in part from the 15 1.1 christos * Boehm-Demers-Weiser conservative garbage collector. 16 1.1 christos */ 17 1.1 christos 18 1.1 christos #include <urcu/arch.h> 19 1.1 christos #include <urcu/config.h> 20 1.1 christos #include <urcu/compiler.h> 21 1.1 christos #include <urcu/system.h> 22 1.1 christos 23 1.1 christos #define UATOMIC_HAS_ATOMIC_BYTE 24 1.1 christos #define UATOMIC_HAS_ATOMIC_SHORT 25 1.1 christos 26 1.1 christos #ifdef __cplusplus 27 1.1 christos extern "C" { 28 1.1 christos #endif 29 1.1 christos 30 1.1 christos /* 31 1.1 christos * Derived from AO_compare_and_swap() and AO_test_and_set_full(). 32 1.1 christos */ 33 1.1 christos 34 1.1 christos /* 35 1.1 christos * The __hp() macro casts the void pointer @x to a pointer to a structure 36 1.1 christos * containing an array of char of the specified size. This allows passing the 37 1.1 christos * @addr arguments of the following inline functions as "m" and "+m" operands 38 1.1 christos * to the assembly. The @size parameter should be a constant to support 39 1.1 christos * compilers such as clang which do not support VLA. Create typedefs because 40 1.1 christos * C++ does not allow types be defined in casts. 41 1.1 christos */ 42 1.1 christos 43 1.1 christos typedef struct { char v[1]; } __hp_1; 44 1.1 christos typedef struct { char v[2]; } __hp_2; 45 1.1 christos typedef struct { char v[4]; } __hp_4; 46 1.1 christos typedef struct { char v[8]; } __hp_8; 47 1.1 christos 48 1.1 christos #define __hp(size, x) ((__hp_##size *)(x)) 49 1.1 christos 50 1.1 christos /* cmpxchg */ 51 1.1 christos 52 1.1 christos static inline __attribute__((always_inline)) 53 1.1 christos unsigned long __uatomic_cmpxchg(void *addr, unsigned long old, 54 1.1 christos unsigned long _new, int len) 55 1.1 christos { 56 1.1 christos switch (len) { 57 1.1 christos case 1: 58 1.1 christos { 59 1.1 christos unsigned char result = old; 60 1.1 christos 61 1.1 christos __asm__ __volatile__( 62 1.1 christos "lock; cmpxchgb %2, %1" 63 1.1 christos : "+a"(result), "+m"(*__hp(1, addr)) 64 1.1 christos : "q"((unsigned char)_new) 65 1.1 christos : "memory"); 66 1.1 christos return result; 67 1.1 christos } 68 1.1 christos case 2: 69 1.1 christos { 70 1.1 christos unsigned short result = old; 71 1.1 christos 72 1.1 christos __asm__ __volatile__( 73 1.1 christos "lock; cmpxchgw %2, %1" 74 1.1 christos : "+a"(result), "+m"(*__hp(2, addr)) 75 1.1 christos : "r"((unsigned short)_new) 76 1.1 christos : "memory"); 77 1.1 christos return result; 78 1.1 christos } 79 1.1 christos case 4: 80 1.1 christos { 81 1.1 christos unsigned int result = old; 82 1.1 christos 83 1.1 christos __asm__ __volatile__( 84 1.1 christos "lock; cmpxchgl %2, %1" 85 1.1 christos : "+a"(result), "+m"(*__hp(4, addr)) 86 1.1 christos : "r"((unsigned int)_new) 87 1.1 christos : "memory"); 88 1.1 christos return result; 89 1.1 christos } 90 1.1 christos #if (CAA_BITS_PER_LONG == 64) 91 1.1 christos case 8: 92 1.1 christos { 93 1.1 christos unsigned long result = old; 94 1.1 christos 95 1.1 christos __asm__ __volatile__( 96 1.1 christos "lock; cmpxchgq %2, %1" 97 1.1 christos : "+a"(result), "+m"(*__hp(8, addr)) 98 1.1 christos : "r"((unsigned long)_new) 99 1.1 christos : "memory"); 100 1.1 christos return result; 101 1.1 christos } 102 1.1 christos #endif 103 1.1 christos } 104 1.1 christos /* 105 1.1 christos * generate an illegal instruction. Cannot catch this with 106 1.1 christos * linker tricks when optimizations are disabled. 107 1.1 christos */ 108 1.1 christos __asm__ __volatile__("ud2"); 109 1.1 christos return 0; 110 1.1 christos } 111 1.1 christos 112 1.1 christos #define _uatomic_cmpxchg(addr, old, _new) \ 113 1.1 christos ((__typeof__(*(addr))) __uatomic_cmpxchg((addr), \ 114 1.1 christos caa_cast_long_keep_sign(old), \ 115 1.1 christos caa_cast_long_keep_sign(_new),\ 116 1.1 christos sizeof(*(addr)))) 117 1.1 christos 118 1.1 christos /* xchg */ 119 1.1 christos 120 1.1 christos static inline __attribute__((always_inline)) 121 1.1 christos unsigned long __uatomic_exchange(void *addr, unsigned long val, int len) 122 1.1 christos { 123 1.1 christos /* Note: the "xchg" instruction does not need a "lock" prefix. */ 124 1.1 christos switch (len) { 125 1.1 christos case 1: 126 1.1 christos { 127 1.1 christos unsigned char result; 128 1.1 christos __asm__ __volatile__( 129 1.1 christos "xchgb %0, %1" 130 1.1 christos : "=q"(result), "+m"(*__hp(1, addr)) 131 1.1 christos : "0" ((unsigned char)val) 132 1.1 christos : "memory"); 133 1.1 christos return result; 134 1.1 christos } 135 1.1 christos case 2: 136 1.1 christos { 137 1.1 christos unsigned short result; 138 1.1 christos __asm__ __volatile__( 139 1.1 christos "xchgw %0, %1" 140 1.1 christos : "=r"(result), "+m"(*__hp(2, addr)) 141 1.1 christos : "0" ((unsigned short)val) 142 1.1 christos : "memory"); 143 1.1 christos return result; 144 1.1 christos } 145 1.1 christos case 4: 146 1.1 christos { 147 1.1 christos unsigned int result; 148 1.1 christos __asm__ __volatile__( 149 1.1 christos "xchgl %0, %1" 150 1.1 christos : "=r"(result), "+m"(*__hp(4, addr)) 151 1.1 christos : "0" ((unsigned int)val) 152 1.1 christos : "memory"); 153 1.1 christos return result; 154 1.1 christos } 155 1.1 christos #if (CAA_BITS_PER_LONG == 64) 156 1.1 christos case 8: 157 1.1 christos { 158 1.1 christos unsigned long result; 159 1.1 christos __asm__ __volatile__( 160 1.1 christos "xchgq %0, %1" 161 1.1 christos : "=r"(result), "+m"(*__hp(8, addr)) 162 1.1 christos : "0" ((unsigned long)val) 163 1.1 christos : "memory"); 164 1.1 christos return result; 165 1.1 christos } 166 1.1 christos #endif 167 1.1 christos } 168 1.1 christos /* 169 1.1 christos * generate an illegal instruction. Cannot catch this with 170 1.1 christos * linker tricks when optimizations are disabled. 171 1.1 christos */ 172 1.1 christos __asm__ __volatile__("ud2"); 173 1.1 christos return 0; 174 1.1 christos } 175 1.1 christos 176 1.1 christos #define _uatomic_xchg(addr, v) \ 177 1.1 christos ((__typeof__(*(addr))) __uatomic_exchange((addr), \ 178 1.1 christos caa_cast_long_keep_sign(v), \ 179 1.1 christos sizeof(*(addr)))) 180 1.1 christos 181 1.1 christos /* uatomic_add_return */ 182 1.1 christos 183 1.1 christos static inline __attribute__((always_inline)) 184 1.1 christos unsigned long __uatomic_add_return(void *addr, unsigned long val, 185 1.1 christos int len) 186 1.1 christos { 187 1.1 christos switch (len) { 188 1.1 christos case 1: 189 1.1 christos { 190 1.1 christos unsigned char result = val; 191 1.1 christos 192 1.1 christos __asm__ __volatile__( 193 1.1 christos "lock; xaddb %1, %0" 194 1.1 christos : "+m"(*__hp(1, addr)), "+q" (result) 195 1.1 christos : 196 1.1 christos : "memory"); 197 1.1 christos return result + (unsigned char)val; 198 1.1 christos } 199 1.1 christos case 2: 200 1.1 christos { 201 1.1 christos unsigned short result = val; 202 1.1 christos 203 1.1 christos __asm__ __volatile__( 204 1.1 christos "lock; xaddw %1, %0" 205 1.1 christos : "+m"(*__hp(2, addr)), "+r" (result) 206 1.1 christos : 207 1.1 christos : "memory"); 208 1.1 christos return result + (unsigned short)val; 209 1.1 christos } 210 1.1 christos case 4: 211 1.1 christos { 212 1.1 christos unsigned int result = val; 213 1.1 christos 214 1.1 christos __asm__ __volatile__( 215 1.1 christos "lock; xaddl %1, %0" 216 1.1 christos : "+m"(*__hp(4, addr)), "+r" (result) 217 1.1 christos : 218 1.1 christos : "memory"); 219 1.1 christos return result + (unsigned int)val; 220 1.1 christos } 221 1.1 christos #if (CAA_BITS_PER_LONG == 64) 222 1.1 christos case 8: 223 1.1 christos { 224 1.1 christos unsigned long result = val; 225 1.1 christos 226 1.1 christos __asm__ __volatile__( 227 1.1 christos "lock; xaddq %1, %0" 228 1.1 christos : "+m"(*__hp(8, addr)), "+r" (result) 229 1.1 christos : 230 1.1 christos : "memory"); 231 1.1 christos return result + (unsigned long)val; 232 1.1 christos } 233 1.1 christos #endif 234 1.1 christos } 235 1.1 christos /* 236 1.1 christos * generate an illegal instruction. Cannot catch this with 237 1.1 christos * linker tricks when optimizations are disabled. 238 1.1 christos */ 239 1.1 christos __asm__ __volatile__("ud2"); 240 1.1 christos return 0; 241 1.1 christos } 242 1.1 christos 243 1.1 christos #define _uatomic_add_return(addr, v) \ 244 1.1 christos ((__typeof__(*(addr))) __uatomic_add_return((addr), \ 245 1.1 christos caa_cast_long_keep_sign(v), \ 246 1.1 christos sizeof(*(addr)))) 247 1.1 christos 248 1.1 christos /* uatomic_and */ 249 1.1 christos 250 1.1 christos static inline __attribute__((always_inline)) 251 1.1 christos void __uatomic_and(void *addr, unsigned long val, int len) 252 1.1 christos { 253 1.1 christos switch (len) { 254 1.1 christos case 1: 255 1.1 christos { 256 1.1 christos __asm__ __volatile__( 257 1.1 christos "lock; andb %1, %0" 258 1.1 christos : "=m"(*__hp(1, addr)) 259 1.1 christos : "iq" ((unsigned char)val) 260 1.1 christos : "memory"); 261 1.1 christos return; 262 1.1 christos } 263 1.1 christos case 2: 264 1.1 christos { 265 1.1 christos __asm__ __volatile__( 266 1.1 christos "lock; andw %1, %0" 267 1.1 christos : "=m"(*__hp(2, addr)) 268 1.1 christos : "ir" ((unsigned short)val) 269 1.1 christos : "memory"); 270 1.1 christos return; 271 1.1 christos } 272 1.1 christos case 4: 273 1.1 christos { 274 1.1 christos __asm__ __volatile__( 275 1.1 christos "lock; andl %1, %0" 276 1.1 christos : "=m"(*__hp(4, addr)) 277 1.1 christos : "ir" ((unsigned int)val) 278 1.1 christos : "memory"); 279 1.1 christos return; 280 1.1 christos } 281 1.1 christos #if (CAA_BITS_PER_LONG == 64) 282 1.1 christos case 8: 283 1.1 christos { 284 1.1 christos __asm__ __volatile__( 285 1.1 christos "lock; andq %1, %0" 286 1.1 christos : "=m"(*__hp(8, addr)) 287 1.1 christos : "er" ((unsigned long)val) 288 1.1 christos : "memory"); 289 1.1 christos return; 290 1.1 christos } 291 1.1 christos #endif 292 1.1 christos } 293 1.1 christos /* 294 1.1 christos * generate an illegal instruction. Cannot catch this with 295 1.1 christos * linker tricks when optimizations are disabled. 296 1.1 christos */ 297 1.1 christos __asm__ __volatile__("ud2"); 298 1.1 christos return; 299 1.1 christos } 300 1.1 christos 301 1.1 christos #define _uatomic_and(addr, v) \ 302 1.1 christos (__uatomic_and((addr), caa_cast_long_keep_sign(v), sizeof(*(addr)))) 303 1.1 christos 304 1.1 christos /* uatomic_or */ 305 1.1 christos 306 1.1 christos static inline __attribute__((always_inline)) 307 1.1 christos void __uatomic_or(void *addr, unsigned long val, int len) 308 1.1 christos { 309 1.1 christos switch (len) { 310 1.1 christos case 1: 311 1.1 christos { 312 1.1 christos __asm__ __volatile__( 313 1.1 christos "lock; orb %1, %0" 314 1.1 christos : "=m"(*__hp(1, addr)) 315 1.1 christos : "iq" ((unsigned char)val) 316 1.1 christos : "memory"); 317 1.1 christos return; 318 1.1 christos } 319 1.1 christos case 2: 320 1.1 christos { 321 1.1 christos __asm__ __volatile__( 322 1.1 christos "lock; orw %1, %0" 323 1.1 christos : "=m"(*__hp(2, addr)) 324 1.1 christos : "ir" ((unsigned short)val) 325 1.1 christos : "memory"); 326 1.1 christos return; 327 1.1 christos } 328 1.1 christos case 4: 329 1.1 christos { 330 1.1 christos __asm__ __volatile__( 331 1.1 christos "lock; orl %1, %0" 332 1.1 christos : "=m"(*__hp(4, addr)) 333 1.1 christos : "ir" ((unsigned int)val) 334 1.1 christos : "memory"); 335 1.1 christos return; 336 1.1 christos } 337 1.1 christos #if (CAA_BITS_PER_LONG == 64) 338 1.1 christos case 8: 339 1.1 christos { 340 1.1 christos __asm__ __volatile__( 341 1.1 christos "lock; orq %1, %0" 342 1.1 christos : "=m"(*__hp(8, addr)) 343 1.1 christos : "er" ((unsigned long)val) 344 1.1 christos : "memory"); 345 1.1 christos return; 346 1.1 christos } 347 1.1 christos #endif 348 1.1 christos } 349 1.1 christos /* 350 1.1 christos * generate an illegal instruction. Cannot catch this with 351 1.1 christos * linker tricks when optimizations are disabled. 352 1.1 christos */ 353 1.1 christos __asm__ __volatile__("ud2"); 354 1.1 christos return; 355 1.1 christos } 356 1.1 christos 357 1.1 christos #define _uatomic_or(addr, v) \ 358 1.1 christos (__uatomic_or((addr), caa_cast_long_keep_sign(v), sizeof(*(addr)))) 359 1.1 christos 360 1.1 christos /* uatomic_add */ 361 1.1 christos 362 1.1 christos static inline __attribute__((always_inline)) 363 1.1 christos void __uatomic_add(void *addr, unsigned long val, int len) 364 1.1 christos { 365 1.1 christos switch (len) { 366 1.1 christos case 1: 367 1.1 christos { 368 1.1 christos __asm__ __volatile__( 369 1.1 christos "lock; addb %1, %0" 370 1.1 christos : "=m"(*__hp(1, addr)) 371 1.1 christos : "iq" ((unsigned char)val) 372 1.1 christos : "memory"); 373 1.1 christos return; 374 1.1 christos } 375 1.1 christos case 2: 376 1.1 christos { 377 1.1 christos __asm__ __volatile__( 378 1.1 christos "lock; addw %1, %0" 379 1.1 christos : "=m"(*__hp(2, addr)) 380 1.1 christos : "ir" ((unsigned short)val) 381 1.1 christos : "memory"); 382 1.1 christos return; 383 1.1 christos } 384 1.1 christos case 4: 385 1.1 christos { 386 1.1 christos __asm__ __volatile__( 387 1.1 christos "lock; addl %1, %0" 388 1.1 christos : "=m"(*__hp(4, addr)) 389 1.1 christos : "ir" ((unsigned int)val) 390 1.1 christos : "memory"); 391 1.1 christos return; 392 1.1 christos } 393 1.1 christos #if (CAA_BITS_PER_LONG == 64) 394 1.1 christos case 8: 395 1.1 christos { 396 1.1 christos __asm__ __volatile__( 397 1.1 christos "lock; addq %1, %0" 398 1.1 christos : "=m"(*__hp(8, addr)) 399 1.1 christos : "er" ((unsigned long)val) 400 1.1 christos : "memory"); 401 1.1 christos return; 402 1.1 christos } 403 1.1 christos #endif 404 1.1 christos } 405 1.1 christos /* 406 1.1 christos * generate an illegal instruction. Cannot catch this with 407 1.1 christos * linker tricks when optimizations are disabled. 408 1.1 christos */ 409 1.1 christos __asm__ __volatile__("ud2"); 410 1.1 christos return; 411 1.1 christos } 412 1.1 christos 413 1.1 christos #define _uatomic_add(addr, v) \ 414 1.1 christos (__uatomic_add((addr), caa_cast_long_keep_sign(v), sizeof(*(addr)))) 415 1.1 christos 416 1.1 christos 417 1.1 christos /* uatomic_inc */ 418 1.1 christos 419 1.1 christos static inline __attribute__((always_inline)) 420 1.1 christos void __uatomic_inc(void *addr, int len) 421 1.1 christos { 422 1.1 christos switch (len) { 423 1.1 christos case 1: 424 1.1 christos { 425 1.1 christos __asm__ __volatile__( 426 1.1 christos "lock; incb %0" 427 1.1 christos : "=m"(*__hp(1, addr)) 428 1.1 christos : 429 1.1 christos : "memory"); 430 1.1 christos return; 431 1.1 christos } 432 1.1 christos case 2: 433 1.1 christos { 434 1.1 christos __asm__ __volatile__( 435 1.1 christos "lock; incw %0" 436 1.1 christos : "=m"(*__hp(2, addr)) 437 1.1 christos : 438 1.1 christos : "memory"); 439 1.1 christos return; 440 1.1 christos } 441 1.1 christos case 4: 442 1.1 christos { 443 1.1 christos __asm__ __volatile__( 444 1.1 christos "lock; incl %0" 445 1.1 christos : "=m"(*__hp(4, addr)) 446 1.1 christos : 447 1.1 christos : "memory"); 448 1.1 christos return; 449 1.1 christos } 450 1.1 christos #if (CAA_BITS_PER_LONG == 64) 451 1.1 christos case 8: 452 1.1 christos { 453 1.1 christos __asm__ __volatile__( 454 1.1 christos "lock; incq %0" 455 1.1 christos : "=m"(*__hp(8, addr)) 456 1.1 christos : 457 1.1 christos : "memory"); 458 1.1 christos return; 459 1.1 christos } 460 1.1 christos #endif 461 1.1 christos } 462 1.1 christos /* generate an illegal instruction. Cannot catch this with linker tricks 463 1.1 christos * when optimizations are disabled. */ 464 1.1 christos __asm__ __volatile__("ud2"); 465 1.1 christos return; 466 1.1 christos } 467 1.1 christos 468 1.1 christos #define _uatomic_inc(addr) (__uatomic_inc((addr), sizeof(*(addr)))) 469 1.1 christos 470 1.1 christos /* uatomic_dec */ 471 1.1 christos 472 1.1 christos static inline __attribute__((always_inline)) 473 1.1 christos void __uatomic_dec(void *addr, int len) 474 1.1 christos { 475 1.1 christos switch (len) { 476 1.1 christos case 1: 477 1.1 christos { 478 1.1 christos __asm__ __volatile__( 479 1.1 christos "lock; decb %0" 480 1.1 christos : "=m"(*__hp(1, addr)) 481 1.1 christos : 482 1.1 christos : "memory"); 483 1.1 christos return; 484 1.1 christos } 485 1.1 christos case 2: 486 1.1 christos { 487 1.1 christos __asm__ __volatile__( 488 1.1 christos "lock; decw %0" 489 1.1 christos : "=m"(*__hp(2, addr)) 490 1.1 christos : 491 1.1 christos : "memory"); 492 1.1 christos return; 493 1.1 christos } 494 1.1 christos case 4: 495 1.1 christos { 496 1.1 christos __asm__ __volatile__( 497 1.1 christos "lock; decl %0" 498 1.1 christos : "=m"(*__hp(4, addr)) 499 1.1 christos : 500 1.1 christos : "memory"); 501 1.1 christos return; 502 1.1 christos } 503 1.1 christos #if (CAA_BITS_PER_LONG == 64) 504 1.1 christos case 8: 505 1.1 christos { 506 1.1 christos __asm__ __volatile__( 507 1.1 christos "lock; decq %0" 508 1.1 christos : "=m"(*__hp(8, addr)) 509 1.1 christos : 510 1.1 christos : "memory"); 511 1.1 christos return; 512 1.1 christos } 513 1.1 christos #endif 514 1.1 christos } 515 1.1 christos /* 516 1.1 christos * generate an illegal instruction. Cannot catch this with 517 1.1 christos * linker tricks when optimizations are disabled. 518 1.1 christos */ 519 1.1 christos __asm__ __volatile__("ud2"); 520 1.1 christos return; 521 1.1 christos } 522 1.1 christos 523 1.1 christos #define _uatomic_dec(addr) (__uatomic_dec((addr), sizeof(*(addr)))) 524 1.1 christos 525 1.1 christos #ifdef URCU_ARCH_X86_NO_CAS 526 1.1 christos 527 1.1 christos /* For backwards compat */ 528 1.1 christos #define CONFIG_RCU_COMPAT_ARCH 1 529 1.1 christos 530 1.1 christos extern int __rcu_cas_avail; 531 1.1 christos extern int __rcu_cas_init(void); 532 1.1 christos 533 1.1 christos #define UATOMIC_COMPAT(insn) \ 534 1.1 christos ((caa_likely(__rcu_cas_avail > 0)) \ 535 1.1 christos ? (_uatomic_##insn) \ 536 1.1 christos : ((caa_unlikely(__rcu_cas_avail < 0) \ 537 1.1 christos ? ((__rcu_cas_init() > 0) \ 538 1.1 christos ? (_uatomic_##insn) \ 539 1.1 christos : (compat_uatomic_##insn)) \ 540 1.1 christos : (compat_uatomic_##insn)))) 541 1.1 christos 542 1.1 christos /* 543 1.1 christos * We leave the return value so we don't break the ABI, but remove the 544 1.1 christos * return value from the API. 545 1.1 christos */ 546 1.1 christos extern unsigned long _compat_uatomic_set(void *addr, 547 1.1 christos unsigned long _new, int len); 548 1.1 christos #define compat_uatomic_set(addr, _new) \ 549 1.1 christos ((void) _compat_uatomic_set((addr), \ 550 1.1 christos caa_cast_long_keep_sign(_new), \ 551 1.1 christos sizeof(*(addr)))) 552 1.1 christos 553 1.1 christos 554 1.1 christos extern unsigned long _compat_uatomic_xchg(void *addr, 555 1.1 christos unsigned long _new, int len); 556 1.1 christos #define compat_uatomic_xchg(addr, _new) \ 557 1.1 christos ((__typeof__(*(addr))) _compat_uatomic_xchg((addr), \ 558 1.1 christos caa_cast_long_keep_sign(_new), \ 559 1.1 christos sizeof(*(addr)))) 560 1.1 christos 561 1.1 christos extern unsigned long _compat_uatomic_cmpxchg(void *addr, unsigned long old, 562 1.1 christos unsigned long _new, int len); 563 1.1 christos #define compat_uatomic_cmpxchg(addr, old, _new) \ 564 1.1 christos ((__typeof__(*(addr))) _compat_uatomic_cmpxchg((addr), \ 565 1.1 christos caa_cast_long_keep_sign(old), \ 566 1.1 christos caa_cast_long_keep_sign(_new), \ 567 1.1 christos sizeof(*(addr)))) 568 1.1 christos 569 1.1 christos extern void _compat_uatomic_and(void *addr, unsigned long _new, int len); 570 1.1 christos #define compat_uatomic_and(addr, v) \ 571 1.1 christos (_compat_uatomic_and((addr), \ 572 1.1 christos caa_cast_long_keep_sign(v), \ 573 1.1 christos sizeof(*(addr)))) 574 1.1 christos 575 1.1 christos extern void _compat_uatomic_or(void *addr, unsigned long _new, int len); 576 1.1 christos #define compat_uatomic_or(addr, v) \ 577 1.1 christos (_compat_uatomic_or((addr), \ 578 1.1 christos caa_cast_long_keep_sign(v), \ 579 1.1 christos sizeof(*(addr)))) 580 1.1 christos 581 1.1 christos extern unsigned long _compat_uatomic_add_return(void *addr, 582 1.1 christos unsigned long _new, int len); 583 1.1 christos #define compat_uatomic_add_return(addr, v) \ 584 1.1 christos ((__typeof__(*(addr))) _compat_uatomic_add_return((addr), \ 585 1.1 christos caa_cast_long_keep_sign(v), \ 586 1.1 christos sizeof(*(addr)))) 587 1.1 christos 588 1.1 christos #define compat_uatomic_add(addr, v) \ 589 1.1 christos ((void)compat_uatomic_add_return((addr), (v))) 590 1.1 christos #define compat_uatomic_inc(addr) \ 591 1.1 christos (compat_uatomic_add((addr), 1)) 592 1.1 christos #define compat_uatomic_dec(addr) \ 593 1.1 christos (compat_uatomic_add((addr), -1)) 594 1.1 christos 595 1.1 christos #else 596 1.1 christos #define UATOMIC_COMPAT(insn) (_uatomic_##insn) 597 1.1 christos #endif 598 1.1 christos 599 1.1 christos /* 600 1.1 christos * All RMW operations have an implicit lock prefix. Thus, ignoring memory 601 1.1 christos * ordering for these operations, since they can all be respected by not 602 1.1 christos * emitting any memory barrier. 603 1.1 christos */ 604 1.1 christos 605 1.1 christos #define uatomic_cmpxchg_mo(addr, old, _new, mos, mof) \ 606 1.1 christos UATOMIC_COMPAT(cmpxchg(addr, old, _new)) 607 1.1 christos 608 1.1 christos #define uatomic_xchg_mo(addr, v, mo) \ 609 1.1 christos UATOMIC_COMPAT(xchg(addr, v)) 610 1.1 christos 611 1.1 christos #define uatomic_and_mo(addr, v, mo) \ 612 1.1 christos UATOMIC_COMPAT(and(addr, v)) 613 1.1 christos #define cmm_smp_mb__before_uatomic_and() cmm_barrier() 614 1.1 christos #define cmm_smp_mb__after_uatomic_and() cmm_barrier() 615 1.1 christos 616 1.1 christos #define uatomic_or_mo(addr, v, mo) \ 617 1.1 christos UATOMIC_COMPAT(or(addr, v)) 618 1.1 christos #define cmm_smp_mb__before_uatomic_or() cmm_barrier() 619 1.1 christos #define cmm_smp_mb__after_uatomic_or() cmm_barrier() 620 1.1 christos 621 1.1 christos #define uatomic_add_return_mo(addr, v, mo) \ 622 1.1 christos UATOMIC_COMPAT(add_return(addr, v)) 623 1.1 christos 624 1.1 christos #define uatomic_add_mo(addr, v, mo) UATOMIC_COMPAT(add(addr, v)) 625 1.1 christos #define cmm_smp_mb__before_uatomic_add() cmm_barrier() 626 1.1 christos #define cmm_smp_mb__after_uatomic_add() cmm_barrier() 627 1.1 christos 628 1.1 christos #define uatomic_inc_mo(addr, mo) UATOMIC_COMPAT(inc(addr)) 629 1.1 christos #define cmm_smp_mb__before_uatomic_inc() cmm_barrier() 630 1.1 christos #define cmm_smp_mb__after_uatomic_inc() cmm_barrier() 631 1.1 christos 632 1.1 christos #define uatomic_dec_mo(addr, mo) UATOMIC_COMPAT(dec(addr)) 633 1.1 christos #define cmm_smp_mb__before_uatomic_dec() cmm_barrier() 634 1.1 christos #define cmm_smp_mb__after_uatomic_dec() cmm_barrier() 635 1.1 christos 636 1.1 christos 637 1.1 christos static inline void _cmm_compat_c11_smp_mb__before_uatomic_load_mo(enum cmm_memorder mo) 638 1.1 christos { 639 1.1 christos /* 640 1.1 christos * A SMP barrier is not necessary for CMM_SEQ_CST because, only a 641 1.1 christos * previous store can be reordered with the load. However, emitting the 642 1.1 christos * memory barrier after the store is sufficient to prevent reordering 643 1.1 christos * between the two. This follows toolchains decision of emitting the 644 1.1 christos * memory fence on the stores instead of the loads. 645 1.1 christos * 646 1.1 christos * A compiler barrier is necessary because the underlying operation does 647 1.1 christos * not clobber the registers. 648 1.1 christos */ 649 1.1 christos switch (mo) { 650 1.1 christos case CMM_RELAXED: /* Fall-through */ 651 1.1 christos case CMM_ACQUIRE: /* Fall-through */ 652 1.1 christos case CMM_CONSUME: /* Fall-through */ 653 1.1 christos case CMM_SEQ_CST: /* Fall-through */ 654 1.1 christos case CMM_SEQ_CST_FENCE: 655 1.1 christos cmm_barrier(); 656 1.1 christos break; 657 1.1 christos case CMM_ACQ_REL: /* Fall-through */ 658 1.1 christos case CMM_RELEASE: /* Fall-through */ 659 1.1 christos default: 660 1.1 christos abort(); 661 1.1 christos break; 662 1.1 christos } 663 1.1 christos } 664 1.1 christos 665 1.1 christos static inline void _cmm_compat_c11_smp_mb__after_uatomic_load_mo(enum cmm_memorder mo) 666 1.1 christos { 667 1.1 christos /* 668 1.1 christos * A SMP barrier is not necessary for CMM_SEQ_CST because following 669 1.1 christos * loads and stores cannot be reordered with the load. 670 1.1 christos * 671 1.1 christos * A SMP barrier is however necessary for CMM_SEQ_CST_FENCE to respect 672 1.1 christos * the memory model, since the underlying operation does not have a lock 673 1.1 christos * prefix. 674 1.1 christos * 675 1.1 christos * A compiler barrier is necessary because the underlying operation does 676 1.1 christos * not clobber the registers. 677 1.1 christos */ 678 1.1 christos switch (mo) { 679 1.1 christos case CMM_SEQ_CST_FENCE: 680 1.1 christos cmm_smp_mb(); 681 1.1 christos break; 682 1.1 christos case CMM_RELAXED: /* Fall-through */ 683 1.1 christos case CMM_ACQUIRE: /* Fall-through */ 684 1.1 christos case CMM_CONSUME: /* Fall-through */ 685 1.1 christos case CMM_SEQ_CST: 686 1.1 christos cmm_barrier(); 687 1.1 christos break; 688 1.1 christos case CMM_ACQ_REL: /* Fall-through */ 689 1.1 christos case CMM_RELEASE: /* Fall-through */ 690 1.1 christos default: 691 1.1 christos abort(); 692 1.1 christos break; 693 1.1 christos } 694 1.1 christos } 695 1.1 christos 696 1.1 christos static inline void _cmm_compat_c11_smp_mb__before_uatomic_store_mo(enum cmm_memorder mo) 697 1.1 christos { 698 1.1 christos /* 699 1.1 christos * A SMP barrier is not necessary for CMM_SEQ_CST because the store can 700 1.1 christos * only be reodered with later loads 701 1.1 christos * 702 1.1 christos * A compiler barrier is necessary because the underlying operation does 703 1.1 christos * not clobber the registers. 704 1.1 christos */ 705 1.1 christos switch (mo) { 706 1.1 christos case CMM_RELAXED: /* Fall-through */ 707 1.1 christos case CMM_RELEASE: /* Fall-through */ 708 1.1 christos case CMM_SEQ_CST: /* Fall-through */ 709 1.1 christos case CMM_SEQ_CST_FENCE: 710 1.1 christos cmm_barrier(); 711 1.1 christos break; 712 1.1 christos case CMM_ACQ_REL: /* Fall-through */ 713 1.1 christos case CMM_ACQUIRE: /* Fall-through */ 714 1.1 christos case CMM_CONSUME: /* Fall-through */ 715 1.1 christos default: 716 1.1 christos abort(); 717 1.1 christos break; 718 1.1 christos } 719 1.1 christos } 720 1.1 christos 721 1.1 christos static inline void _cmm_compat_c11_smp_mb__after_uatomic_store_mo(enum cmm_memorder mo) 722 1.1 christos { 723 1.1 christos /* 724 1.1 christos * A SMP barrier is necessary for CMM_SEQ_CST because the store can be 725 1.1 christos * reorded with later loads. Since no memory barrier is being emitted 726 1.1 christos * before loads, one has to be emitted after the store. This follows 727 1.1 christos * toolchains decision of emitting the memory fence on the stores instead 728 1.1 christos * of the loads. 729 1.1 christos * 730 1.1 christos * A SMP barrier is necessary for CMM_SEQ_CST_FENCE to respect the 731 1.1 christos * memory model, since the underlying store does not have a lock prefix. 732 1.1 christos * 733 1.1 christos * A compiler barrier is necessary because the underlying operation does 734 1.1 christos * not clobber the registers. 735 1.1 christos */ 736 1.1 christos switch (mo) { 737 1.1 christos case CMM_SEQ_CST: /* Fall-through */ 738 1.1 christos case CMM_SEQ_CST_FENCE: 739 1.1 christos cmm_smp_mb(); 740 1.1 christos break; 741 1.1 christos case CMM_RELAXED: /* Fall-through */ 742 1.1 christos case CMM_RELEASE: 743 1.1 christos cmm_barrier(); 744 1.1 christos break; 745 1.1 christos case CMM_ACQ_REL: /* Fall-through */ 746 1.1 christos case CMM_ACQUIRE: /* Fall-through */ 747 1.1 christos case CMM_CONSUME: /* Fall-through */ 748 1.1 christos default: 749 1.1 christos abort(); 750 1.1 christos break; 751 1.1 christos } 752 1.1 christos } 753 1.1 christos 754 1.1 christos #define _cmm_compat_c11_smp_mb__before_mo(operation, mo) \ 755 1.1 christos do { \ 756 1.1 christos _cmm_compat_c11_smp_mb__before_ ## operation ## _mo (mo); \ 757 1.1 christos } while (0) 758 1.1 christos 759 1.1 christos #define _cmm_compat_c11_smp_mb__after_mo(operation, mo) \ 760 1.1 christos do { \ 761 1.1 christos _cmm_compat_c11_smp_mb__after_ ## operation ## _mo (mo); \ 762 1.1 christos } while (0) 763 1.1 christos 764 1.1 christos 765 1.1 christos #ifdef __cplusplus 766 1.1 christos } 767 1.1 christos #endif 768 1.1 christos 769 1.1 christos #include <urcu/uatomic/generic.h> 770 1.1 christos 771 1.1 christos #endif /* _URCU_ARCH_UATOMIC_X86_H */ 772