Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
Clojure
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Helion
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Yul (Solidity IR)
Zig
Javascript
GIMPLE
Ygen
sway
c source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502 cc65 2.17
6502 cc65 2.18
6502 cc65 2.19
6502 cc65 trunk
ARM GCC 10.2.0 (linux)
ARM GCC 10.2.1 (none)
ARM GCC 10.3.0 (linux)
ARM GCC 10.3.1 (2021.07 none)
ARM GCC 10.3.1 (2021.10 none)
ARM GCC 10.5.0
ARM GCC 11.1.0 (linux)
ARM GCC 11.2.0 (linux)
ARM GCC 11.2.1 (none)
ARM GCC 11.3.0 (linux)
ARM GCC 11.4.0
ARM GCC 12.1.0 (linux)
ARM GCC 12.2.0 (linux)
ARM GCC 12.3.0
ARM GCC 12.4.0
ARM GCC 12.5.0
ARM GCC 13.1.0 (linux)
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 13.3.0
ARM GCC 13.3.0 (unknown-eabi)
ARM GCC 13.4.0
ARM GCC 13.4.0 (unknown-eabi)
ARM GCC 14.1.0
ARM GCC 14.1.0 (unknown-eabi)
ARM GCC 14.2.0
ARM GCC 14.2.0 (unknown-eabi)
ARM GCC 14.3.0
ARM GCC 14.3.0 (unknown-eabi)
ARM GCC 15.1.0
ARM GCC 15.1.0 (unknown-eabi)
ARM GCC 15.2.0
ARM GCC 15.2.0 (unknown-eabi)
ARM GCC 4.5.4 (linux)
ARM GCC 4.6.4 (linux)
ARM GCC 5.4 (linux)
ARM GCC 5.4.1 (none)
ARM GCC 6.3.0 (linux)
ARM GCC 6.4.0 (linux)
ARM GCC 7.2.1 (none)
ARM GCC 7.3.0 (linux)
ARM GCC 7.5.0 (linux)
ARM GCC 8.2.0 (WinCE)
ARM GCC 8.2.0 (linux)
ARM GCC 8.3.1 (none)
ARM GCC 8.5.0 (linux)
ARM GCC 9.2.1 (none)
ARM GCC 9.3.0 (linux)
ARM GCC trunk (linux)
ARM msvc v19.0 (ex-WINE)
ARM msvc v19.10 (ex-WINE)
ARM msvc v19.14 (ex-WINE)
ARM64 GCC 10.2.0
ARM64 GCC 10.3.0
ARM64 GCC 10.4.0
ARM64 GCC 10.5.0
ARM64 GCC 11.1.0
ARM64 GCC 11.2.0
ARM64 GCC 11.3.0
ARM64 GCC 11.4.0
ARM64 GCC 12.1.0
ARM64 GCC 12.2.0
ARM64 GCC 12.3.0
ARM64 GCC 12.4.0
ARM64 GCC 12.5.0
ARM64 GCC 13.1.0
ARM64 GCC 13.2.0
ARM64 GCC 13.3.0
ARM64 GCC 13.4.0
ARM64 GCC 14.1.0
ARM64 GCC 14.2.0
ARM64 GCC 14.3.0
ARM64 GCC 15.1.0
ARM64 GCC 15.2.0
ARM64 GCC 4.9.4
ARM64 GCC 5.4
ARM64 GCC 5.5.0
ARM64 GCC 6.3
ARM64 GCC 6.4.0
ARM64 GCC 7.3.0
ARM64 GCC 7.5.0
ARM64 GCC 8.2.0
ARM64 GCC 8.5.0
ARM64 GCC 9.3.0
ARM64 GCC 9.4.0
ARM64 GCC 9.5.0
ARM64 GCC trunk
ARM64 Morello GCC 10.1.0 Alpha 1
ARM64 Morello GCC 10.1.2 Alpha 2
ARM64 msvc v19.14 (ex-WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 12.4.0
AVR gcc 12.5.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 13.3.0
AVR gcc 13.4.0
AVR gcc 14.1.0
AVR gcc 14.2.0
AVR gcc 14.3.0
AVR gcc 15.1.0
AVR gcc 15.2.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF clang 19.1.0
BPF clang 20.1.0
BPF clang 21.1.0
BPF gcc 13.1.0
BPF gcc 13.2.0
BPF gcc 13.3.0
BPF gcc 13.4.0
BPF gcc 14.1.0
BPF gcc 14.2.0
BPF gcc 14.3.0
BPF gcc 15.1.0
BPF gcc 15.2.0
BPF gcc trunk
C2Rust (master)
Chibicc 2020-12-07
FRC 2019
FRC 2020
FRC 2023
HPPA gcc 14.2.0
HPPA gcc 14.3.0
HPPA gcc 15.1.0
HPPA gcc 15.2.0
K1C gcc 7.4
K1C gcc 7.5
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
KVX ACB 5.0.0 (GCC 12.2.1)
KVX ACB 5.2.0 (GCC 13.2.1)
LC3 (trunk)
M68K clang (trunk)
M68K gcc 13.1.0
M68K gcc 13.2.0
M68K gcc 13.3.0
M68K gcc 13.4.0
M68K gcc 14.1.0
M68K gcc 14.2.0
M68K gcc 14.3.0
M68K gcc 15.1.0
M68K gcc 15.2.0
MRISC32 gcc (trunk)
MSP430 gcc 12.1.0
MSP430 gcc 12.2.0
MSP430 gcc 12.3.0
MSP430 gcc 12.4.0
MSP430 gcc 12.5.0
MSP430 gcc 13.1.0
MSP430 gcc 13.2.0
MSP430 gcc 13.3.0
MSP430 gcc 13.4.0
MSP430 gcc 14.1.0
MSP430 gcc 14.2.0
MSP430 gcc 14.3.0
MSP430 gcc 15.1.0
MSP430 gcc 15.2.0
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
MinGW gcc 14.3.0
MinGW gcc 15.2.0
ORCA/C 2.1.0
ORCA/C 2.2.0
ORCA/C 2.2.1
POWER64 gcc 11.2.0
POWER64 gcc 12.1.0
POWER64 gcc 12.2.0
POWER64 gcc 12.3.0
POWER64 gcc 12.4.0
POWER64 gcc 12.5.0
POWER64 gcc 13.1.0
POWER64 gcc 13.2.0
POWER64 gcc 13.3.0
POWER64 gcc 13.4.0
POWER64 gcc 14.1.0
POWER64 gcc 14.2.0
POWER64 gcc 14.3.0
POWER64 gcc 15.1.0
POWER64 gcc 15.2.0
POWER64 gcc trunk
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 12.4.0
RISC-V (32-bits) gcc 12.5.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 13.3.0
RISC-V (32-bits) gcc 13.4.0
RISC-V (32-bits) gcc 14.1.0
RISC-V (32-bits) gcc 14.2.0
RISC-V (32-bits) gcc 14.3.0
RISC-V (32-bits) gcc 15.1.0
RISC-V (32-bits) gcc 15.2.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 12.4.0
RISC-V (64-bits) gcc 12.5.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 13.3.0
RISC-V (64-bits) gcc 13.4.0
RISC-V (64-bits) gcc 14.1.0
RISC-V (64-bits) gcc 14.2.0
RISC-V (64-bits) gcc 14.3.0
RISC-V (64-bits) gcc 15.1.0
RISC-V (64-bits) gcc 15.2.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 19.1.0
RISC-V rv32gc clang 20.1.0
RISC-V rv32gc clang 21.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 19.1.0
RISC-V rv64gc clang 20.1.0
RISC-V rv64gc clang 21.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SDCC 4.0.0
SDCC 4.1.0
SDCC 4.2.0
SDCC 4.3.0
SDCC 4.4.0
SDCC 4.5.0
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 12.4.0
SPARC LEON gcc 12.5.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC LEON gcc 13.3.0
SPARC LEON gcc 13.4.0
SPARC LEON gcc 14.1.0
SPARC LEON gcc 14.2.0
SPARC LEON gcc 14.3.0
SPARC LEON gcc 15.1.0
SPARC LEON gcc 15.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 12.4.0
SPARC gcc 12.5.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC gcc 13.3.0
SPARC gcc 13.4.0
SPARC gcc 14.1.0
SPARC gcc 14.2.0
SPARC gcc 14.3.0
SPARC gcc 15.1.0
SPARC gcc 15.2.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 12.4.0
SPARC64 gcc 12.5.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
SPARC64 gcc 13.3.0
SPARC64 gcc 13.4.0
SPARC64 gcc 14.1.0
SPARC64 gcc 14.2.0
SPARC64 gcc 14.3.0
SPARC64 gcc 15.1.0
SPARC64 gcc 15.2.0
TCC (trunk)
TCC 0.9.27
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 12.4.0
TI C6x gcc 12.5.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI C6x gcc 13.3.0
TI C6x gcc 13.4.0
TI C6x gcc 14.1.0
TI C6x gcc 14.2.0
TI C6x gcc 14.3.0
TI C6x gcc 15.1.0
TI C6x gcc 15.2.0
TI CL430 21.6.1
Tricore gcc 11.3.0 (EEESlab)
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
VAX gcc NetBSDELF 12.4.0 (Apr 16 05:27 2025)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 14.2.0 (20241119)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 14.2.0 (20241119)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 14.2.0 (20241119)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.20 VS16.0
arm64 msvc v19.21 VS16.1
arm64 msvc v19.22 VS16.2
arm64 msvc v19.23 VS16.3
arm64 msvc v19.24 VS16.4
arm64 msvc v19.25 VS16.5
arm64 msvc v19.27 VS16.7
arm64 msvc v19.28 VS16.8
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30 VS17.0
arm64 msvc v19.31 VS17.1
arm64 msvc v19.32 VS17.2
arm64 msvc v19.33 VS17.3
arm64 msvc v19.34 VS17.4
arm64 msvc v19.35 VS17.5
arm64 msvc v19.36 VS17.6
arm64 msvc v19.37 VS17.7
arm64 msvc v19.38 VS17.8
arm64 msvc v19.39 VS17.9
arm64 msvc v19.40 VS17.10
arm64 msvc v19.41 VS17.11
arm64 msvc v19.42 VS17.12
arm64 msvc v19.43 VS17.13
arm64 msvc v19.44 VS17.14
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 12.0.0
armv7-a clang 12.0.1
armv7-a clang 13.0.0
armv7-a clang 13.0.1
armv7-a clang 14.0.0
armv7-a clang 15.0.0
armv7-a clang 16.0.0
armv7-a clang 17.0.1
armv7-a clang 18.1.0
armv7-a clang 19.1.0
armv7-a clang 20.1.0
armv7-a clang 21.1.0
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 12.0.1
armv8-a clang 13.0.0
armv8-a clang 13.0.1
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 19.1.0
armv8-a clang 20.1.0
armv8-a clang 21.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
clang 12 for DPU (rel 2023.2.0)
cproc-master
ez80-clang 15.0.0
ez80-clang 15.0.7
llvm-mos commander X16
llvm-mos commodore 64
llvm-mos mega65
llvm-mos nes-cnrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos osi-c1p
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 12.4.0
loongarch64 gcc 12.5.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
loongarch64 gcc 13.3.0
loongarch64 gcc 13.4.0
loongarch64 gcc 14.1.0
loongarch64 gcc 14.2.0
loongarch64 gcc 14.3.0
loongarch64 gcc 15.1.0
loongarch64 gcc 15.2.0
mips (el) gcc 12.1.0
mips (el) gcc 12.2.0
mips (el) gcc 12.3.0
mips (el) gcc 12.4.0
mips (el) gcc 12.5.0
mips (el) gcc 13.1.0
mips (el) gcc 13.2.0
mips (el) gcc 13.3.0
mips (el) gcc 13.4.0
mips (el) gcc 14.1.0
mips (el) gcc 14.2.0
mips (el) gcc 14.3.0
mips (el) gcc 15.1.0
mips (el) gcc 15.2.0
mips (el) gcc 4.9.4
mips (el) gcc 5.4
mips (el) gcc 5.5.0
mips (el) gcc 9.5.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips clang 19.1.0
mips clang 20.1.0
mips clang 21.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 12.4.0
mips gcc 12.5.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 13.3.0
mips gcc 13.4.0
mips gcc 14.1.0
mips gcc 14.2.0
mips gcc 14.3.0
mips gcc 15.1.0
mips gcc 15.2.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 12.4.0
mips64 (el) gcc 12.5.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 13.3.0
mips64 (el) gcc 13.4.0
mips64 (el) gcc 14.1.0
mips64 (el) gcc 14.2.0
mips64 (el) gcc 14.3.0
mips64 (el) gcc 15.1.0
mips64 (el) gcc 15.2.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 clang 19.1.0
mips64 clang 20.1.0
mips64 clang 21.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 12.4.0
mips64 gcc 12.5.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 13.3.0
mips64 gcc 13.4.0
mips64 gcc 14.1.0
mips64 gcc 14.2.0
mips64 gcc 14.3.0
mips64 gcc 15.1.0
mips64 gcc 15.2.0
mips64 gcc 4.9.4
mips64 gcc 5.4
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mips64el clang 19.1.0
mips64el clang 20.1.0
mips64el clang 21.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel clang 19.1.0
mipsel clang 20.1.0
mipsel clang 21.1.0
movfuscator (trunk)
nanoMIPS gcc 6.3.0
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 12.4.0
power gcc 12.5.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 13.3.0
power gcc 13.4.0
power gcc 14.1.0
power gcc 14.2.0
power gcc 14.3.0
power gcc 15.1.0
power gcc 15.2.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 12.4.0
power64le gcc 12.5.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 13.3.0
power64le gcc 13.4.0
power64le gcc 14.1.0
power64le gcc 14.2.0
power64le gcc 14.3.0
power64le gcc 15.1.0
power64le gcc 15.2.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
ppci 0.5.5
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 12.4.0
s390x gcc 12.5.0
s390x gcc 13.1.0
s390x gcc 13.2.0
s390x gcc 13.3.0
s390x gcc 13.4.0
s390x gcc 14.1.0
s390x gcc 14.2.0
s390x gcc 14.3.0
s390x gcc 15.1.0
s390x gcc 15.2.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 12.4.0
sh gcc 12.5.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 13.3.0
sh gcc 13.4.0
sh gcc 14.1.0
sh gcc 14.2.0
sh gcc 14.3.0
sh gcc 15.1.0
sh gcc 15.2.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (ex-WINE)
x64 msvc v19.10 (ex-WINE)
x64 msvc v19.14 (ex-WINE)
x64 msvc v19.20 VS16.0
x64 msvc v19.21 VS16.1
x64 msvc v19.22 VS16.2
x64 msvc v19.23 VS16.3
x64 msvc v19.24 VS16.4
x64 msvc v19.25 VS16.5
x64 msvc v19.27 VS16.7
x64 msvc v19.28 VS16.8
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30 VS17.0
x64 msvc v19.31 VS17.1
x64 msvc v19.32 VS17.2
x64 msvc v19.33 VS17.3
x64 msvc v19.34 VS17.4
x64 msvc v19.35 VS17.5
x64 msvc v19.36 VS17.6
x64 msvc v19.37 VS17.7
x64 msvc v19.38 VS17.8
x64 msvc v19.39 VS17.9
x64 msvc v19.40 VS17.10
x64 msvc v19.41 VS17.11
x64 msvc v19.42 VS17.12
x64 msvc v19.43 VS17.13
x64 msvc v19.44 VS17.14
x64 msvc v19.latest
x86 CompCert 3.10
x86 CompCert 3.11
x86 CompCert 3.12
x86 CompCert 3.9
x86 gcc 1.27
x86 msvc v19.0 (ex-WINE)
x86 msvc v19.10 (ex-WINE)
x86 msvc v19.14 (ex-WINE)
x86 msvc v19.20 VS16.0
x86 msvc v19.21 VS16.1
x86 msvc v19.22 VS16.2
x86 msvc v19.23 VS16.3
x86 msvc v19.24 VS16.4
x86 msvc v19.25 VS16.5
x86 msvc v19.27 VS16.7
x86 msvc v19.28 VS16.8
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30 VS17.0
x86 msvc v19.31 VS17.1
x86 msvc v19.32 VS17.2
x86 msvc v19.33 VS17.3
x86 msvc v19.34 VS17.4
x86 msvc v19.35 VS17.5
x86 msvc v19.36 VS17.6
x86 msvc v19.37 VS17.7
x86 msvc v19.38 VS17.8
x86 msvc v19.39 VS17.9
x86 msvc v19.40 VS17.10
x86 msvc v19.41 VS17.11
x86 msvc v19.42 VS17.12
x86 msvc v19.43 VS17.13
x86 msvc v19.44 VS17.14
x86 msvc v19.latest
x86 nvc 24.11
x86 nvc 24.9
x86 nvc 25.1
x86 nvc 25.11
x86 nvc 25.3
x86 nvc 25.5
x86 nvc 25.7
x86 nvc 25.9
x86 tendra (trunk)
x86-64 clang (assertions trunk)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 15.0.0
x86-64 clang 16.0.0
x86-64 clang 17.0.1
x86-64 clang 18.1.0
x86-64 clang 19.1.0
x86-64 clang 20.1.0
x86-64 clang 21.1.0
x86-64 clang 3.0.0
x86-64 clang 3.1
x86-64 clang 3.2
x86-64 clang 3.3
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.7
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.1
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.3 (assertions)
x86-64 gcc 10.4
x86-64 gcc 10.4 (assertions)
x86-64 gcc 10.5
x86-64 gcc 10.5 (assertions)
x86-64 gcc 11.1
x86-64 gcc 11.1 (assertions)
x86-64 gcc 11.2
x86-64 gcc 11.2 (assertions)
x86-64 gcc 11.3
x86-64 gcc 11.3 (assertions)
x86-64 gcc 11.4
x86-64 gcc 11.4 (assertions)
x86-64 gcc 12.1
x86-64 gcc 12.1 (assertions)
x86-64 gcc 12.2
x86-64 gcc 12.2 (assertions)
x86-64 gcc 12.3
x86-64 gcc 12.3 (assertions)
x86-64 gcc 12.4
x86-64 gcc 12.4 (assertions)
x86-64 gcc 12.5
x86-64 gcc 12.5 (assertions)
x86-64 gcc 13.1
x86-64 gcc 13.1 (assertions)
x86-64 gcc 13.2
x86-64 gcc 13.2 (assertions)
x86-64 gcc 13.3
x86-64 gcc 13.3 (assertions)
x86-64 gcc 13.4
x86-64 gcc 13.4 (assertions)
x86-64 gcc 14.1
x86-64 gcc 14.1 (assertions)
x86-64 gcc 14.2
x86-64 gcc 14.2 (assertions)
x86-64 gcc 14.3
x86-64 gcc 14.3 (assertions)
x86-64 gcc 15.1
x86-64 gcc 15.1 (assertions)
x86-64 gcc 15.2
x86-64 gcc 15.2 (assertions)
x86-64 gcc 3.4.6
x86-64 gcc 4.0.4
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.5
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx (latest)
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2024.0.0
x86_64 CompCert 3.10
x86_64 CompCert 3.11
x86_64 CompCert 3.12
x86_64 CompCert 3.9
z180-clang 15.0.0
z180-clang 15.0.7
z80-clang 15.0.0
z80-clang 15.0.7
z88dk 2.2
zig cc 0.10.0
zig cc 0.11.0
zig cc 0.12.0
zig cc 0.12.1
zig cc 0.13.0
zig cc 0.14.0
zig cc 0.14.1
zig cc 0.15.1
zig cc 0.15.2
zig cc 0.6.0
zig cc 0.7.0
zig cc 0.7.1
zig cc 0.8.0
zig cc 0.9.0
zig cc trunk
Options
Source code
/* C89 compatible atomics. Choice of public domain or MIT-0. See license statements at the end of this file. David Reid - mackron@gmail.com */ /* Introduction ============ This library aims to implement an equivalent to the C11 atomics library. It's intended to be used as a way to enable the use of atomics in a mostly consistent manner to modern C, while still enabling compatibility with older compilers. This is *not* a drop-in replacement for C11 atomics, but is very similar. Only limited testing has been done so use at your own risk. I'm happy to accept feedback and pull requests with bug fixes. When compiling with GCC and Clang, this library will translate to a one-to-one wrapper around the __atomic_* intrinsics provided by the compiler. When compiling with Visual C++ things are a bit more complicated because it does not have support for C11 style atomic intrinsics. This library will try to use the _Interlocked* intrinsics instead, and if unavailable will use inlined assembly (x86 only). Supported compilers are Visual Studio back to VC6, GCC and Clang. If you need support for a different compiler I'm happy to add support (pull requests appreciated). This library currently assumes the `int` data type is 32 bits. Differences With C11 -------------------- For practicality, this is not a drop-in replacement for C11's `stdthread.h`. Below are the main differences between c89thread and stdthread. * All operations require an explicit size which is specified by the name of the function, and only 8-, 16-, 32- and 64-bit operations are supported. Objects of an arbitrary sizes are not supported. * Some extra APIs are included: - `c89atomic_compare_and_swap_*()` - `c89atomic_test_and_set_*()` - `c89atomic_clear_*()` * All APIs are namespaced with `c89`. * `c89atomic_*` data types are undecorated. Compare Exchange ---------------- This library implements a simple compare-and-swap function called `c89atomic_compare_and_swap_*()` which is slightly different to C11's `atomic_compare_exchange_*()`. This is named differently to distinguish between the two. `c89atomic_compare_and_swap_*()` returns the old value as the return value, whereas `atomic_compare_exchange_*()` will return it through a parameter and supports explicit memory orders for success and failure cases. With Visual Studio and versions of GCC earlier than 4.7, an implementation of `atomic_compare_exchange_*()` is included which is implemented in terms of `c89atomic_compare_and_swap_*()`, but there's subtle details to be aware of with this implementation. Note that the following only applies for Visual Studio and versions of GCC earlier than 4.7. Later versions of GCC and Clang use the `__atomic_compare_exchange_n()` intrinsic directly and are not subject to the following. Below is the 32-bit implementation of `c89atomic_compare_exchange_strong_explicit_32()` which is implemented the same for the weak versions and other sizes, and only for Visual Studio and old versions of GCC (prior to 4.7): ```c c89atomic_bool c89atomic_compare_exchange_strong_explicit_32(volatile c89atomic_uint32* dst, volatile c89atomic_uint32* expected, c89atomic_uint32 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { c89atomic_uint32 expectedValue; c89atomic_uint32 result; expectedValue = c89atomic_load_explicit_32(expected, c89atomic_memory_order_seq_cst); result = c89atomic_compare_and_swap_32(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { c89atomic_store_explicit_32(expected, result, failureOrder); return 0; } } ``` The call to `c89atomic_store_explicit_32()` is not atomic with respect to the main compare-and-swap operation which may cause problems when `expected` points to memory that is shared between threads. This only becomes an issue if `expected` can be accessed from multiple threads at the same time which for the most part will never happen because a compare-and-swap will almost always be used in a loop with a local variable being used for the expected value. If the above is a concern, you should consider reworking your code to use `c89atomic_compare_and_swap_*()` directly, which is atomic and more efficient. Alternatively you'll need to use a lock to synchronize access to `expected`, upgrade your compiler, or use a different library. Types and Functions ------------------- The following types and functions are implemented: +-----------------------------------------+-----------------------------------------------+ | C11 Atomics | C89 Atomics | +-----------------------------------------+-----------------------------------------------+ | #include <stdatomic.h> | #include "c89atomic.h" | +-----------------------------------------+-----------------------------------------------+ | memory_order | c89atomic_memory_order | | memory_order_relaxed | c89atomic_memory_order_relaxed | | memory_order_consume | c89atomic_memory_order_consume | | memory_order_acquire | c89atomic_memory_order_acquire | | memory_order_release | c89atomic_memory_order_release | | memory_order_acq_rel | c89atomic_memory_order_acq_rel | | memory_order_seq_cst | c89atomic_memory_order_seq_cst | +-----------------------------------------+-----------------------------------------------+ | atomic_flag | c89atomic_flag | | atomic_bool | c89atomic_bool | | atomic_int8 | c89atomic_int8 | | atomic_uint8 | c89atomic_uint8 | | atomic_int16 | c89atomic_int16 | | atomic_uint16 | c89atomic_uint16 | | atomic_int32 | c89atomic_int32 | | atomic_uint32 | c89atomic_uint32 | | atomic_int64 | c89atomic_int64 | | atomic_uint64 | c89atomic_uint64 | +-----------------------------------------+-----------------------------------------------+ | atomic_flag_test_and_set | c89atomic_flag_test_and_set | | atomic_flag_test_and_set_explicit | c89atomic_flag_test_and_set_explicit | | | c89atomic_test_and_set_8 | | | c89atomic_test_and_set_16 | | | c89atomic_test_and_set_32 | | | c89atomic_test_and_set_64 | | | c89atomic_test_and_set_explicit_8 | | | c89atomic_test_and_set_explicit_16 | | | c89atomic_test_and_set_explicit_32 | | | c89atomic_test_and_set_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_flag_clear | c89atomic_flag_clear | | atomic_flag_clear_explicit | c89atomic_flag_clear_explicit | | | c89atomic_clear_8 | | | c89atomic_clear_16 | | | c89atomic_clear_32 | | | c89atomic_clear_64 | | | c89atomic_clear_explicit_8 | | | c89atomic_clear_explicit_16 | | | c89atomic_clear_explicit_32 | | | c89atomic_clear_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_store | c89atomic_store_8 | | atomic_store_explicit | c89atomic_store_16 | | | c89atomic_store_32 | | | c89atomic_store_64 | | | c89atomic_store_explicit_8 | | | c89atomic_store_explicit_16 | | | c89atomic_store_explicit_32 | | | c89atomic_store_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_load | c89atomic_load_8 | | atomic_load_explicit | c89atomic_load_16 | | | c89atomic_load_32 | | | c89atomic_load_64 | | | c89atomic_load_explicit_8 | | | c89atomic_load_explicit_16 | | | c89atomic_load_explicit_32 | | | c89atomic_load_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_exchange | c89atomic_exchange_8 | | atomic_exchange_explicit | c89atomic_exchange_16 | | | c89atomic_exchange_32 | | | c89atomic_exchange_64 | | | c89atomic_exchange_explicit_8 | | | c89atomic_exchange_explicit_16 | | | c89atomic_exchange_explicit_32 | | | c89atomic_exchange_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_compare_exchange_weak | c89atomic_compare_exchange_weak_8 | | atomic_compare_exchange_weak_explicit | c89atomic_compare_exchange_weak_16 | | atomic_compare_exchange_strong | c89atomic_compare_exchange_weak_32 | | atomic_compare_exchange_strong_explicit | c89atomic_compare_exchange_weak_64 | | | c89atomic_compare_exchange_weak_explicit_8 | | | c89atomic_compare_exchange_weak_explicit_16 | | | c89atomic_compare_exchange_weak_explicit_32 | | | c89atomic_compare_exchange_weak_explicit_64 | | | c89atomic_compare_exchange_strong_8 | | | c89atomic_compare_exchange_strong_16 | | | c89atomic_compare_exchange_strong_32 | | | c89atomic_compare_exchange_strong_64 | | | c89atomic_compare_exchange_strong_explicit_8 | | | c89atomic_compare_exchange_strong_explicit_16 | | | c89atomic_compare_exchange_strong_explicit_32 | | | c89atomic_compare_exchange_strong_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_fetch_add | c89atomic_fetch_add_8 | | atomic_fetch_add_explicit | c89atomic_fetch_add_16 | | | c89atomic_fetch_add_32 | | | c89atomic_fetch_add_64 | | | c89atomic_fetch_add_explicit_8 | | | c89atomic_fetch_add_explicit_16 | | | c89atomic_fetch_add_explicit_32 | | | c89atomic_fetch_add_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_fetch_sub | c89atomic_fetch_sub_8 | | atomic_fetch_sub_explicit | c89atomic_fetch_sub_16 | | | c89atomic_fetch_sub_32 | | | c89atomic_fetch_sub_64 | | | c89atomic_fetch_sub_explicit_8 | | | c89atomic_fetch_sub_explicit_16 | | | c89atomic_fetch_sub_explicit_32 | | | c89atomic_fetch_sub_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_fetch_or | c89atomic_fetch_or_8 | | atomic_fetch_or_explicit | c89atomic_fetch_or_16 | | | c89atomic_fetch_or_32 | | | c89atomic_fetch_or_64 | | | c89atomic_fetch_or_explicit_8 | | | c89atomic_fetch_or_explicit_16 | | | c89atomic_fetch_or_explicit_32 | | | c89atomic_fetch_or_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_fetch_xor | c89atomic_fetch_xor_8 | | atomic_fetch_xor_explicit | c89atomic_fetch_xor_16 | | | c89atomic_fetch_xor_32 | | | c89atomic_fetch_xor_64 | | | c89atomic_fetch_xor_explicit_8 | | | c89atomic_fetch_xor_explicit_16 | | | c89atomic_fetch_xor_explicit_32 | | | c89atomic_fetch_xor_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_fetch_and | c89atomic_fetch_and_8 | | atomic_fetch_and_explicit | c89atomic_fetch_and_16 | | | c89atomic_fetch_and_32 | | | c89atomic_fetch_and_64 | | | c89atomic_fetch_and_explicit_8 | | | c89atomic_fetch_and_explicit_16 | | | c89atomic_fetch_and_explicit_32 | | | c89atomic_fetch_and_explicit_64 | +-----------------------------------------+-----------------------------------------------+ | atomic_thread_fence() | c89atomic_thread_fence | | atomic_signal_fence() | c89atomic_signal_fence | +-----------------------------------------+-----------------------------------------------+ | atomic_is_lock_free | c89atomic_is_lock_free_8 | | | c89atomic_is_lock_free_16 | | | c89atomic_is_lock_free_32 | | | c89atomic_is_lock_free_64 | +-----------------------------------------+-----------------------------------------------+ | (Not Defined) | c89atomic_compare_and_swap_8 | | | c89atomic_compare_and_swap_16 | | | c89atomic_compare_and_swap_32 | | | c89atomic_compare_and_swap_64 | | | c89atomic_compare_and_swap_ptr | | | c89atomic_compiler_fence | +-----------------------------------------+-----------------------------------------------+ */ #ifndef c89atomic_h #define c89atomic_h #if defined(__cplusplus) extern "C" { #endif typedef signed char c89atomic_int8; typedef unsigned char c89atomic_uint8; typedef signed short c89atomic_int16; typedef unsigned short c89atomic_uint16; typedef signed int c89atomic_int32; typedef unsigned int c89atomic_uint32; #if defined(_MSC_VER) typedef signed __int64 c89atomic_int64; typedef unsigned __int64 c89atomic_uint64; #else #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wlong-long" #if defined(__clang__) #pragma GCC diagnostic ignored "-Wc++11-long-long" #endif #endif typedef signed long long c89atomic_int64; typedef unsigned long long c89atomic_uint64; #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #pragma GCC diagnostic pop #endif #endif typedef int c89atomic_memory_order; typedef unsigned char c89atomic_bool; typedef unsigned char c89atomic_flag; /* Architecture Detection */ #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT) #ifdef _WIN32 #ifdef _WIN64 #define C89ATOMIC_64BIT #else #define C89ATOMIC_32BIT #endif #endif #endif #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT) #ifdef __GNUC__ #ifdef __LP64__ #define C89ATOMIC_64BIT #else #define C89ATOMIC_32BIT #endif #endif #endif #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT) #include <stdint.h> #if INTPTR_MAX == INT64_MAX #define C89ATOMIC_64BIT #else #define C89ATOMIC_32BIT #endif #endif #if defined(__x86_64__) || defined(_M_X64) #define C89ATOMIC_X64 #elif defined(__i386) || defined(_M_IX86) #define C89ATOMIC_X86 #elif defined(__arm__) || defined(_M_ARM) #define C89ATOMIC_ARM #endif /* We want to encourage the compiler to inline. When adding support for a new compiler, make sure it's handled here. */ #if defined(_MSC_VER) #define C89ATOMIC_INLINE __forceinline #elif defined(__GNUC__) /* I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) #define C89ATOMIC_INLINE __inline__ __attribute__((always_inline)) #else #define C89ATOMIC_INLINE inline __attribute__((always_inline)) #endif #elif defined(__WATCOMC__) || defined(__DMC__) #define C89ATOMIC_INLINE __inline #else #define C89ATOMIC_INLINE #endif #if (defined(_MSC_VER) /*&& !defined(__clang__)*/) || defined(__WATCOMC__) || defined(__DMC__) /* Visual C++. */ #define c89atomic_memory_order_relaxed 0 #define c89atomic_memory_order_consume 1 #define c89atomic_memory_order_acquire 2 #define c89atomic_memory_order_release 3 #define c89atomic_memory_order_acq_rel 4 #define c89atomic_memory_order_seq_cst 5 /* Visual Studio 2003 and earlier have no support for sized atomic operations. We'll need to use inlined assembly for these compilers. */ #if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */ /* New Visual C++. These functions don't use the `order` parameter, so in order to avoid warnings about unused parameters we need to implement these as functions. */ #include <intrin.h> static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return (c89atomic_uint8)_InterlockedExchange8((volatile char*)dst, (char)src); } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return (c89atomic_uint16)_InterlockedExchange16((volatile short*)dst, (short)src); } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return (c89atomic_uint32)_InterlockedExchange((volatile long*)dst, (long)src); } #if defined(C89ATOMIC_64BIT) static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return (c89atomic_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); } #endif static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return (c89atomic_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return (c89atomic_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return (c89atomic_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); } #if defined(C89ATOMIC_64BIT) static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return (c89atomic_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); } #endif #define c89atomic_compare_and_swap_8( dst, expected, desired) (c89atomic_uint8 )_InterlockedCompareExchange8 ((volatile char* )dst, (char )desired, (char )expected) #define c89atomic_compare_and_swap_16(dst, expected, desired) (c89atomic_uint16)_InterlockedCompareExchange16((volatile short* )dst, (short )desired, (short )expected) #define c89atomic_compare_and_swap_32(dst, expected, desired) (c89atomic_uint32)_InterlockedCompareExchange ((volatile long* )dst, (long )desired, (long )expected) #define c89atomic_compare_and_swap_64(dst, expected, desired) (c89atomic_uint64)_InterlockedCompareExchange64((volatile long long*)dst, (long long)desired, (long long)expected) /* Can't use MemoryBarrier() for this as it require Windows headers which we want to avoid in the header. */ #if defined(C89ATOMIC_X64) #define c89atomic_thread_fence(order) __faststorefence(), (void)order #else static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order) { volatile c89atomic_uint32 barrier = 0; (void)order; c89atomic_fetch_add_explicit_32(&barrier, 0, order); } #endif /* C89ATOMIC_X64 */ #else /* Old Visual C++, Digital Mars and OpenWatcom. */ #if defined(C89ATOMIC_X86) /* x86. Implemented via inlined assembly. This supports both MSVC, Digital Mars and OpenWatcom. OpenWatcom is a little bit too pedantic with it's warnings. A few notes: - The return value of these functions are defined by the AL/AX/EAX/EAX:EDX registers which means an explicit return statement is not actually necessary. This is helpful for performance reasons because it means we can avoid the cost of a declaring a local variable and moving the value in EAX into that variable, only to then return it. However, unfortunately OpenWatcom thinks this is a mistake and tries to be helpful by throwing a warning. To work around we're going to declare a "result" variable and incur this theoretical cost. - Variables that are assigned within the inline assembly will not be detected as such, and OpenWatcom will throw a warning about the variable being used without being assigned. To work around this we just initialize our local variables to 0. */ /* thread_fence() */ static C89ATOMIC_INLINE void __stdcall c89atomic_thread_fence(c89atomic_memory_order order) { (void)order; __asm { lock add [esp], 0 } } /* exchange() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { c89atomic_uint8 result = 0; (void)order; __asm { mov ecx, dst mov al, src lock xchg [ecx], al mov result, al } return result; } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { c89atomic_uint16 result = 0; (void)order; __asm { mov ecx, dst mov ax, src lock xchg [ecx], ax mov result, ax } return result; } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { c89atomic_uint32 result = 0; (void)order; __asm { mov ecx, dst mov eax, src lock xchg [ecx], eax mov result, eax } return result; } /* fetch_add() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { c89atomic_uint8 result = 0; (void)order; __asm { mov ecx, dst mov al, src lock xadd [ecx], al mov result, al } return result; } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { c89atomic_uint16 result = 0; (void)order; __asm { mov ecx, dst mov ax, src lock xadd [ecx], ax mov result, ax } return result; } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { c89atomic_uint32 result = 0; (void)order; __asm { mov ecx, dst mov eax, src lock xadd [ecx], eax mov result, eax } return result; } /* compare_and_swap() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired) { c89atomic_uint8 result = 0; __asm { mov ecx, dst mov al, expected mov dl, desired lock cmpxchg [ecx], dl /* Writes to EAX which MSVC will treat as the return value. */ mov result, al } return result; } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired) { c89atomic_uint16 result = 0; __asm { mov ecx, dst mov ax, expected mov dx, desired lock cmpxchg [ecx], dx /* Writes to EAX which MSVC will treat as the return value. */ mov result, ax } return result; } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired) { c89atomic_uint32 result = 0; __asm { mov ecx, dst mov eax, expected mov edx, desired lock cmpxchg [ecx], edx /* Writes to EAX which MSVC will treat as the return value. */ mov result, eax } return result; } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired) { c89atomic_uint32 resultEAX = 0; c89atomic_uint32 resultEDX = 0; __asm { mov esi, dst /* From Microsoft documentation: "... you don't need to preserve the EAX, EBX, ECX, EDX, ESI, or EDI registers." Choosing ESI since it's the next available one in their list. */ mov eax, dword ptr expected mov edx, dword ptr expected + 4 mov ebx, dword ptr desired mov ecx, dword ptr desired + 4 lock cmpxchg8b qword ptr [esi] /* Writes to EAX:EDX which MSVC will treat as the return value. */ mov resultEAX, eax mov resultEDX, edx } return ((c89atomic_uint64)resultEDX << 32) | resultEAX; } #else /* x64 or ARM. Should never get here because these are not valid targets for older versions of Visual Studio. */ #error Unsupported architecture. #endif #endif /* I'm not sure how to implement a compiler barrier for old MSVC so I'm just making it a thread_fence() and hopefully the compiler will see the volatile and not do any reshuffling. If anybody has a better idea on this please let me know! Cannot use _ReadWriteBarrier() as it has been marked as deprecated. */ #define c89atomic_compiler_fence() c89atomic_thread_fence(c89atomic_memory_order_seq_cst) /* I'm not sure how to implement this for MSVC. For now just using thread_fence(). */ #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) /* Atomic loads can be implemented in terms of a compare-and-swap. Need to implement as functions to silence warnings about `order` being unused. */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return c89atomic_compare_and_swap_8(ptr, 0, 0); } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return c89atomic_compare_and_swap_16(ptr, 0, 0); } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return c89atomic_compare_and_swap_32(ptr, 0, 0); } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return c89atomic_compare_and_swap_64(ptr, 0, 0); } /* atomic_store() is the same as atomic_exchange() but returns void. */ #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order) #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order) #define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order) #define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order) /* Some 64-bit atomic operations are not supported by MSVC when compiling in 32-bit mode.*/ #if defined(C89ATOMIC_32BIT) static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; do { oldValue = *dst; } while (c89atomic_compare_and_swap_64(dst, oldValue, src) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue + src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #endif /* fetch_sub() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 oldValue; volatile c89atomic_uint8 newValue; do { oldValue = *dst; newValue = (c89atomic_uint8)(oldValue - src); } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; volatile c89atomic_uint16 newValue; do { oldValue = *dst; newValue = (c89atomic_uint16)(oldValue - src); } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; volatile c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue - src; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue - src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } /* fetch_and() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 oldValue; volatile c89atomic_uint8 newValue; do { oldValue = *dst; newValue = (c89atomic_uint8)(oldValue & src); } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; volatile c89atomic_uint16 newValue; do { oldValue = *dst; newValue = (c89atomic_uint16)(oldValue & src); } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; volatile c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue & src; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue & src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } /* fetch_xor() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 oldValue; volatile c89atomic_uint8 newValue; do { oldValue = *dst; newValue = (c89atomic_uint8)(oldValue ^ src); } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; volatile c89atomic_uint16 newValue; do { oldValue = *dst; newValue = (c89atomic_uint16)(oldValue ^ src); } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; volatile c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue ^ src; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue ^ src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } /* fetch_or() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 oldValue; volatile c89atomic_uint8 newValue; do { oldValue = *dst; newValue = (c89atomic_uint8)(oldValue | src); } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; volatile c89atomic_uint16 newValue; do { oldValue = *dst; newValue = (c89atomic_uint16)(oldValue | src); } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; volatile c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue | src; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue | src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #define c89atomic_test_and_set_explicit_8( dst, order) c89atomic_exchange_explicit_8 (dst, 1, order) #define c89atomic_test_and_set_explicit_16(dst, order) c89atomic_exchange_explicit_16(dst, 1, order) #define c89atomic_test_and_set_explicit_32(dst, order) c89atomic_exchange_explicit_32(dst, 1, order) #define c89atomic_test_and_set_explicit_64(dst, order) c89atomic_exchange_explicit_64(dst, 1, order) #define c89atomic_clear_explicit_8( dst, order) c89atomic_store_explicit_8 (dst, 0, order) #define c89atomic_clear_explicit_16(dst, order) c89atomic_store_explicit_16(dst, 0, order) #define c89atomic_clear_explicit_32(dst, order) c89atomic_store_explicit_32(dst, 0, order) #define c89atomic_clear_explicit_64(dst, order) c89atomic_store_explicit_64(dst, 0, order) #define c89atomic_flag_test_and_set_explicit(ptr, order) (c89atomic_flag)c89atomic_test_and_set_explicit_8(ptr, order) #define c89atomic_flag_clear_explicit(ptr, order) c89atomic_clear_explicit_8(ptr, order) #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) /* Modern GCC atomic built-ins. */ #define C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE #define C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE #define c89atomic_memory_order_relaxed __ATOMIC_RELAXED #define c89atomic_memory_order_consume __ATOMIC_CONSUME #define c89atomic_memory_order_acquire __ATOMIC_ACQUIRE #define c89atomic_memory_order_release __ATOMIC_RELEASE #define c89atomic_memory_order_acq_rel __ATOMIC_ACQ_REL #define c89atomic_memory_order_seq_cst __ATOMIC_SEQ_CST #define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory") #define c89atomic_thread_fence(order) __atomic_thread_fence(order) #define c89atomic_signal_fence(order) __atomic_signal_fence(order) #define c89atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr) #define c89atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr) #define c89atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr) #define c89atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr) #define c89atomic_flag_test_and_set_explicit(dst, order) (c89atomic_flag)__atomic_test_and_set(dst, order) #define c89atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order) #define c89atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order) #define c89atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order) #define c89atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order) #define c89atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order) #define c89atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order) #define c89atomic_clear_explicit_16(dst, order) __atomic_store_n(dst, 0, order) #define c89atomic_clear_explicit_32(dst, order) __atomic_store_n(dst, 0, order) #define c89atomic_clear_explicit_64(dst, order) __atomic_store_n(dst, 0, order) #define c89atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order) #define c89atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order) #define c89atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order) #define c89atomic_store_explicit_64(dst, src, order) __atomic_store_n(dst, src, order) #define c89atomic_load_explicit_8( dst, order) __atomic_load_n(dst, order) #define c89atomic_load_explicit_16(dst, order) __atomic_load_n(dst, order) #define c89atomic_load_explicit_32(dst, order) __atomic_load_n(dst, order) #define c89atomic_load_explicit_64(dst, order) __atomic_load_n(dst, order) #define c89atomic_exchange_explicit_8( dst, src, order) __atomic_exchange_n(dst, src, order) #define c89atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order) #define c89atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order) #define c89atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order) #define c89atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) #define c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) #define c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) #define c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) #define c89atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order) #define c89atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order) #define c89atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order) #define c89atomic_fetch_add_explicit_64(dst, src, order) __atomic_fetch_add(dst, src, order) #define c89atomic_fetch_sub_explicit_8( dst, src, order) __atomic_fetch_sub(dst, src, order) #define c89atomic_fetch_sub_explicit_16(dst, src, order) __atomic_fetch_sub(dst, src, order) #define c89atomic_fetch_sub_explicit_32(dst, src, order) __atomic_fetch_sub(dst, src, order) #define c89atomic_fetch_sub_explicit_64(dst, src, order) __atomic_fetch_sub(dst, src, order) #define c89atomic_fetch_or_explicit_8( dst, src, order) __atomic_fetch_or(dst, src, order) #define c89atomic_fetch_or_explicit_16(dst, src, order) __atomic_fetch_or(dst, src, order) #define c89atomic_fetch_or_explicit_32(dst, src, order) __atomic_fetch_or(dst, src, order) #define c89atomic_fetch_or_explicit_64(dst, src, order) __atomic_fetch_or(dst, src, order) #define c89atomic_fetch_xor_explicit_8( dst, src, order) __atomic_fetch_xor(dst, src, order) #define c89atomic_fetch_xor_explicit_16(dst, src, order) __atomic_fetch_xor(dst, src, order) #define c89atomic_fetch_xor_explicit_32(dst, src, order) __atomic_fetch_xor(dst, src, order) #define c89atomic_fetch_xor_explicit_64(dst, src, order) __atomic_fetch_xor(dst, src, order) #define c89atomic_fetch_and_explicit_8( dst, src, order) __atomic_fetch_and(dst, src, order) #define c89atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order) #define c89atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order) #define c89atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order) #define c89atomic_compare_and_swap_8 (dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #define c89atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #define c89atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #define c89atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #else /* GCC and compilers supporting GCC-style inlined assembly. */ #define c89atomic_memory_order_relaxed 1 #define c89atomic_memory_order_consume 2 #define c89atomic_memory_order_acquire 3 #define c89atomic_memory_order_release 4 #define c89atomic_memory_order_acq_rel 5 #define c89atomic_memory_order_seq_cst 6 #define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory") #if defined(__GNUC__) /* Legacy GCC atomic built-ins. Everything is a full memory barrier. */ #define c89atomic_thread_fence(order) __sync_synchronize(), (void)order /* exchange() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { if (order > c89atomic_memory_order_acquire) { __sync_synchronize(); } return __sync_lock_test_and_set(dst, src); } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; do { oldValue = *dst; } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; do { oldValue = *dst; } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; do { oldValue = *dst; } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); (void)order; return oldValue; } /* fetch_add() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_add(dst, src); } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_add(dst, src); } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_add(dst, src); } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_add(dst, src); } /* fetch_sub() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_sub(dst, src); } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_sub(dst, src); } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_sub(dst, src); } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_sub(dst, src); } /* fetch_or() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_or(dst, src); } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_or(dst, src); } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_or(dst, src); } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_or(dst, src); } /* fetch_xor() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_xor(dst, src); } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_xor(dst, src); } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_xor(dst, src); } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_xor(dst, src); } /* fetch_and() */ static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_and(dst, src); } static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_and(dst, src); } static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_and(dst, src); } static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { (void)order; return __sync_fetch_and_and(dst, src); } #define c89atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #define c89atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #define c89atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #define c89atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #else /* Non-GCC compilers supporting GCC-style inlined assembly. The inlined assembly below uses Gas syntax. */ /* It's actually kind of confusing as to the best way to implement a memory barrier on x86/64. From my quick research, it looks like there's a few options: - SFENCE/LFENCE/MFENCE - LOCK ADD - XCHG (with a memory operand, not two register operands) It looks like the SFENCE instruction was added in the Pentium III series, whereas the LFENCE and MFENCE instructions were added in the Pentium 4 series. It's not clear how this actually differs to a LOCK-prefixed instruction or an XCHG instruction with a memory operand. For simplicity and compatibility, I'm just using a LOCK-prefixed ADD instruction which adds 0 to the value pointed to by the ESP register. The use of the ESP register is that it should theoretically have a high likelyhood to be in cache. For now, just to keep things simple, this is always doing a full memory barrier which means the `order` parameter is ignored on x86/64. I want a thread fence to also act as a compiler fence, so therefore I'm forcing this to be inlined by implementing it as a define. */ #if defined(C89ATOMIC_X86) #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc") #elif defined(C89ATOMIC_X64) #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc") #else #error Unsupported architecture. Please submit a feature request. #endif /* compare_and_swap() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired) { volatile c89atomic_uint8 result; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired) { volatile c89atomic_uint16 result; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired) { volatile c89atomic_uint32 result; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired) { volatile c89atomic_uint64 result; #if defined(C89ATOMIC_X86) /* We can't use the standard CMPXCHG here because x86 does not support it with 64-bit values. We need to instead use CMPXCHG8B which is a bit harder to use. The annoying part with this is the use of the -fPIC compiler switch which requires the EBX register never be modified. The problem is that CMPXCHG8B requires us to write our desired value to it. I'm resolving this by just pushing and popping the EBX register manually. */ volatile c89atomic_uint32 resultEAX; volatile c89atomic_uint32 resultEDX; __asm__ __volatile__("push %%ebx; xchg %5, %%ebx; lock; cmpxchg8b %0; pop %%ebx" : "+m"(*dst), "=a"(resultEAX), "=d"(resultEDX) : "a"(expected & 0xFFFFFFFF), "d"(expected >> 32), "r"(desired & 0xFFFFFFFF), "c"(desired >> 32) : "cc"); result = ((c89atomic_uint64)resultEDX << 32) | resultEAX; #elif defined(C89ATOMIC_X64) __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } /* exchange() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 result = 0; (void)order; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 result = 0; (void)order; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 result; (void)order; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 result; (void)order; #if defined(C89ATOMIC_X86) do { result = *dst; } while (c89atomic_compare_and_swap_64(dst, result, src) != result); #elif defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } /* fetch_add() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { c89atomic_uint8 result; (void)order; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { c89atomic_uint16 result; (void)order; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { c89atomic_uint32 result; (void)order; #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); #else #error Unsupported architecture. Please submit a feature request. #endif return result; } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { #if defined(C89ATOMIC_X86) volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; (void)order; do { oldValue = *dst; newValue = oldValue + src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); return oldValue; #elif defined(C89ATOMIC_X64) volatile c89atomic_uint64 result; (void)order; __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); return result; #endif } /* fetch_sub() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 oldValue; volatile c89atomic_uint8 newValue; do { oldValue = *dst; newValue = (c89atomic_uint8)(oldValue - src); } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; volatile c89atomic_uint16 newValue; do { oldValue = *dst; newValue = (c89atomic_uint16)(oldValue - src); } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; volatile c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue - src; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue - src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } /* fetch_and() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 oldValue; volatile c89atomic_uint8 newValue; do { oldValue = *dst; newValue = (c89atomic_uint8)(oldValue & src); } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; volatile c89atomic_uint16 newValue; do { oldValue = *dst; newValue = (c89atomic_uint16)(oldValue & src); } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; volatile c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue & src; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue & src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } /* fetch_xor() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 oldValue; volatile c89atomic_uint8 newValue; do { oldValue = *dst; newValue = (c89atomic_uint8)(oldValue ^ src); } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; volatile c89atomic_uint16 newValue; do { oldValue = *dst; newValue = (c89atomic_uint16)(oldValue ^ src); } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; volatile c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue ^ src; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue ^ src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } /* fetch_or() */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { volatile c89atomic_uint8 oldValue; volatile c89atomic_uint8 newValue; do { oldValue = *dst; newValue = (c89atomic_uint8)(oldValue | src); } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { volatile c89atomic_uint16 oldValue; volatile c89atomic_uint16 newValue; do { oldValue = *dst; newValue = (c89atomic_uint16)(oldValue | src); } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { volatile c89atomic_uint32 oldValue; volatile c89atomic_uint32 newValue; do { oldValue = *dst; newValue = oldValue | src; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { volatile c89atomic_uint64 oldValue; volatile c89atomic_uint64 newValue; do { oldValue = *dst; newValue = oldValue | src; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; } #endif #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) /* Atomic loads can be implemented in terms of a compare-and-swap. Need to implement as functions to silence warnings about `order` being unused. */ static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return c89atomic_compare_and_swap_8(ptr, 0, 0); } static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return c89atomic_compare_and_swap_16(ptr, 0, 0); } static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return c89atomic_compare_and_swap_32(ptr, 0, 0); } static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; /* Always using the strongest memory order. */ return c89atomic_compare_and_swap_64(ptr, 0, 0); } #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order) #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order) #define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order) #define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order) #define c89atomic_test_and_set_explicit_8( dst, order) c89atomic_exchange_explicit_8 (dst, 1, order) #define c89atomic_test_and_set_explicit_16(dst, order) c89atomic_exchange_explicit_16(dst, 1, order) #define c89atomic_test_and_set_explicit_32(dst, order) c89atomic_exchange_explicit_32(dst, 1, order) #define c89atomic_test_and_set_explicit_64(dst, order) c89atomic_exchange_explicit_64(dst, 1, order) #define c89atomic_clear_explicit_8( dst, order) c89atomic_store_explicit_8 (dst, 0, order) #define c89atomic_clear_explicit_16(dst, order) c89atomic_store_explicit_16(dst, 0, order) #define c89atomic_clear_explicit_32(dst, order) c89atomic_store_explicit_32(dst, 0, order) #define c89atomic_clear_explicit_64(dst, order) c89atomic_store_explicit_64(dst, 0, order) #define c89atomic_flag_test_and_set_explicit(ptr, order) (c89atomic_flag)c89atomic_test_and_set_explicit_8(ptr, order) #define c89atomic_flag_clear_explicit(ptr, order) c89atomic_clear_explicit_8(ptr, order) #endif /* compare_exchange() */ #if !defined(C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE) c89atomic_bool c89atomic_compare_exchange_strong_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8* expected, c89atomic_uint8 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { c89atomic_uint8 expectedValue; c89atomic_uint8 result; (void)successOrder; (void)failureOrder; expectedValue = c89atomic_load_explicit_8(expected, c89atomic_memory_order_seq_cst); result = c89atomic_compare_and_swap_8(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { c89atomic_store_explicit_8(expected, result, failureOrder); return 0; } } c89atomic_bool c89atomic_compare_exchange_strong_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16* expected, c89atomic_uint16 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { c89atomic_uint16 expectedValue; c89atomic_uint16 result; (void)successOrder; (void)failureOrder; expectedValue = c89atomic_load_explicit_16(expected, c89atomic_memory_order_seq_cst); result = c89atomic_compare_and_swap_16(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { c89atomic_store_explicit_16(expected, result, failureOrder); return 0; } } c89atomic_bool c89atomic_compare_exchange_strong_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32* expected, c89atomic_uint32 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { c89atomic_uint32 expectedValue; c89atomic_uint32 result; (void)successOrder; (void)failureOrder; expectedValue = c89atomic_load_explicit_32(expected, c89atomic_memory_order_seq_cst); result = c89atomic_compare_and_swap_32(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { c89atomic_store_explicit_32(expected, result, failureOrder); return 0; } } c89atomic_bool c89atomic_compare_exchange_strong_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64* expected, c89atomic_uint64 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { c89atomic_uint64 expectedValue; c89atomic_uint64 result; (void)successOrder; (void)failureOrder; expectedValue = c89atomic_load_explicit_64(expected, c89atomic_memory_order_seq_cst); result = c89atomic_compare_and_swap_64(dst, expectedValue, desired); if (result == expectedValue) { return 1; } else { c89atomic_store_explicit_64(expected, result, failureOrder); return 0; } } #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) #endif /* C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE */ #if !defined(C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE) static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_8(volatile void* ptr) { (void)ptr; return 1; } static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_16(volatile void* ptr) { (void)ptr; return 1; } static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_32(volatile void* ptr) { (void)ptr; return 1; } static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_64(volatile void* ptr) { (void)ptr; /* For 64-bit atomics, we can only safely say atomics are lock free on 64-bit architectures or x86. Otherwise we need to be conservative and assume not lock free. */ #if defined(C89ATOMIC_64BIT) return 1; #else #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64) return 1; #else return 0; #endif #endif } #endif /* C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE */ /* Pointer versions of relevant operations. Note that some functions cannot be implemented as #defines because for some reason, some compilers complain with a warning if you don't use the return value. I'm not fully sure why this happens, but to work around this, those particular functions are just implemented as inlined functions. */ #if defined(C89ATOMIC_64BIT) static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr) { return c89atomic_is_lock_free_64((volatile c89atomic_uint64*)ptr); } static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order) { return (void*)c89atomic_load_explicit_64((volatile c89atomic_uint64*)ptr, order); } static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order) { c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order); } static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order) { return (void*)c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order); } static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { return c89atomic_compare_exchange_strong_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder); } static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { return c89atomic_compare_exchange_weak_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder); } static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) { return (void*)c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)expected, (c89atomic_uint64)desired); } #elif defined(C89ATOMIC_32BIT) static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr) { return c89atomic_is_lock_free_32((volatile c89atomic_uint32*)ptr); } static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order) { return (void*)c89atomic_load_explicit_32((volatile c89atomic_uint32*)ptr, order); } static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order) { c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order); } static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order) { return (void*)c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order); } static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { return c89atomic_compare_exchange_strong_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder); } static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) { return c89atomic_compare_exchange_weak_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder); } static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) { return (void*)c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)expected, (c89atomic_uint32)desired); } #else #error Unsupported architecture. #endif /* Implicit Flags. */ #define c89atomic_flag_test_and_set(ptr) c89atomic_flag_test_and_set_explicit(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_flag_clear(ptr) c89atomic_flag_clear_explicit(ptr, c89atomic_memory_order_seq_cst) /* Implicit Pointer. */ #define c89atomic_store_ptr(dst, src) c89atomic_store_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst) #define c89atomic_load_ptr(ptr) c89atomic_load_explicit_ptr((volatile void**)ptr, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_ptr(dst, src) c89atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_ptr(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void*)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_ptr(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void*)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) /* Implicit Unsigned Integer. */ #define c89atomic_test_and_set_8( ptr) c89atomic_test_and_set_explicit_8( ptr, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_16(ptr) c89atomic_test_and_set_explicit_16(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_32(ptr) c89atomic_test_and_set_explicit_32(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_64(ptr) c89atomic_test_and_set_explicit_64(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_8( ptr) c89atomic_clear_explicit_8( ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_16(ptr) c89atomic_clear_explicit_16(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_32(ptr) c89atomic_clear_explicit_32(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_64(ptr) c89atomic_clear_explicit_64(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_store_8( dst, src) c89atomic_store_explicit_8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_store_16(dst, src) c89atomic_store_explicit_16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_store_32(dst, src) c89atomic_store_explicit_32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_store_64(dst, src) c89atomic_store_explicit_64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_load_8( ptr) c89atomic_load_explicit_8( ptr, c89atomic_memory_order_seq_cst) #define c89atomic_load_16(ptr) c89atomic_load_explicit_16(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_load_32(ptr) c89atomic_load_explicit_32(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_load_64(ptr) c89atomic_load_explicit_64(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_8( dst, src) c89atomic_exchange_explicit_8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_16(dst, src) c89atomic_exchange_explicit_16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_32(dst, src) c89atomic_exchange_explicit_32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_64(dst, src) c89atomic_exchange_explicit_64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_8( dst, expected, desired) c89atomic_compare_exchange_strong_explicit_8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_16(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_32(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_64(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_8( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_16( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_32( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_64( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_add_8( dst, src) c89atomic_fetch_add_explicit_8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_add_16(dst, src) c89atomic_fetch_add_explicit_16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_add_32(dst, src) c89atomic_fetch_add_explicit_32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_add_64(dst, src) c89atomic_fetch_add_explicit_64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_sub_8( dst, src) c89atomic_fetch_sub_explicit_8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_sub_16(dst, src) c89atomic_fetch_sub_explicit_16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_sub_32(dst, src) c89atomic_fetch_sub_explicit_32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_sub_64(dst, src) c89atomic_fetch_sub_explicit_64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_or_8( dst, src) c89atomic_fetch_or_explicit_8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_or_16(dst, src) c89atomic_fetch_or_explicit_16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_or_32(dst, src) c89atomic_fetch_or_explicit_32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_or_64(dst, src) c89atomic_fetch_or_explicit_64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_xor_8( dst, src) c89atomic_fetch_xor_explicit_8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_xor_16(dst, src) c89atomic_fetch_xor_explicit_16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_xor_32(dst, src) c89atomic_fetch_xor_explicit_32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_xor_64(dst, src) c89atomic_fetch_xor_explicit_64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_and_8( dst, src) c89atomic_fetch_and_explicit_8 (dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_and_16(dst, src) c89atomic_fetch_and_explicit_16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_and_32(dst, src) c89atomic_fetch_and_explicit_32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_and_64(dst, src) c89atomic_fetch_and_explicit_64(dst, src, c89atomic_memory_order_seq_cst) /* Explicit Signed Integer. */ #define c89atomic_test_and_set_explicit_i8( ptr, order) c89atomic_test_and_set_explicit_8( (c89atomic_uint8* )ptr, order) #define c89atomic_test_and_set_explicit_i16(ptr, order) c89atomic_test_and_set_explicit_16((c89atomic_uint16*)ptr, order) #define c89atomic_test_and_set_explicit_i32(ptr, order) c89atomic_test_and_set_explicit_32((c89atomic_uint32*)ptr, order) #define c89atomic_test_and_set_explicit_i64(ptr, order) c89atomic_test_and_set_explicit_64((c89atomic_uint64*)ptr, order) #define c89atomic_clear_explicit_i8( ptr, order) c89atomic_clear_explicit_8( (c89atomic_uint8* )ptr, order) #define c89atomic_clear_explicit_i16(ptr, order) c89atomic_clear_explicit_16((c89atomic_uint16*)ptr, order) #define c89atomic_clear_explicit_i32(ptr, order) c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order) #define c89atomic_clear_explicit_i64(ptr, order) c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order) #define c89atomic_store_explicit_i8( dst, src, order) c89atomic_store_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) #define c89atomic_store_explicit_i16(dst, src, order) c89atomic_store_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) #define c89atomic_store_explicit_i32(dst, src, order) c89atomic_store_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) #define c89atomic_store_explicit_i64(dst, src, order) c89atomic_store_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) #define c89atomic_load_explicit_i8( ptr, order) c89atomic_load_explicit_8( (c89atomic_uint8* )ptr, order) #define c89atomic_load_explicit_i16(ptr, order) c89atomic_load_explicit_16((c89atomic_uint16*)ptr, order) #define c89atomic_load_explicit_i32(ptr, order) c89atomic_load_explicit_32((c89atomic_uint32*)ptr, order) #define c89atomic_load_explicit_i64(ptr, order) c89atomic_load_explicit_64((c89atomic_uint64*)ptr, order) #define c89atomic_exchange_explicit_i8( dst, src, order) c89atomic_exchange_explicit_8 ((c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) #define c89atomic_exchange_explicit_i16(dst, src, order) c89atomic_exchange_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) #define c89atomic_exchange_explicit_i32(dst, src, order) c89atomic_exchange_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) #define c89atomic_exchange_explicit_i64(dst, src, order) c89atomic_exchange_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) #define c89atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8* )expected, (c89atomic_uint8 )desired, successOrder, failureOrder) #define c89atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16*)expected, (c89atomic_uint16)desired, successOrder, failureOrder) #define c89atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder) #define c89atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8* )expected, (c89atomic_uint8 )desired, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16*)expected, (c89atomic_uint16)desired, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder) #define c89atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder) #define c89atomic_fetch_add_explicit_i8( dst, src, order) c89atomic_fetch_add_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) #define c89atomic_fetch_add_explicit_i16(dst, src, order) c89atomic_fetch_add_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) #define c89atomic_fetch_add_explicit_i32(dst, src, order) c89atomic_fetch_add_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) #define c89atomic_fetch_add_explicit_i64(dst, src, order) c89atomic_fetch_add_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) #define c89atomic_fetch_sub_explicit_i8( dst, src, order) c89atomic_fetch_sub_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) #define c89atomic_fetch_sub_explicit_i16(dst, src, order) c89atomic_fetch_sub_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) #define c89atomic_fetch_sub_explicit_i32(dst, src, order) c89atomic_fetch_sub_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) #define c89atomic_fetch_sub_explicit_i64(dst, src, order) c89atomic_fetch_sub_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) #define c89atomic_fetch_or_explicit_i8( dst, src, order) c89atomic_fetch_or_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) #define c89atomic_fetch_or_explicit_i16(dst, src, order) c89atomic_fetch_or_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) #define c89atomic_fetch_or_explicit_i32(dst, src, order) c89atomic_fetch_or_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) #define c89atomic_fetch_or_explicit_i64(dst, src, order) c89atomic_fetch_or_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) #define c89atomic_fetch_xor_explicit_i8( dst, src, order) c89atomic_fetch_xor_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) #define c89atomic_fetch_xor_explicit_i16(dst, src, order) c89atomic_fetch_xor_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) #define c89atomic_fetch_xor_explicit_i32(dst, src, order) c89atomic_fetch_xor_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) #define c89atomic_fetch_xor_explicit_i64(dst, src, order) c89atomic_fetch_xor_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) #define c89atomic_fetch_and_explicit_i8( dst, src, order) c89atomic_fetch_and_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) #define c89atomic_fetch_and_explicit_i16(dst, src, order) c89atomic_fetch_and_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) #define c89atomic_fetch_and_explicit_i32(dst, src, order) c89atomic_fetch_and_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) #define c89atomic_fetch_and_explicit_i64(dst, src, order) c89atomic_fetch_and_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) /* Implicit Signed Integer. */ #define c89atomic_test_and_set_i8( ptr) c89atomic_test_and_set_explicit_i8( ptr, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_i16(ptr) c89atomic_test_and_set_explicit_i16(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_i32(ptr) c89atomic_test_and_set_explicit_i32(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_test_and_set_i64(ptr) c89atomic_test_and_set_explicit_i64(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_i8( ptr) c89atomic_clear_explicit_i8( ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_i16(ptr) c89atomic_clear_explicit_i16(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_i32(ptr) c89atomic_clear_explicit_i32(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_i64(ptr) c89atomic_clear_explicit_i64(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_store_i8( dst, src) c89atomic_store_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_store_i16(dst, src) c89atomic_store_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_store_i32(dst, src) c89atomic_store_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_store_i64(dst, src) c89atomic_store_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_load_i8( ptr) c89atomic_load_explicit_i8( ptr, c89atomic_memory_order_seq_cst) #define c89atomic_load_i16(ptr) c89atomic_load_explicit_i16(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_load_i32(ptr) c89atomic_load_explicit_i32(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_load_i64(ptr) c89atomic_load_explicit_i64(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_i8( dst, src) c89atomic_exchange_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_i16(dst, src) c89atomic_exchange_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_i32(dst, src) c89atomic_exchange_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_i64(dst, src) c89atomic_exchange_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_i8( dst, expected, desired) c89atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_i16(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_i32(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_strong_i64(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_i8( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_i16(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_i32(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_compare_exchange_weak_i64(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_add_i8( dst, src) c89atomic_fetch_add_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_add_i16(dst, src) c89atomic_fetch_add_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_add_i32(dst, src) c89atomic_fetch_add_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_add_i64(dst, src) c89atomic_fetch_add_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_sub_i8( dst, src) c89atomic_fetch_sub_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_sub_i16(dst, src) c89atomic_fetch_sub_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_sub_i32(dst, src) c89atomic_fetch_sub_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_sub_i64(dst, src) c89atomic_fetch_sub_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_or_i8( dst, src) c89atomic_fetch_or_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_or_i16(dst, src) c89atomic_fetch_or_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_or_i32(dst, src) c89atomic_fetch_or_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_or_i64(dst, src) c89atomic_fetch_or_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_xor_i8( dst, src) c89atomic_fetch_xor_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_xor_i16(dst, src) c89atomic_fetch_xor_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_xor_i32(dst, src) c89atomic_fetch_xor_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_xor_i64(dst, src) c89atomic_fetch_xor_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_and_i8( dst, src) c89atomic_fetch_and_explicit_i8( dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_and_i16(dst, src) c89atomic_fetch_and_explicit_i16(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_and_i32(dst, src) c89atomic_fetch_and_explicit_i32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_fetch_and_i64(dst, src) c89atomic_fetch_and_explicit_i64(dst, src, c89atomic_memory_order_seq_cst) #if defined(__cplusplus) } #endif #endif /* c89atomic_h */ /* This software is available as a choice of the following licenses. Choose whichever you prefer. =============================================================================== ALTERNATIVE 1 - Public Domain (www.unlicense.org) =============================================================================== This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to <http://unlicense.org/> =============================================================================== ALTERNATIVE 2 - MIT No Attribution =============================================================================== Copyright 2020 David Reid Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <stdint.h> #include <stdatomic.h> float x; volatile float xv; _Atomic float xa; static void c89atomic_store_f32(float *f, float v) { union {uint32_t i; float f;} u; u.f = v; c89atomic_store_32((uint32_t*)f, u.i); } static float c89atomic_load_f32(float *f) { union {uint32_t i; float f;} u; u.i = c89atomic_load_32((uint32_t*)&x); return u.f; } void set_c11atomic(float v) { xa = v; } void set_c89atomic(float v) { c89atomic_store_f32(&x, v); } void set_volatile(float v) { xv = v; } void set_naive(float v) { x = v; } float get_c11atomic() { return xa; } float get_c89atomic() { return c89atomic_load_f32(&x); } float get_volatile() { return xv; } float get_naive() { return x; }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree