LLVM 22.x tile for building compilers, language runtimes, and out-of-tree tooling
88
83%
Does it follow best practices?
Impact
96%
1.23xAverage score across 5 eval scenarios
Passed
No known issues
Use this skill when you want cross-module optimization — inlining, devirtualization, dead-code elimination, or whole-program alias analysis — across separately compiled translation units.
| Full LTO | ThinLTO | |
|---|---|---|
| How it works | All bitcode merged into one giant module, then optimized | Per-module summaries at compile time; parallel backends at link time |
| Memory use | Very high (all IR in RAM at once) | Much lower (only imported pieces) |
| Link time | Slow for large programs | Fast, parallelism-friendly |
| Optimization quality | Maximum (whole-program view) | Close to full LTO for most workloads |
| When to use | Small-to-medium programs, maximum perf | Large codebases (Chromium-scale) |
If your compiler emits bitcode files (.bc) or hands off to Clang for linking:
#include "llvm/Bitcode/BitcodeWriter.h"
// After all IR is generated and verified:
std::error_code EC;
llvm::raw_fd_ostream OS("output.bc", EC, llvm::sys::fs::OF_None);
if (EC) { llvm::errs() << "Error: " << EC.message() << "\n"; return 1; }
llvm::WriteBitcodeToFile(*M, OS);# Compile step: emit bitcode-containing objects
clang -flto -O2 -c a.ll -o a.o
clang -flto -O2 -c b.ll -o b.o
# Link step: LLD does LTO internally
clang -flto -O2 -fuse-ld=lld a.o b.o -o progclang -flto=thin -O2 -c a.ll -o a.o
clang -flto=thin -O2 -c b.ll -o b.o
clang -flto=thin -O2 -fuse-ld=lld a.o b.o -o progRules:
-flto/-flto=thin flag at both compile and link.ld + LLVMgold.so plugin.If your compiler processes multiple modules in one process (e.g., a JIT or AOT driver), you can merge and optimize without file-based LTO:
#include "llvm/Linker/Linker.h"
// Start with an empty "combined" module
auto Combined = std::make_unique<llvm::Module>("combined", Ctx);
// Link each translation unit into it
llvm::Linker L(*Combined);
for (auto &TU : TranslationUnits) {
if (L.linkInModule(std::move(TU)))
llvm::report_fatal_error("Linking failed");
}#include "llvm/Passes/PassBuilder.h"
llvm::PassBuilder PB;
llvm::ModuleAnalysisManager MAM;
llvm::CGSCCAnalysisManager CGAM;
llvm::FunctionAnalysisManager FAM;
llvm::LoopAnalysisManager LAM;
PB.registerModuleAnalyses(MAM);
PB.registerCGSCCAnalyses(CGAM);
PB.registerFunctionAnalyses(FAM);
PB.registerLoopAnalyses(LAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
// Build an O2-equivalent pipeline for the combined module
llvm::ModulePassManager MPM =
PB.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O2);
MPM.run(*Combined, MAM);#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/TargetSelect.h"
// ... initialize target, create TargetMachine, emit object file ...
// (same as single-module compilation — see out-of-tree.md)For bitcode emission, add BitWriter to your llvm_map_components_to_libnames call:
llvm_map_components_to_libnames(LLVM_LIBS
core support bitwriter linker passes
# add your target(s) here
)
target_link_libraries(MyCompiler PRIVATE ${LLVM_LIBS})# Disassemble bitcode to readable IR
llvm-dis output.bc -o output.ll
# Assemble IR back to bitcode
llvm-as output.ll -o output.bc
# Inspect LTO sections in an object
llvm-readobj --llvm-bitcode-section output.o
# Check ThinLTO summary
llvm-readobj --thinlto-summary output.o| Symptom | Likely cause |
|---|---|
| Symbols undefined at link | Hidden visibility blocking import; check __attribute__((visibility("default"))) |
| ODR violations / wrong behavior | Two definitions of the same symbol; check for inline mismatches |
| LTO binary differs from non-LTO | Optimization exposing UB — check with -fsanitize=undefined |
| Linker ignores bitcode | Using a non-LTO-aware linker; switch to lld |
| Bitcode mismatch error | Mixing bitcode from different LLVM versions — pin to LLVM 22 |
-flto objects with a non-LTO-aware linker without understanding the consequences.llvm-dis to inspect failing modules when diagnosing IR-level LTO bugs.verifyModule(*M, &errs()) before running the optimization pipeline.docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
skills
add-alias-analysis
add-attributes-metadata
add-calling-convention
add-debug-info
add-exception-handling
add-gc-statepoints
add-intrinsic
add-lto
add-sanitizer
add-vectorization-hint
frontend-to-ir
jit-setup
lit-filecheck
lower-struct-types
new-target
out-of-tree-setup
tessl-llvm
version-sync