StaticLLVM
Documentation for StaticLLVM
StaticLLVM.LLVMBlockStaticLLVM.MethodInfoStaticLLVM.ModVarInfoStaticLLVM.ModuleInfoStaticLLVM.assemble_modinfoStaticLLVM.buildStaticLLVM.clean_cacheStaticLLVM.collect_methods!StaticLLVM.collect_modvar_pairsStaticLLVM.compile_llvm_filesStaticLLVM.dump_llvm_irStaticLLVM.emit_llvmStaticLLVM.emit_llvmStaticLLVM.emit_nativeStaticLLVM.emit_nativeStaticLLVM.extract_llvmStaticLLVM.find_matching_braceStaticLLVM.get_arg_typesStaticLLVM.get_configStaticLLVM.get_mod_filepathStaticLLVM.is_static_codeStaticLLVM.load_pkgStaticLLVM.make_modvar_defStaticLLVM.patch_memory_alloc!StaticLLVM.patch_memory_instance!StaticLLVM.pyprintStaticLLVM.recover_heap_objectStaticLLVM.recover_heap_objectStaticLLVM.remove_memoryref_callsStaticLLVM.remove_substringsStaticLLVM.replace_memory_allocStaticLLVM.run_commandStaticLLVM.split_blocksStaticLLVM.strip_commentsStaticLLVM.strip_gc_allocationsStaticLLVM.write_if_changed
StaticLLVM.LLVMBlock — TypeLLVMBlock(lable::Symbol, index::Int, ir::SubString{String})Represents a basic block in LLVM IR with its label, index (order), and IR body.
label::Symbol:Identifier for the LLVM IR block, e.g.:entry,:L3, etc.index::Int: The order of block in LLVM IR function.ir::SubString{String}: A substring view of the whole block.
StaticLLVM.MethodInfo — TypeMethodInfo(m::Core.Method)
MethodInfo(m::Core.Method, name::Symbol())A mutable struct that stores metadata and compiled LLVM IR information for a specific Julia method.
Fields
name::Symbol: A user-friendly name for the method. Defaults to the mangled name if not provided.mangled::Symbol: The internal compiler name of the method, used for LLVM IR lookup.arg_types::Tuple: A tuple of argument types (excluding the function type), derived from the method signature.method::Core.Method: The original JuliaMethodobjectllvm_ir::String: The LLVM IR code generated for the method, extracted as a string.
StaticLLVM.ModVarInfo — TypeModVarInfo(name::String, mod::Module, mangled::String, llvm_def::String, llvm_decl::String)Holds metadata for a module-level mutable variable (ModVar):
name::Symbol: Julia binding namefile::Symbol: file of mod-varsmangled::String: LLVM mangled global namellvm_def::String: LLVM IR global variable definitionllvm_decl::String: LLVM IR external declaration
StaticLLVM.ModuleInfo — TypeModuleInfoStores metadata associated with a Julia Module, including referenced methods and global module-level variables.
Fields
mod::Module: The Julia module this information is associated with.mangled::String: The mangled name of the module, following the Itanium C++ ABImodvars::IdSet{ModVarInfo}: A set of global static variables (ModVarInfo) used in this module. Identity-based (IdSet) to ensure uniqueness by object reference.methods::Vector{MethodInfo}: A list of methods (MethodInfo) defined or referenced within this module.
Usage
ModuleInfo is typically constructed internally during code analysis or code generation workflows to track both method definitions and global state referenced by a module.
StaticLLVM.assemble_modinfo — Methodassemble_modinfo(config::Dict{String,Any}, method_map::IdDict{Core.Method,Symbol}, modvar_map::IdDict{UInt,ModVarInfo}, check_ir::Bool = true) -> IdDict{Module, ModuleInfo}Constructs ModuleInfo objects that capture method-level (MethodInfo) and global variable (ModVarInfo) metadata within each Julia module.
Each entry in method_map is processed to generate a MethodInfo object containing LLVM IR and related properties. Similarly, each global variable entry in modvar_map is assigned to the appropriate module.
Arguments
config::Dict{String,Any}: Configuration dictionary. Must include keys like"debug"and"policy", controlling diagnostics and symbol filtering.method_map::IdDict{Core.Method,Symbol}: Maps JuliaMethodobjects to their LLVM mangled symbol names.modvar_map::IdDict{UInt,ModVarInfo}: Maps raw pointer addresses (asUInt) to their corresponding global variable metadata.
LLVM IR policy Behavior
:warn: Emits a warning if non-static LLVM IR is found.:strict: Throws an error.:strip: Attempts to strip the specific GC-related IR allocations:strip_all: Attempts to strip all GC-related IR allocations.
Returns
- An
IdDict{Module, ModuleInfo}mapping each involved JuliaModuleto its assembledModuleInforepresentation, including static methods and module-level variables.
StaticLLVM.build — Functionbuild(mod::Module=Main, config::Dict=default_config())Main build process:
- Parse arguments if called from
Main. - Collect global variables and method info.
- Dump LLVM IR files.
- Optionally compile with clang.
Arguments
mod: The module to process (defaults toMain).config: Build configuration dictionary.
Supported compile modes:
:none– Just generate IR:onefile– Compile all IR into a single binary:makefile– (Not implemented)
StaticLLVM.clean_cache — Methodclean_cache(path::String)Delete cached build files (e.g., .o, .so, .dll, .lib, .a, .dylib) under the given directory. This is useful for cleaning intermediate or compiled files before a fresh build.
Arguments
path: Directory where cache files are stored.
StaticLLVM.collect_methods! — Functioncollect_methods!(name_map::IdDict{Method, Symbol}, method::Method)Recursively collect methods starting from method, ensuring all are precompiled and mapped to mangled names. This function avoids use of global state by requiring an explicit name map to be passed in.
Arguments
method::Method: The starting method to process.name_map::IdDict{Method, Symbol}: A dictionary to store original methods and their original names.
Behavior
- Ensures the method is precompiled.
- Stores a mapping from the method to its mangled name.
- Recursively processes
Core.MethodInstanceobjects found inmethod.roots.
StaticLLVM.collect_modvar_pairs — Methodcollect_modvars(mod::Module) -> Vector{Tuple{Int, ModVarInfo}}Recursively collects all mutable, constant global variables defined in a Julia module mod (excluding functions, types, and strings), and returns a list of (pointer, ModVarInfo) pairs.
Each ModVarInfo contains:
- the original symbol name
- the module it belongs to
- its mangled LLVM symbol name
- its LLVM IR definition and declaration
StaticLLVM.compile_llvm_files — Methodcompile_llvm_files(config::Dict)Compile all LLVM IR files in a specified directory into a single output binary.
Expected keys in config:
"module": Name of the output executable."dir": Directory containing.llfiles."clang": Path toclangcompiler."cflag": Compiler flags (as a single string, e.g. "-O2 -flto").
Prints status messages and compilation result.
StaticLLVM.dump_llvm_ir — Methoddump_llvm_ir(modinfo::ModuleInfo, output_dir::String, check::Bool)Write LLVM IR files for a given ModuleInfo instance.
- Writes the IR of static module variables into one file named after the module.
- Writes the IR for each method individually into separate files.
- Skips writing files if content is unchanged (if
checkis true).
StaticLLVM.emit_llvm — Functionemit_llvm(fn::Function, args::Union{Tuple, Nothing}=nothing; clean::Bool=true, dump::Bool=true) -> StringGenerate LLVM IR for a specific method of a Julia function specialized on given argument types.
Arguments
fn: Julia function whose LLVM IR is requested.args: Tuple of argument types specifying the method specialization; ifnothing, expect exactly one method forfn.clean: Remove extraneous comments and optionally add header if true (default: true).dump: Include full LLVM module in output if true (default: true).
Returns
- LLVM IR string of the matched method, optionally cleaned.
Behavior
- If
argsis provided, usewhichto find the exact method. - If
argsisnothing, expectfnto have exactly one method, or throw an error. - Delegates actual IR emission to another
emit_llvmmethod accepting aMethod.
Example
ir = emit_llvm(sin, (Float64,); clean=true, dump=false)
println(ir)
add(x::Int) = x + 1
ir = emit_llvm(add)
println(ir)StaticLLVM.emit_llvm — Methodemit_llvm(method::Core.Method; clean::Bool=true, dump::Bool=true) -> StringGenerate the LLVM IR for a given Julia method.
Arguments
method: TheCore.Methodobject to generate LLVM IR for.clean: Iftrue, strip comments and optionally prepend a header comment. Default istrue.dump: Iftrue, include the full LLVM module in the output. Default istrue.
Returns
- A string containing the LLVM IR of the method. When
cleanistrue, comments are stripped.
Details
- Extracts the function instance and argument types from the method signature.
- Uses
InteractiveUtils.code_llvmto get the LLVM IR as a string. - Optionally cleans the IR by removing comments using
strip_comments. - When cleaning, adds the method signature as a header comment.
Example
ir = emit_llvm(my_method, clean=true, dump=false)
println(ir)StaticLLVM.emit_native — Functionemit_native(fn::Function, args::Union{Tuple, Nothing}=nothing; clean::Bool=true, dump::Bool=true) -> StringGenerate native LLVM assembly for a specific method of a Julia function given argument types.
Arguments
fn: Julia function whose LLVM IR is requested.args: Tuple of argument types specifying the method specialization; ifnothing, expect exactly one method forfn.clean: Remove extraneous comments and optionally add header if true (default: true).dump: Include full LLVM module in output if true (default: true).
Returns
- A string containing the native LLVM assembly code.
- When
cleanistrue, comments and debug info are removed.
Behavior
- If
argsis provided, usewhichto find the exact method. - If
argsisnothing, expectfnto have exactly one method, or throw an error. - Delegates actual IR emission to another
emit_llvmmethod accepting aMethod.
Example
ir = emit_native(sin, (Float64,); clean=true, dump=false)
println(ir)
add(x::Int) = x + 1
ir = emit_native(add)
println(ir)StaticLLVM.emit_native — Methodemit_native(method::Core.Method; clean::Bool=true, dump::Bool=true) -> StringGenerate the native LLVM bitcode (assembly) for a given Julia method.
Arguments
method: TheCore.Methodto generate native code for.clean: Iftrue, remove comments and debug info from the output. Default istrue.dump: Iftrue, include the full module dump. Default istrue.
Returns
- A string containing the native LLVM assembly code.
- When
cleanistrue, comments and debug info are removed.
Details
- Extracts the function instance and argument types from the method signature.
- Calls
InteractiveUtils.code_nativeto get native LLVM assembly. - Controls debug info level:
:noneif clean, otherwise:default. - Optionally cleans the output by stripping comments.
Example
native_ir = emit_native(my_method, clean=true, dump=false)
println(native_ir)StaticLLVM.extract_llvm — Functionextract_llvm(method::Core.Method, ir::String; main::Bool=false) -> StringExtract and clean up the LLVM IR of a single Julia-compiled function from the full IR string ir.
Arguments
method::Core.Method: The Julia method to locate in the LLVM IR.ir::String: The full LLVM IR text to search within.main::Bool=false: If true, rename the function to@main, otherwise use the Julia function name.
Returns
String: A cleaned and rewritten IR block for the requested function, including global constants and necessary declarations.
Notes
- Handles name mangling in
@julia_<funcname>_<id>style. - Rewrites global constant names for uniqueness.
- Gathers required
declarelines and LLVM attributes for external linkage.
StaticLLVM.find_matching_brace — Functionfind_matching_brace(s::String, start_pos::Int=1) -> IntFinds the index of the closing brace '}' that matches the first opening brace '{' found at or after start_pos in the string s.
Returns the index of the matching closing brace, or -1 if:
- No opening brace is found at or after
start_pos, or - Braces are unbalanced and a match can't be found.
Arguments
s: The input string to search.start_pos: The position in the string to start searching from (1-based). Defaults to 1.
Example
find_matching_brace("a{b{c}d}e") # returns 9
find_matching_brace("abc", 1) # returns -1StaticLLVM.get_arg_types — Methodget_arg_types(m::Core.Method) -> TupleExtracts the argument types (excluding the function itself) from the method's signature.
StaticLLVM.get_config — Methodget_config(; kwargs...) -> Dict{String, Any}Return a copy of the default config, with optional keyword overrides.
StaticLLVM.get_mod_filepath — Methodget_mod_filepath(mod::Module) -> SymbolRetrieve the source file path symbol where the given module mod is defined.
Arguments
mod::Module: The Julia module to inspect.
Returns
Symbol: The source file path as a Symbol if found.
Behavior
- Checks if the module has a special field
:_source_file_and returns it if present. - Otherwise, scans module names (excluding some built-ins) to find a function defined solely in this module and returns the file path of that function's method.
- Throws an error if no suitable source file path is found.
Notes
- Skips imported names and private names starting with
#. - Excludes names like
:evaland:includeto avoid common standard functions.
StaticLLVM.is_static_code — Methodis_static_code(ir::String)::BoolDetermines whether the given LLVM IR string is "static", i.e., free from dynamic symbols or Julia internal functions.
Returns
trueif the IR contains no known dynamic patterns.falseif any non-static signature (like@ijl_) is found.
StaticLLVM.load_pkg — Methodload_pkg() -> ModuleLoad a Julia package or source file specified by the first command-line argument (ARGS[1]).
Behavior
- If
ARGS[1]is a file path, includes the file and extracts the package name from the filename. - Otherwise, attempts to
importthe package by name. - If import fails and a directory with the package name exists, tries to include the source file under
./<package>/src/<package>. - Raises an error if the package cannot be found or loaded.
- Optionally, uses
ARGS[2]as the module name to return; defaults to the package name.
Returns
- The loaded Julia module.
Notes
- Depends on global
ARGSarray (command line arguments). - Prints status messages indicating loading steps.
Example
```bash julia script.jl MyPackage OptionalModuleName
StaticLLVM.make_modvar_def — Methodmake_modvar_def(name::String, value::T, is_const::Bool = false) -> (String, String)Generate LLVM IR global variable definition and external declaration strings for a Julia module variable.
name: The variable name to be used in LLVM IR (as@name).value: The Julia module variable value to represent.is_const: If true, the LLVM global is markedconstant; otherwise, it's mutable (global).
Returns a tuple (definition::String, declaration::String) where:
definitionis the LLVM IR global definition string with initialization.declarationis the LLVM IR external global declaration string.
Supported Julia types for value:
- Floating point: Float64, Float32
- Integer types: Int8, Int16, Int32, Int64, Int128 and unsigned equivalents
- Bool
- Ptr types
- String
- Immutable bitstypes (non-primitive)
Throws an error if the type is unsupported.
StaticLLVM.patch_memory_alloc! — Methodpatch_memory_alloc!(block::LLVMBlock, type_map::Vector{Pair{String, Int}}) -> BoolReplaces the LLVM IR code that performs allocation via jl_alloc_genericmemory with explicit malloc or calloc instructions, based on whether the allocated type is mutable or abstract.
Arguments
block: AnLLVMBlockcontaining the IR code.type_map: A list ofPair{String, Int}, mapping type IDs (e.g.,"GenericMemory#1222") to an integer flag (0 = mutable/abstract, 1 = concrete/immutable).
Returns
trueif the replacement occurred,falseotherwise.
StaticLLVM.patch_memory_instance! — Methodpatch_memory_instance!(blocks_map::Dict{Symbol, LLVMBlock}, block::LLVMBlock) -> BoolPatch the LLVM IR of a block to replace a specific Core.GenericMemory atomic load instruction and simplify its associated conditional branch logic.
Arguments
blocks_map: A dictionary mapping basic block names (asSymbol) toLLVMBlockobjects.block: The LLVM block whose IR may contain aCore.GenericMemoryload instruction.
Returns
trueif the block was modified,falseotherwise.
Description
This function searches for a specific pattern in the LLVM IR indicating the use of a hard-coded atomic load from Core.GenericMemory#<id>.jit. If found, the instruction is replaced with a cast from a globally defined pointer @GenericMemoryInstance. The jump logic immediately following the load is also simplified to jump unconditionally to the "success" label.
This is a low-level IR patching utility meant to canonicalize memory access logic.
StaticLLVM.pyprint — Methodpyprint(args...; sep=" ", tail="")
Print multiple arguments joined by a separator and ending with a specified tail string.
Arguments
args...: A variable number of arguments to be printed.sep: Separator string inserted between arguments. Default is a single space" ".tail: String appended at the end of the output. Default is newline `"
"`.
Behavior
- Converts all arguments to strings.
- Joins them with the separator.
- Prints the resulting string followed by the tail string.
Example
pyprint("Hello", "world", 123; sep=", ", tail="!
")
# Output: Hello, world, 123!StaticLLVM.recover_heap_object — Methodrecover_heap_object(addr::Integer) -> AnyGiven a raw address (e.g. from pointer_from_objref), attempts to reconstruct the original Julia object stored at that memory location.
This function inspects the memory layout:
- If the tag indicates a
String, reconstruct it. - If the tag seems to point to a valid heap-allocated
DataType, rehydrate the object.
Returns nothing if the tag is not recognizable or unsupported.
StaticLLVM.recover_heap_object — Methodrecover_heap_object(p::Ptr) -> AnyLow-level internal logic to reconstruct a Julia object from a raw pointer p. This inspects the memory tag to determine the type of the object.
Used internally by recover_heap_object.
StaticLLVM.remove_memoryref_calls — Methodremove_memoryref_calls(block::LLVMBlock) -> BoolScans the LLVM IR in block and removes all lines that match calls to @memoryref. Returns true if any modifications were made.
Arguments
block: TheLLVMBlockto process.
Returns
trueif the block's IR was modified,falseotherwise.
StaticLLVM.remove_substrings — Methodremove_substrings(input_str::AbstractString, ranges::Vector{Tuple{Int, Int}}) -> StringRemoves substrings from input_str specified by the list of ranges.
Arguments
input_str: The original string.ranges: A vector of(start, stop)index tuples indicating substrings to remove.
Returns
- A new string with the specified substrings removed.
Example
remove_substrings("Hello, world!", [(1,5), (8,8)]) # returns ", orld!"StaticLLVM.replace_memory_alloc — Methodreplace_memory_alloc(method::MethodInfo)Scans and patches LLVM IR in the given method to replace allocations related to Core.GenericMemory.
This function:
- Extracts memory layout sizes for GenericMemory types from method metadata.
- Iterates over all LLVM functions in the method, splits them into blocks.
- For each block, attempts to patch GenericMemory instances and allocations, and removes calls to
@memoryref. - Finally updates the LLVM IR in the method with the patched blocks.
Arguments
method: AMethodInfostruct containing LLVM IR and metadata.
Notes
- Relies on low-level unsafe pointer operations to inspect Julia internal data.
- Emits a warning if element size exceeds 256 bytes.
- Throws an error if no GenericMemory alias is found.
StaticLLVM.run_command — Methodrun_command(cmd::Cmd; verbose::Bool=false) -> NamedTupleRun the given command and capture its output.
Arguments
cmd: ACmdobject representing the system command to execute.verbose: If true, prints the command before execution.
Returns
A named tuple (success, code, output):
success:trueif the command succeeded,falseotherwise.code: Exit code (0 if success, -1 if error caught).output: Command output or error message as a string.
StaticLLVM.split_blocks — Methodsplit_blocks(ir::AbstractString) -> Vector{LLVMBlock}Splits a full LLVM IR string into a list of LLVMBlock objects, based on labeled basic blocks (e.g., entry:, L3:).
Arguments
ir: A string containing LLVM IR code.
Returns
- A vector of
LLVMBlockobjects, each representing a labeled block of IR code.
Example
blocks = split_blocks(ir_string)StaticLLVM.strip_comments — Methodstrip_comments(ir::String) -> StringRemoves comments and trailing whitespace from LLVM IR code lines, while preserving leading indentation and empty lines with no code content.
Arguments
ir: A multiline string containing LLVM IR code.
Returns
- A new string where each line has comments (starting with
;) and trailing spaces removed. - Lines that contain only whitespace or comments are omitted.
Details
- The function splits the input text into lines.
- For each line, it finds the first comment delimiter
;. - It keeps only the part of the line before the comment.
- Trailing whitespace is trimmed, but leading whitespace (indentation) is preserved.
- Empty or whitespace-only lines after stripping are skipped.
- The resulting lines are joined back with newline characters.
Example
code = """
define i32 @main() {
%1 = add i32 1, 2 ; addition
ret i32 %1 ; return value
}
"""
println(strip_comments(code))
# Output:
# define i32 @main() {
# %1 = add i32 1, 2
# ret i32 %1
# }StaticLLVM.strip_gc_allocations — Methodstrip_gc_allocations(ir::String)::StringClean up Julia IR by removing GC-related stack management and replacing @ijl_gc_pool_alloc_instrumented calls with standard malloc calls for further IR-level optimization or analysis.
Arguments
ir::String: The input LLVM IR string generated by Julia.
Returns
- A cleaned-up IR string with GC stack frames and pool allocation calls removed or replaced.
StaticLLVM.write_if_changed — Methodwrite_if_changed(filepath::String, content::String, check::Bool)::IntWrites content to filepath only if the file content has changed or doesn't exist. If check is false, no writing occurs.
Returns
- 1 if the file was written (or would be written).
- 0 if no writing was done due to
check == false.