From ff15977666b313c25e0b66302fa789898e00279e Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 20 Dec 2024 10:31:39 +0100 Subject: [PATCH] Extend atomic instruction APIs (#495) --- docs/src/lib/instructions.md | 7 ++++ docs/src/man/instructions.md | 7 +++- src/core/instructions.jl | 66 +++++++++++++++++++++++++++++++++++- src/newpm.jl | 2 +- src/utils.jl | 5 ++- test/instructions_tests.jl | 21 ++++++++++++ 6 files changed, 102 insertions(+), 6 deletions(-) diff --git a/docs/src/lib/instructions.md b/docs/src/lib/instructions.md index 41942c0f..29784581 100644 --- a/docs/src/lib/instructions.md +++ b/docs/src/lib/instructions.md @@ -40,6 +40,13 @@ ordering! SyncScope syncscope syncscope! +binop +isweak +weak! +success_ordering +success_ordering! +failure_ordering +failure_ordering! ``` ## Call instructions diff --git a/docs/src/man/instructions.md b/docs/src/man/instructions.md index 5fb555ce..be1e148c 100644 --- a/docs/src/man/instructions.md +++ b/docs/src/man/instructions.md @@ -88,9 +88,14 @@ the instruction. This is done by calling the `debuglocation!` function on the bu Atomic instructions support a few additional APIs: - `is_atomic`: check if the instruction is atomic. -- `ordering`/`ordering!`: get or set the ordering of the instruction. +- `isweak`/`weak!`: check if the instruction is weak, or set it to be weak. - `syncscope`/`syncscope!`: get or set the synchronization scope of the instruction to a specific `SyncScope` +- `ordering`/`ordering!`: get or set the ordering of the instruction. +- `success_ordering`/`success_ordering!`: get or set the success ordering of an atomic + compare-and-swap instruction. +- `failure_ordering`/`failure_ordering!`: get or set the failure ordering of an atomic +- `binop`: to get the binary operation of an atomic read-modify-write instruction. ## Call sites instructions diff --git a/src/core/instructions.jl b/src/core/instructions.jl index 23acb1d0..48a97712 100644 --- a/src/core/instructions.jl +++ b/src/core/instructions.jl @@ -121,7 +121,8 @@ predicate(inst::FCmpInst) = API.LLVMGetFCmpPredicate(inst) ## atomics -export is_atomic, ordering, ordering!, SyncScope, syncscope, syncscope! +export is_atomic, ordering, ordering!, SyncScope, syncscope, syncscope!, binop, + isweak, weak!, success_ordering, success_ordering!, failure_ordering, failure_ordering! const AtomicInst = Union{LoadInst, StoreInst, FenceInst, AtomicRMWInst, AtomicCmpXchgInst} @@ -209,6 +210,69 @@ function syncscope!(inst::AtomicInst, scope::SyncScope) API.LLVMSetAtomicSyncScopeID(inst, scope) end +""" + binop(inst::AtomicRMWInst) + +Get the binary operation of the given atomic read-modify-write instruction. +""" +function binop(inst::AtomicRMWInst) + API.LLVMGetAtomicRMWBinOp(inst) +end + +""" + isweak(inst::AtomicCmpXchgInst) + +Check if the given atomic compare-and-exchange instruction is weak. +""" +function isweak(inst::AtomicCmpXchgInst) + API.LLVMGetWeak(inst) |> Bool +end + +""" + weak!(inst::AtomicCmpXchgInst, is_weak::Bool) + +Set whether the given atomic compare-and-exchange instruction is weak. +""" +function weak!(inst::AtomicCmpXchgInst, is_weak::Bool) + API.LLVMSetWeak(inst, is_weak) +end + +""" + success_ordering(inst::AtomicCmpXchgInst) + +Get the success ordering of the given atomic compare-and-exchange instruction. +""" +function success_ordering(inst::AtomicCmpXchgInst) + API.LLVMGetCmpXchgSuccessOrdering(inst) +end + +""" + success_ordering!(inst::AtomicCmpXchgInst, ord::API.LLVMAtomicOrdering) + +Set the success ordering of the given atomic compare-and-exchange instruction. +""" +function success_ordering!(inst::AtomicCmpXchgInst, ord::API.LLVMAtomicOrdering) + API.LLVMSetCmpXchgSuccessOrdering(inst, ord) +end + +""" + failure_ordering(inst::AtomicCmpXchgInst) + +Get the failure ordering of the given atomic compare-and-exchange instruction. +""" +function failure_ordering(inst::AtomicCmpXchgInst) + API.LLVMGetCmpXchgFailureOrdering(inst) +end + +""" + failure_ordering!(inst::AtomicCmpXchgInst, ord::API.LLVMAtomicOrdering) + +Set the failure ordering of the given atomic compare-and-exchange instruction. +""" +function failure_ordering!(inst::AtomicCmpXchgInst, ord::API.LLVMAtomicOrdering) + API.LLVMSetCmpXchgFailureOrdering(inst, ord) +end + ## call sites and invocations diff --git a/src/newpm.jl b/src/newpm.jl index 156a2384..f95304eb 100644 --- a/src/newpm.jl +++ b/src/newpm.jl @@ -203,7 +203,7 @@ function NewPMPassBuilder(; kwargs...) API.LLVMPassBuilderOptionsSetSLPVectorization(obj, value) elseif name == :loop_unrolling API.LLVMPassBuilderOptionsSetLoopUnrolling(obj, value) - elseif loop == :forget_all_scev_in_loop_unroll + elseif name == :forget_all_scev_in_loop_unroll API.LLVMPassBuilderOptionsSetForgetAllSCEVInLoopUnroll(obj, value) elseif name == :licm_mssa_opt_cap API.LLVMPassBuilderOptionsSetLicmMSSAOptCap(obj, value) diff --git a/src/utils.jl b/src/utils.jl index ceef4e4c..6860e53f 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -64,7 +64,7 @@ end Simpler version of [`clone_into!`](@ref) that clones a function `f` into a new function, optionally mapping values according to the `value_map` dictionary. """ -function clone(f::Function; value_map::Dict{<:Value,<:Value}=Dict{Value,Value}()) +function clone(f::Function; value_map::Dict{<:Value,<:Value}=Dict{Value,Value}(), kwargs...) argtypes = LLVMType[] # The user might be deleting arguments to the function by specifying them in @@ -96,8 +96,7 @@ function clone(f::Function; value_map::Dict{<:Value,<:Value}=Dict{Value,Value}() end end - clone_into!(new_f, f; - value_map, changes=API.LLVMCloneFunctionChangeTypeLocalChangesOnly) + clone_into!(new_f, f; value_map, kwargs...) return new_f end diff --git a/test/instructions_tests.jl b/test/instructions_tests.jl index 4a9c81f1..c04cc7bb 100644 --- a/test/instructions_tests.jl +++ b/test/instructions_tests.jl @@ -239,6 +239,27 @@ else @check_ir atomic_rmw_inst "atomicrmw add ptr %4, i32 %0 seq_cst" end + @test binop(atomic_rmw_inst) == LLVM.API.LLVMAtomicRMWBinOpAdd + @test syncscope(atomic_rmw_inst) == SyncScope("system") + syncscope!(atomic_rmw_inst, SyncScope("agent")) + @test syncscope(atomic_rmw_inst) == SyncScope("agent") + + atomic_cmpxchg_inst = atomic_cmpxchg!(builder, ptr1, int1, int2, + LLVM.API.LLVMAtomicOrderingSequentiallyConsistent, LLVM.API.LLVMAtomicOrderingAcquire, single_thread) + if supports_typed_pointers(ctx) + @check_ir atomic_cmpxchg_inst "cmpxchg i32* %4, i32 %0, i32 %1 seq_cst acquire" + else + @check_ir atomic_cmpxchg_inst "cmpxchg ptr %4, i32 %0, i32 %1 seq_cst acquire" + end + @test success_ordering(atomic_cmpxchg_inst) == LLVM.API.LLVMAtomicOrderingSequentiallyConsistent + success_ordering!(atomic_cmpxchg_inst, LLVM.API.LLVMAtomicOrderingAcquireRelease) + @test success_ordering(atomic_cmpxchg_inst) == LLVM.API.LLVMAtomicOrderingAcquireRelease + @test failure_ordering(atomic_cmpxchg_inst) == LLVM.API.LLVMAtomicOrderingAcquire + failure_ordering!(atomic_cmpxchg_inst, LLVM.API.LLVMAtomicOrderingMonotonic) + @test failure_ordering(atomic_cmpxchg_inst) == LLVM.API.LLVMAtomicOrderingMonotonic + @test !isweak(atomic_cmpxchg_inst) + weak!(atomic_cmpxchg_inst, true) + @test isweak(atomic_cmpxchg_inst) single_thread = true atomic_rmw_inst = atomic_rmw!(builder,