Repository: JuliaLang/julia
File: stdlib/InteractiveUtils/src/codeview.jl (Julia)

Code before:
    llvmf_dump = Ref{LLVMFDump}()
    @ccall jl_get_llvmf_defn(llvmf_dump::Ptr{LLVMFDump}, mi::Any, src::Any, wrapper::Bool,
                             true::Bool, ""::Cstring, params::CodegenParams)::Cvoid
    llvmf_dump[].f == C_NULL && error("could not compile the specified method")
    str = @ccall jl_dump_function_asm(llvmf_dump::Ptr{LLVMFDump}, false::Bool,
                                      syntax::Ptr{UInt8}, debuginfo::Ptr{UInt8},
                                      binary::Bool, raw::Bool)::Ref{String}
    return str
end

function _dump_function_llvm(
        mi::Core.MethodInstance, src::Core.CodeInfo, wrapper::Bool,
        strip_ir_metadata::Bool, dump_module::Bool,
        optimize::Bool, debuginfo::Symbol,
        llvm_options::String,
        params::CodegenParams)
    llvmf_dump = Ref{LLVMFDump}()
    @ccall jl_get_llvmf_defn(llvmf_dump::Ptr{LLVMFDump}, mi::Any, src::Any,
                             wrapper::Bool, optimize::Bool, llvm_options::Cstring,
                             params::CodegenParams)::Cvoid
    llvmf_dump[].f == C_NULL && error("could not compile the specified method")
    # Capture pass instrumentation output before dumping IR (which frees the dump)
    pass_output_ptr = llvmf_dump[].pass_output
    pass_output = if pass_output_ptr != C_NULL
        s = unsafe_string(pass_output_ptr)
        Libc.free(pass_output_ptr)
        s
    else
        ""
    end
    str = @ccall jl_dump_function_ir(llvmf_dump::Ptr{LLVMFDump}, strip_ir_metadata::Bool,
                                     dump_module::Bool, debuginfo::Ptr{UInt8})::Ref{String}
    # Prepend pass output to final IR
    return isempty(pass_output) ? str : pass_output * str
end

"""
    code_llvm([io=stdout,], f, types; raw=false, dump_module=false, optimize=true, debuginfo=:default, llvm_options="")

Prints the LLVM bitcodes generated for running the method matching the given generic
function and type signature to `io`.

If the `optimize` keyword is unset, the code will be shown before LLVM optimizations.
All metadata and dbg.* calls are removed from the printed bitcode. For the full IR, set the `raw` keyword to true.
To dump the entire module that encapsulates the function (with declarations), set the `dump_module` keyword to true.
Keyword argument `debuginfo` may be one of source (default) or none, to specify the verbosity of code comments.

The `llvm_options` keyword argument allows passing LLVM options to control the optimization pipeline output.
Supported options include:
- `-print-after-all`: Print IR after each pass
- `-print-before-all`: Print IR before each pass

Review comment (bug):
This should be freed by the same shared library that allocated it. Freeing objects from a different place than you allocated it leads to awkwardness (aka crashes) when you try to use alternatively allocators like mimalloc, and is an anti-pattern that should be always avoided

Code after:
        strip_ir_metadata::Bool, dump_module::Bool,
        optimize::Bool, debuginfo::Symbol,
        llvm_options::String,
        params::CodegenParams)
    llvmf_dump = Ref{LLVMFDump}()
    @ccall jl_get_llvmf_defn(llvmf_dump::Ptr{LLVMFDump}, mi::Any, src::Any,
                             wrapper::Bool, optimize::Bool, llvm_options::Cstring,
                             params::CodegenParams)::Cvoid
    llvmf_dump[].f == C_NULL && error("could not compile the specified method")
    # jl_dump_function_ir handles pass_output internally (prepends it and frees it)
    str = @ccall jl_dump_function_ir(llvmf_dump::Ptr{LLVMFDump}, strip_ir_metadata::Bool,
                                     dump_module::Bool, debuginfo::Ptr{UInt8})::Ref{String}
    return str
end

"""
    code_llvm([io=stdout,], f, types; raw=false, dump_module=false, optimize=true, debuginfo=:default, llvm_options="")

Prints the LLVM bitcodes generated for running the method matching the given generic
function and type signature to `io`.

If the `optimize` keyword is unset, the code will be shown before LLVM optimizations.
All metadata and dbg.* calls are removed from the printed bitcode. For the full IR, set the `raw` keyword to true.
To dump the entire module that encapsulates the function (with declarations), set the `dump_module` keyword to true.
Keyword argument `debuginfo` may be one of source (default) or none, to specify the verbosity of code comments.

The `llvm_options` keyword argument allows passing LLVM options to control the optimization pipeline output.
Supported options include:
- `-print-after-all`: Print IR after each pass
- `-print-before-all`: Print IR before each pass
- `-print-after=<passname>`: Print IR after a specific pass (e.g., `-print-after=InstCombinePass`). Comma-separated lists and repeated flags are supported.
- `-print-before=<passname>`: Print IR before a specific pass. Comma-separated lists and repeated flags are supported.
- `-print-module-scope`: Print entire module instead of just the function
- `-filter-print-funcs=<name>`: Only print IR for functions matching the name

See also: [`@code_llvm`](@ref), [`code_warntype`](@ref), [`code_typed`](@ref), [`code_lowered`](@ref), [`code_native`](@ref).
"""
function code_llvm(io::IO, arginfo::ArgInfo;
                   raw::Bool=false, dump_module::Bool=false, optimize::Bool=true, debuginfo::Symbol=:default,
                   llvm_options::String="",
                   params::CodegenParams=CodegenParams(debug_info_kind=Cint(0), debug_info_level=Cint(2), safepoint_on_entry=raw, gcstack_arg=raw))
    d = _dump_function(arginfo, false, false, raw, dump_module, :intel, optimize, debuginfo, false, llvm_options, params)
    if highlighting[:llvm] && get(io, :color, false)::Bool
        print_llvm(io, d)
    else
        print(io, d)
    end
end
code_llvm(io::IO, @nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}); kwargs...) = code_llvm(io, ArgInfo(argtypes); kwargs...)
code_llvm(io::IO, @nospecialize(f), @nospecialize(types=Base.default_tt(f)); kwargs...) = code_llvm(io, ArgInfo(f, types); kwargs...)
code_llvm(args...; kwargs...) = (@nospecialize; code_llvm(stdout, args...; kwargs...))