diff --git a/.github/workflows/ci-julia-nightly.yml b/.github/workflows/ci-julia-nightly.yml index b8e67fc..7aaccae 100644 --- a/.github/workflows/ci-julia-nightly.yml +++ b/.github/workflows/ci-julia-nightly.yml @@ -18,57 +18,42 @@ on: jobs: test-julia-nightly: timeout-minutes: 30 - name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ github.event_name }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - arch: - - x64 - - x86 + # use default arch exclusive: - '0' os: - ubuntu-latest - - macOS-latest + - macOS-latest # arm - windows-latest threads: - '5' version: - - '1.5' - - '1' + # Runs on Julia nightly only. - 'nightly' - exclude: - - os: macOS-latest - arch: x86 # 32-bit Julia binaries are not available on macOS include: - - exclusive: '1' - threads: '2' - arch: x64 + # (exclusive=1, threads=2) + - arch: x64 + exclusive: '1' os: ubuntu-latest - version: '1' + threads: '2' + version: 'nightly' steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} - arch: ${{ matrix.arch }} - - uses: actions/cache@v4 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 env: JULIA_EXCLUSIVE: ${{ matrix.exclusive }} JULIA_NUM_THREADS: ${{ matrix.threads }} - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v5 with: - file: lcov.info + files: lcov.info diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0ad3c0..c2ca055 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,22 +30,27 @@ jobs: - '0' os: - ubuntu-latest - - macOS-latest - windows-latest + - macos-13 # Intel threads: - '5' version: - '1.5' - '1' - - 'nightly' exclude: - - os: macOS-latest + - os: macos-13 arch: x86 # 32-bit Julia binaries are not available on macOS include: - - exclusive: '1' - threads: '2' - arch: x64 + - arch: aarch64 + exclusive: '0' + os: macos-latest # Arm + threads: '5' + version: '1' # macos-latest (aarch64) need Julia >= v1.8+ + # (exclusive=1, threads=2) + - arch: x64 + exclusive: '1' os: ubuntu-latest + threads: '2' version: '1' steps: - uses: actions/checkout@v4 @@ -53,25 +58,16 @@ jobs: with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v4 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 env: JULIA_EXCLUSIVE: ${{ matrix.exclusive }} JULIA_NUM_THREADS: ${{ matrix.threads }} - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v5 with: - file: lcov.info + files: lcov.info docs: name: Documentation runs-on: ubuntu-latest diff --git a/src/atomics.jl b/src/atomics.jl index 462366c..7d44d6a 100644 --- a/src/atomics.jl +++ b/src/atomics.jl @@ -1,40 +1,95 @@ + for (ityp,jtyp) ∈ [("i8", UInt8), ("i16", UInt16), ("i32", UInt32), ("i64", UInt64), ("i128", UInt128)] @eval begin @inline function _atomic_load(ptr::Ptr{$jtyp}) - Base.llvmcall($(""" - %p = inttoptr i$(8sizeof(Int)) %0 to $(ityp)* - %v = load atomic $(ityp), $(ityp)* %p acquire, align $(Base.gc_alignment(jtyp)) - ret $(ityp) %v - """), $jtyp, Tuple{Ptr{$jtyp}}, ptr) + Base.llvmcall($( + @static if VERSION >= v"1.12-DEV" + # use opaque pointers #53 + """ + %v = load atomic $(ityp), ptr %0 acquire, align $(Base.gc_alignment(jtyp)) + ret $(ityp) %v + """ + else + """ + %p = inttoptr i$(8sizeof(Int)) %0 to $(ityp)* + %v = load atomic $(ityp), $(ityp)* %p acquire, align $(Base.gc_alignment(jtyp)) + ret $(ityp) %v + """ + end + ), $jtyp, Tuple{Ptr{$jtyp}}, ptr) end @inline function _atomic_store!(ptr::Ptr{$jtyp}, x::$jtyp) - Base.llvmcall($(""" - %p = inttoptr i$(8sizeof(Int)) %0 to $(ityp)* - store atomic $(ityp) %1, $(ityp)* %p release, align $(Base.gc_alignment(jtyp)) - ret void - """), Cvoid, Tuple{Ptr{$jtyp}, $jtyp}, ptr, x) + Base.llvmcall($( + @static if VERSION >= v"1.12-DEV" + """ + store atomic $(ityp) %1, ptr %0 release, align $(Base.gc_alignment(jtyp)) + ret void + """ + else + """ + %p = inttoptr i$(8sizeof(Int)) %0 to $(ityp)* + store atomic $(ityp) %1, $(ityp)* %p release, align $(Base.gc_alignment(jtyp)) + ret void + """ + end + ), Cvoid, Tuple{Ptr{$jtyp}, $jtyp}, ptr, x) end @inline function _atomic_cas_cmp!(ptr::Ptr{$jtyp}, cmp::$jtyp, newval::$jtyp) - Base.llvmcall($(""" - %p = inttoptr i$(8sizeof(Int)) %0 to $(ityp)* - %c = cmpxchg $(ityp)* %p, $(ityp) %1, $(ityp) %2 acq_rel acquire - %bit = extractvalue { $ityp, i1 } %c, 1 - %bool = zext i1 %bit to i8 - ret i8 %bool - """), Bool, Tuple{Ptr{$jtyp}, $jtyp, $jtyp}, ptr, cmp, newval) + Base.llvmcall($( + @static if VERSION >= v"1.12-DEV" + """ + %c = cmpxchg ptr %0, $(ityp) %1, $(ityp) %2 acq_rel acquire + %bit = extractvalue { $ityp, i1 } %c, 1 + %bool = zext i1 %bit to i8 + ret i8 %bool + """ + else + """ + %p = inttoptr i$(8sizeof(Int)) %0 to $(ityp)* + %c = cmpxchg $(ityp)* %p, $(ityp) %1, $(ityp) %2 acq_rel acquire + %bit = extractvalue { $ityp, i1 } %c, 1 + %bool = zext i1 %bit to i8 + ret i8 %bool + """ + end + ), Bool, Tuple{Ptr{$jtyp}, $jtyp, $jtyp}, ptr, cmp, newval) end end end -for op ∈ ["xchg", "add", "sub", "and", "nand", "or", "xor", "max", "min", "umax", "umin"] # "fadd", "fsub" + +""" +Operations supported by `atomicrmw`. + +- Julia v1.11 use [libLLVM-16](https://releases.llvm.org/16.0.0/docs/LangRef.html#atomicrmw-instruction) +""" +const atomicrmw_ops = [ + "xchg", "add", "sub", + "and", "nand", "or", "xor", + "max", "min", "umax", "umin", + # "fadd", "fsub", + # "fmax", "fmin", + # "uinc_wrap", "udec_wrap", # Need LLVM 16: VERSION >= v"1.11" +] +for op ∈ atomicrmw_ops f = Symbol("_atomic_", op, '!') for (ityp,jtyp) ∈ [("i8", UInt8), ("i16", UInt16), ("i32", UInt32), ("i64", UInt64), ("i128", UInt128)] @eval begin + # Do inplace `$(op)` for `*ptr` and `x` atomically, return the old value of `*ptr`. @inline function $f(ptr::Ptr{$jtyp}, x::$jtyp) - Base.llvmcall($(""" - %p = inttoptr i$(8sizeof(Int)) %0 to $(ityp)* - %v = atomicrmw $op $(ityp)* %p, $(ityp) %1 acq_rel - ret $(ityp) %v - """), $jtyp, Tuple{Ptr{$jtyp}, $jtyp}, ptr, x) + Base.llvmcall($( + @static if VERSION >= v"1.12-DEV" + """ + %v = atomicrmw $(op) ptr %0, $(ityp) %1 acq_rel + ret $(ityp) %v + """ + else + """ + %p = inttoptr i$(8sizeof(Int)) %0 to $(ityp)* + %v = atomicrmw $op $(ityp)* %p, $(ityp) %1 acq_rel + ret $(ityp) %v + """ + end + ), $jtyp, Tuple{Ptr{$jtyp}, $jtyp}, ptr, x) end end end @@ -44,9 +99,9 @@ for op ∈ ["xchg", "add", "sub", "and", "nand", "or", "xor", "max", "min", "uma end end end + @inline _atomic_state(ptr::Ptr{UInt}) = reinterpret(ThreadState, _atomic_load(reinterpret(Ptr{UInt32}, ptr))) @inline _atomic_store!(ptr::Ptr{UInt}, x::ThreadState) = _atomic_store!(reinterpret(Ptr{UInt32}, ptr), reinterpret(UInt32, x)) @inline function _atomic_cas_cmp!(ptr::Ptr{UInt}, cmp::ThreadState, newval::ThreadState) _atomic_cas_cmp!(reinterpret(Ptr{UInt32}, ptr), reinterpret(UInt32, cmp), reinterpret(UInt32, newval)) end -