Skip to content

Instantly share code, notes, and snippets.

@dillondaudert
Last active November 20, 2019 17:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dillondaudert/be7b2e2943f37dacc75f315cd89590a0 to your computer and use it in GitHub Desktop.
Save dillondaudert/be7b2e2943f37dacc75f315cd89590a0 to your computer and use it in GitHub Desktop.
Atomic{Ptr}
# atomic operations for pointers. for test development purposes
import Base.Sys: WORD_SIZE
using Core.Intrinsics: llvmcall
using Base.Threads: llvmtypes, AtomicTypes
mutable struct MyAtomic{V<:Ptr}
value::V
end
@eval atomic_xchg!(x::MyAtomic{Ptr{V}}, v::Ptr{V}) where V = llvmcall($"""
%ptr = inttoptr i$WORD_SIZE %0 to i$WORD_SIZE*
%rv = atomicrmw xchg i$WORD_SIZE* %ptr, i$WORD_SIZE %1 acq_rel
ret i$WORD_SIZE %rv
""", Ptr{V}, Tuple{Ptr{Ptr{V}}, Ptr{V}}, convert(Ptr{Ptr{V}}, pointer_from_objref(x)), v)
@eval atomic_cas!(x::MyAtomic{Ptr{V}}, cmp::Ptr{V}, new::Ptr{V}) where V = llvmcall($"""
%ptr = inttoptr i$WORD_SIZE %0 to i$WORD_SIZE*
%rs = cmpxchg i$WORD_SIZE* %ptr, i$WORD_SIZE %1, i$WORD_SIZE %2 acq_rel acquire
%rv = extractvalue { i$WORD_SIZE, i1 } %rs, 0
ret i$WORD_SIZE %rv
""", Ptr{V}, Tuple{Ptr{Ptr{V}}, Ptr{V}, Ptr{V}}, convert(Ptr{Ptr{V}}, pointer_from_objref(x)), cmp, new)
A = [1, 2, 3]
ptr1 = pointer(A, 1)
ptr2 = pointer(A, 2)
ptr3 = pointer(A, 3)
my_atomic = MyAtomic{Ptr{Int}}(ptr1)
@assert atomic_xchg!(my_atomic, ptr2) === ptr1
@assert my_atomic.value === ptr2
# atomic_cas!
@assert atomic_cas!(my_atomic, ptr3, ptr3) === ptr2
@assert my_atomic.value === ptr2 # no swap
@assert atomic_cas!(my_atomic, ptr2, ptr3) === ptr2
@assert my_atomic.value === ptr3 # yes swap
import Base.Sys: WORD_SIZE
using Core.Intrinsics: llvmcall
using Base.Threads: llvmtypes, atomictypes
"""
getelementptr(p::Ptr{T}, index::Integer)
Returns the address in memory at `index`. This calls the LLVM op `getelementptr` to
perform pointer arithmetic.
"""
function getelementptr end
getelementptr(p::Ptr, index::Integer) = getelementptr(p, (index % UInt) % UInt)
for typ in atomictypes
lt = llvmtypes[typ]
@eval getelementptr(p::Ptr{$typ}, index::UInt) = oftype(p, llvmcall($"""
%ptr = inttoptr i$WORD_SIZE %0 to $lt*
%idx = getelementptr $lt, $lt* %ptr, i$WORD_SIZE %1
%rv = ptrtoint $lt* %idx to i$WORD_SIZE
ret i$WORD_SIZE %rv
""", UInt, Tuple{Ptr{$typ}, UInt}, p, index))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment