Skip to content

Commit

Permalink
LLVMExtra: Add basic (Post)DominatorTree API (#363)
Browse files Browse the repository at this point in the history
This API can be useful, e.g., to discover that an instruction is
executed exclusively on a throwing code-path.
  • Loading branch information
topolarity authored Sep 29, 2023
1 parent 69962a5 commit 6096371
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 1 deletion.
11 changes: 11 additions & 0 deletions deps/LLVMExtra/include/LLVMExtra.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,5 +196,16 @@ LLVMBool LLVMPointerTypeIsOpaque(LLVMTypeRef Ty);
LLVMTypeRef LLVMPointerTypeInContext(LLVMContextRef C, unsigned AddressSpace);
#endif

// (Post)DominatorTree
typedef struct LLVMOpaqueDominatorTree *LLVMDominatorTreeRef;
LLVMDominatorTreeRef LLVMCreateDominatorTree(LLVMValueRef Fn);
void LLVMDisposeDominatorTree(LLVMDominatorTreeRef Tree);
LLVMBool LLVMDominatorTreeInstructionDominates(LLVMDominatorTreeRef Tree, LLVMValueRef InstA, LLVMValueRef InstB);

typedef struct LLVMOpaquePostDominatorTree *LLVMPostDominatorTreeRef;
LLVMPostDominatorTreeRef LLVMCreatePostDominatorTree(LLVMValueRef Fn);
void LLVMDisposePostDominatorTree(LLVMPostDominatorTreeRef Tree);
LLVMBool LLVMPostDominatorTreeInstructionDominates(LLVMPostDominatorTreeRef Tree, LLVMValueRef InstA, LLVMValueRef InstB);

LLVM_C_EXTERN_C_END
#endif
34 changes: 34 additions & 0 deletions deps/LLVMExtra/lib/llvm-api.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <LLVMExtra.h>

#include <llvm/ADT/Triple.h>
#include <llvm/Analysis/PostDominators.h>
#include <llvm/Analysis/TargetLibraryInfo.h>
#include <llvm/Analysis/TargetTransformInfo.h>
#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
Expand All @@ -13,6 +14,7 @@
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Dominators.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/Scalar.h>
Expand Down Expand Up @@ -637,3 +639,35 @@ LLVMTypeRef LLVMPointerTypeInContext(LLVMContextRef C, unsigned AddressSpace) {
return wrap(PointerType::get(*unwrap(C), AddressSpace));
}
#endif

DEFINE_STDCXX_CONVERSION_FUNCTIONS(DominatorTree, LLVMDominatorTreeRef)

LLVMDominatorTreeRef LLVMCreateDominatorTree(LLVMValueRef Fn) {
return wrap(new DominatorTree(*unwrap<Function>(Fn)));
}

void LLVMDisposeDominatorTree(LLVMDominatorTreeRef Tree) {
delete unwrap(Tree);
}

LLVMBool LLVMDominatorTreeInstructionDominates(
LLVMDominatorTreeRef Tree, LLVMValueRef InstA, LLVMValueRef InstB
) {
return unwrap(Tree)->dominates(unwrap<Instruction>(InstA), unwrap<Instruction>(InstB));
}

DEFINE_STDCXX_CONVERSION_FUNCTIONS(PostDominatorTree, LLVMPostDominatorTreeRef)

LLVMPostDominatorTreeRef LLVMCreatePostDominatorTree(LLVMValueRef Fn) {
return wrap(new PostDominatorTree(*unwrap<Function>(Fn)));
}

void LLVMDisposePostDominatorTree(LLVMPostDominatorTreeRef Tree) {
delete unwrap(Tree);
}

LLVMBool LLVMPostDominatorTreeInstructionDominates(
LLVMPostDominatorTreeRef Tree, LLVMValueRef InstA, LLVMValueRef InstB
) {
return unwrap(Tree)->dominates(unwrap<Instruction>(InstA), unwrap<Instruction>(InstB));
}
32 changes: 32 additions & 0 deletions lib/libLLVM_extra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,38 @@ function LLVMReplaceMDNodeOperandWith(MD, I, New)
ccall((:LLVMReplaceMDNodeOperandWith, libLLVMExtra), Cvoid, (LLVMMetadataRef, Cuint, LLVMMetadataRef), MD, I, New)
end

mutable struct LLVMOpaqueDominatorTree end

const LLVMDominatorTreeRef = Ptr{LLVMOpaqueDominatorTree}

function LLVMCreateDominatorTree(Fn)
ccall((:LLVMCreateDominatorTree, libLLVMExtra), LLVMDominatorTreeRef, (LLVMValueRef, ), Fn)
end

function LLVMDisposeDominatorTree(Tree)
ccall((:LLVMDisposeDominatorTree, libLLVMExtra), Cvoid, (LLVMDominatorTreeRef, ), Tree)
end

function LLVMDominatorTreeInstructionDominates(Tree, InstA, InstB)
ccall((:LLVMDominatorTreeInstructionDominates, libLLVMExtra), LLVMBool, (LLVMDominatorTreeRef, LLVMValueRef, LLVMValueRef), Tree, InstA, InstB)
end

mutable struct LLVMOpaquePostDominatorTree end

const LLVMPostDominatorTreeRef = Ptr{LLVMOpaquePostDominatorTree}

function LLVMCreatePostDominatorTree(Fn)
ccall((:LLVMCreatePostDominatorTree, libLLVMExtra), LLVMPostDominatorTreeRef, (LLVMValueRef, ), Fn)
end

function LLVMDisposePostDominatorTree(Tree)
ccall((:LLVMDisposePostDominatorTree, libLLVMExtra), Cvoid, (LLVMPostDominatorTreeRef, ), Tree)
end

function LLVMPostDominatorTreeInstructionDominates(Tree, InstA, InstB)
ccall((:LLVMPostDominatorTreeInstructionDominates, libLLVMExtra), LLVMBool, (LLVMPostDominatorTreeRef, LLVMValueRef, LLVMValueRef), Tree, InstA, InstB)
end

if version() > v"12"
function LLVMContextSupportsTypedPointers(Ctx)
ccall((:LLVMContextSupportsTypedPointers, libLLVMExtra), LLVMBool, (LLVMContextRef,), Ctx)
Expand Down
28 changes: 27 additions & 1 deletion src/analysis.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export verify
export verify, dominates

function verify(mod::Module)
out_error = Ref{Cstring}()
Expand All @@ -18,3 +18,29 @@ function verify(f::Function)
throw(LLVMException("broken function"))
end
end

@checked struct DomTree
ref::API.LLVMDominatorTreeRef
end

Base.unsafe_convert(::Type{API.LLVMDominatorTreeRef}, domtree::DomTree) = domtree.ref

DomTree(f::Function) = DomTree(API.LLVMCreateDominatorTree(f))
dispose(domtree::DomTree) = API.LLVMDisposeDominatorTree(domtree)

function dominates(domtree::DomTree, A::Instruction, B::Instruction)
convert(Core.Bool, API.LLVMDominatorTreeInstructionDominates(domtree, A, B))
end

@checked struct PostDomTree
ref::API.LLVMPostDominatorTreeRef
end

Base.unsafe_convert(::Type{API.LLVMPostDominatorTreeRef}, postdomtree::PostDomTree) = postdomtree.ref

PostDomTree(f::Function) = PostDomTree(API.LLVMCreatePostDominatorTree(f))
dispose(postdomtree::PostDomTree) = API.LLVMDisposePostDominatorTree(postdomtree)

function dominates(postdomtree::PostDomTree, A::Instruction, B::Instruction)
convert(Core.Bool, API.LLVMPostDominatorTreeInstructionDominates(postdomtree, A, B))
end
72 changes: 72 additions & 0 deletions test/analysis_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,76 @@ end
verify(fn)
end

@dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("SomeModule") begin
ft = LLVM.FunctionType(LLVM.VoidType())
fn = LLVM.Function(mod, "SomeFunction", ft)
@test isempty(parameters(fn))

ft = LLVM.FunctionType(LLVM.VoidType(), [LLVM.Int1Type()])
fn = LLVM.Function(mod, "SomeOtherFunction", ft)
@test !isempty(parameters(fn))

bb1 = BasicBlock(fn, "entry")
bb2 = BasicBlock(fn, "then")
bb3 = BasicBlock(fn, "else")

position!(builder, bb1)
allocinst1 = alloca!(builder, LLVM.Int8Type())
brinst = br!(builder, parameters(fn)[1], bb2, bb3)
@test opcode(brinst) == LLVM.API.LLVMBr

position!(builder, bb2)
retinst2 = ret!(builder)

position!(builder, bb3)
allocinst3 = alloca!(builder, LLVM.Int8Type())
retinst3 = ret!(builder)

domtree = LLVM.DomTree(fn)
@test dominates(domtree, allocinst1, brinst)
@test dominates(domtree, allocinst1, retinst2)
@test dominates(domtree, allocinst1, allocinst3)
@test dominates(domtree, allocinst1, retinst3)
@test !dominates(domtree, brinst, allocinst1)
@test dominates(domtree, brinst, retinst2)
@test dominates(domtree, brinst, allocinst3)
@test dominates(domtree, brinst, retinst3)
@test !dominates(domtree, retinst2, allocinst1)
@test !dominates(domtree, retinst2, retinst3)
@test !dominates(domtree, retinst2, brinst)
@test !dominates(domtree, retinst2, allocinst3)
@test !dominates(domtree, retinst3, allocinst1)
@test !dominates(domtree, retinst3, retinst2)
@test !dominates(domtree, retinst3, brinst)
@test !dominates(domtree, retinst3, allocinst3)
@test !dominates(domtree, allocinst3, allocinst1)
@test !dominates(domtree, allocinst3, brinst)
@test !dominates(domtree, allocinst3, retinst2)
@test dominates(domtree, allocinst3, retinst3)
dispose(domtree)

postdomtree = LLVM.PostDomTree(fn)
@test !dominates(postdomtree, allocinst1, brinst)
@test !dominates(postdomtree, allocinst1, retinst2)
@test !dominates(postdomtree, allocinst1, retinst3)
@test !dominates(postdomtree, allocinst1, allocinst3)
@test dominates(postdomtree, brinst, allocinst1)
@test !dominates(postdomtree, brinst, retinst2)
@test !dominates(postdomtree, brinst, retinst3)
@test !dominates(postdomtree, brinst, allocinst3)
@test !dominates(postdomtree, retinst2, allocinst1)
@test !dominates(postdomtree, retinst2, retinst3)
@test !dominates(postdomtree, retinst2, brinst)
@test !dominates(postdomtree, retinst2, allocinst3)
@test !dominates(postdomtree, retinst3, allocinst1)
@test !dominates(postdomtree, retinst3, retinst2)
@test !dominates(postdomtree, retinst3, brinst)
@test dominates(postdomtree, retinst3, allocinst3)
@test !dominates(postdomtree, allocinst3, allocinst1)
@test !dominates(postdomtree, allocinst3, brinst)
@test !dominates(postdomtree, allocinst3, retinst2)
@test !dominates(postdomtree, allocinst3, retinst3)
dispose(postdomtree)
end

end

0 comments on commit 6096371

Please sign in to comment.