diff --git a/src/dibuilder.jl b/src/dibuilder.jl index 6a80dfe7..eb46e321 100644 --- a/src/dibuilder.jl +++ b/src/dibuilder.jl @@ -1,3 +1,157 @@ +export DIBuilder, DIFile, DICompileUnit, DILexicalBlock, DISubprogram + +@checked struct DIBuilder + ref::API.LLVMDIBuilderRef +end + +# LLVMCreateDIBuilderDisallowUnresolved +DIBuilder(mod::Module) = DIBuilder(API.LLVMCreateDIBuilder(mod)) + +dispose(builder::DIBuilder) = API.LLVMDisposeDIBuilder(builder) +finalize(builder::DIBuilder) = API.LLVMDIBuilderFinalize(builder) + +Base.unsafe_convert(::Type{API.LLVMDIBuilderRef}, builder::DIBuilder) = builder.ref + +struct DIFile + file::String + dir::String +end + +struct DICompileUnit + file::Metadata + language::API.LLVMDWARFSourceLanguage + producer::String + sysroot::String + sdk::String + flags::String + optimized::Core.Bool + version::Int +end + +function compileunit!(builder::DIBuilder, cu::DICompileUnit) + md = API.LLVMDIBuilderCreateCompileUnit( + builder, + cu.language, + cu.file, + cu.producer, convert(Csize_t, length(cu.producer)), + cu.optimized ? LLVM.True : LLVM.False, + cu.flags, convert(Csize_t, length(cu.flags)), + convert(Cuint, cu.version), + #=SplitName=# C_NULL, 0, + API.LLVMDWARFEmissionFull, + #=DWOId=# 0, + #=SplitDebugInlining=# LLVM.True, + #=DebugInfoForProfiling=# LLVM.False, + cu.sysroot, convert(Csize_t, length(cu.sysroot)), + cu.sdk, convert(Csize_t, length(cu.sdk)), + ) + return Metadata(md) +end + +function file!(builder::DIBuilder, file::DIFile) + md = API.LLVMDIBuilderCreateFile( + builder, + file.file, convert(Csize_t, length(file.file)), + file.dir, convert(Csize_t, length(file.dir)) + ) + return Metadata(md) +end + +struct DILexicalBlock + file::Metadata + line::Int + column::Int +end + +function lexicalblock!(builder::DIBuilder, scope::Metadata, block::DILexicalBlock) + md = API.LLVMDIBuilderCreateLexicalBlock( + builder, + scope, + block.file, + convert(Cuint, block.line), + convert(Cuint, block.column) + ) + Metadata(md) +end + +function lexicalblock!(builder::DIBuilder, scope::Metadata, file::Metadata, discriminator) + md = API.LLVMDIBuilderCreateLexicalBlockFile( + builder, + scope, + file, + convert(Cuint, discriminator) + ) + Metadata(md) +end + +struct DISubprogram + name::String + linkageName::String + file::Metadata + line::Int + type::Metadata + localToUnit::Core.Bool + isDefinition::Core.Bool + scopeLine::Int + flags::LLVM.API.LLVMDIFlags + optimized::Core.Bool +end + +function subprogram!(builder::DIBuilder, f::DISubprogram) + md = API.LLVMDIBuilderCreateFunction( + builder, + f.file, + f.name, convert(Csize_t, length(f.name)), + f.linkageName, convert(Csize_t, length(f.linkageName)), + f.file, + f.line, + f.type, + f.localToUnit ? LLVM.True : LLVM.False, + f.isDefinition ? LLVM.True : LLVM.False, + convert(Cuint, f.scopeLine), + f.flags, + f.optimized ? LLVM.True : LLVM.False + ) + Metadata(md) +end + +# TODO: Variables + +function basictype!(builder::DIBuilder, name, size, encoding) + md = LLVM.API.LLVMDIBuilderCreateBasicType( + builder, + name, convert(Csize_t, length(name)), + convert(UInt64, size), + encoding, + LLVM.API.LLVMDIFlagZero + ) + Metadata(md) +end + +function pointertype!(builder::DIBuilder, basetype::Metadata, size, as, align=0, name="") + md = LLVM.API.LLVMDIBuilderCreatePointerType( + builder, + basetype, + convert(UInt64, size), + convert(UInt32, align), + convert(Cuint, as), + name, convert(Csize_t, length(name)), + ) + Metadata(md) +end + +function subroutinetype!(builder::DIBuilder, file::Metadata, rettype, paramtypes...) + params = collect(x for x in (rettype, paramtypes...)) + md = LLVM.API.LLVMDIBuilderCreateSubroutineType( + builder, + file, + params, + length(params), + LLVM.API.LLVMDIFlagZero + ) + Metadata(md) +end + function DILocation(ctx, line, col, scope=nothing, inlined_at=nothing) # XXX: are null scopes valid? they crash LLVM: # DILocation(Context(), 1, 2).scope @@ -5,3 +159,5 @@ function DILocation(ctx, line, col, scope=nothing, inlined_at=nothing) something(scope, C_NULL), something(inlined_at, C_NULL))) end + +# TODO: Types \ No newline at end of file diff --git a/test/dibuilder.jl b/test/dibuilder.jl new file mode 100644 index 00000000..43d0b4fa --- /dev/null +++ b/test/dibuilder.jl @@ -0,0 +1,69 @@ +@testset "dibuilder" begin + +Context() do ctx +LLVM.Module("SomeModule", ctx) do mod + builder = DIBuilder(mod) + dispose(builder) +end +end + +Context() do ctx +LLVM.Module("SomeModule", ctx) do mod + dibuilder = DIBuilder(mod) + file = DIFile("test.jl", "src") + file_md = LLVM.file!(dibuilder, file) + cu = DICompileUnit(file_md, LLVM.API.LLVMDWARFSourceLanguageJulia, "LLVM.jl Tests", "/", "LLVM.jl", "", false, 4) + cu_md = LLVM.compileunit!(dibuilder, cu) + + Builder(ctx) do builder + ft = LLVM.FunctionType(LLVM.VoidType(ctx), [LLVM.Int64Type(ctx)]) + rt_md = LLVM.basictype!(dibuilder, "Nothing", 0, 0) + param_md = LLVM.basictype!(dibuilder, "Int64", sizeof(Int64), 0) + dift_md = LLVM.subroutinetype!(dibuilder, file_md, rt_md, param_md) + fn = LLVM.Function(mod, "SomeFunction", ft) + difn = DISubprogram(LLVM.name(fn), "linkage", file_md, 3, dift_md, true, true, 5, LLVM.API.LLVMDIFlagPublic, false) + difn_md = LLVM.subprogram!(dibuilder, difn) + LLVM.set_subprogram!(fn, difn_md) + + entrybb = BasicBlock(fn, "entry") + position!(builder, entrybb) + + ptr = inttoptr!(builder, parameters(fn)[1], LLVM.PointerType(LLVM.Int64Type(ctx))) + ptr_md = LLVM.pointertype!(dibuilder, param_md, sizeof(Ptr{Int64}), LLVM.addrspace(llvmtype(ptr)), 0, "MyPtr") + # TODO: LLVM.dbg_declare!(builder, mod, ptr, ptr_md) + val = ptrtoint!(builder, ptr, LLVM.Int64Type(ctx)) + + block = DILexicalBlock(file_md, 1, 1) + block_md = LLVM.lexicalblock!(dibuilder, file_md, block) # could also be file + debuglocation!(builder, LLVM.MetadataAsValue(LLVM.API.LLVMMetadataAsValue(ctx, block_md))) + ret!(builder) + end + + finalize(dibuilder) + dispose(dibuilder) + + fun = functions(mod)["SomeFunction"] + bb = entry(fun) + inst = last(instructions(bb)) + @test !isempty(metadata(inst)) + inst_str = sprint(io->Base.show(io, inst)) + @test occursin("!dbg", inst_str) + + @test !isempty(metadata(inst)) + mod_str = sprint(io->Base.show(io, mod)) + @test occursin("!llvm.dbg.cu", mod_str) + @test occursin("!DICompileUnit", mod_str) + @test occursin("!DIFile", mod_str) + @test occursin("!DILexicalBlock", mod_str) + @test !occursin("scope: null", mod_str) + @test occursin("DISubprogram", mod_str) + @test occursin("DISubroutineType", mod_str) + @test occursin("DIBasicType", mod_str) + + strip_debuginfo!(mod) + @test isempty(metadata(inst)) +end +end + +end + diff --git a/test/runtests.jl b/test/runtests.jl index 6031d2d6..9b4b4eca 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -83,11 +83,11 @@ if LLVM.has_orc_v2() include("orcv2.jl") end +include("dibuilder.jl") include("Kaleidoscope.jl") include("examples.jl") include("interop.jl") - end