Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

LLVM PassBuilder Registry

Abstract

Tileiras embeds an LLVM PassBuilder registry that resolves textual pass names to factory callbacks. It is the mechanism by which strings inside --pass-pipeline="..." arguments turn into pass instances, and it is the same mechanism the driver uses when the inner serialization stage builds its LLVM optimization pipeline from a named OptimizationLevel. The registry holds 551 entries: 478 reached through templated getTypeName<T>() keys derived from C++ pass class names, 66 reached through bare string keys for passes that opt out of the templated path, 5 pipeline aliases that expand to multi-pass sequences, and 2 specials for analysis printing and verification. The registrar populates the global StringMap at static-init time before any compilation begins, so the table is read-only during compile and the textual resolver runs as a single hash lookup.

The registry is a menu, not a schedule. An entry being present means a user could ask for the pass by name; it does not mean the default Tileiras pipeline runs that pass.

Registry Families

FamilyExamplesRole
Module analysescall graph, profile summary, verifier analysisQuery module-wide facts.
Module transformsinlining, internalization, global optimizationRewrite whole modules.
CGSCC passesinliner and call-graph transformsOptimize call-graph components.
Function analysesalias analysis, dominators, loops, scalar evolutionQuery function-local facts.
Function transformsinstcombine, GVN, vectorization, NVVM cleanupRewrite LLVM IR functions.
Loop passesLICM, rotate, unswitch, unrollRewrite loops.
Machine passesregister allocation, scheduling, MIR cleanupRewrite MachineIR.

NVIDIA-Specific Entries

Pass nameStagePurpose
check-gep-indexModuleValidate constant GEP indices after frontend cleanup.
check-kernel-functionsModuleNormalize kernel and non-kernel function linkage (see Kernel/CDP/Inline/Pretreat — Kernel Identity).
cnp-launch-checkModuleValidate CUDA dynamic-parallelism launch calls (see Kernel/CDP/Inline/Pretreat — CDP Launch Expansion).
ipmspModuleSpecialize generic-pointer callees by memory space.
nv-early-inlinerModuleRun an NVIDIA-tuned early inliner (see Kernel/CDP/Inline/Pretreat).
nv-inline-mustModuleForce-inline functions whose ABI cannot survive as calls (see Kernel/CDP/Inline/Pretreat).
nvvm-pretreatModuleCanonicalize raw NVVM IR before verification and optimization (see Kernel/CDP/Inline/Pretreat).
nvvm-verifyModuleCheck NVVM kernel launches and parameter-space usage (see NVVM IR Verifier).
printf-loweringModuleLower device printf to the vprintf ABI (see printf Lowering and vprintf).
select-kernelsModuleRestrict processing to selected kernels for diagnostics/testing.
nvvm-aaFunction analysisProvide address-space-aware alias information.
kernel-infoFunctionEmit per-kernel diagnostic metrics.
nvvm-peephole-optimizerFunctionSimplify NVVM IR and address arithmetic before selection (see Peephole MIR and Image Handles).
propagate-alignmentFunctionPropagate alignment facts through memory operations.
reuse-local-memoryFunctionReuse non-overlapping local-memory slots.
memory-space-optFunctionInfer and rewrite concrete address spaces (see Memory-Space-Opt and Process-Restrict).
lower-aggr-copiesFunctionExpand unsupported aggregate memory intrinsics (see lower-args, lower-aggr-copies, lower-struct-args).
lower-struct-argsFunctionLower by-value struct kernel parameters (see lower-args, lower-aggr-copies, lower-struct-args).
process-restrictFunctionMaterialize __restrict__ alias metadata (see Memory-Space-Opt and Process-Restrict).

The same registry also exposes stock LLVM names such as default, thinlto, lto, verify, inline, function-simplification, and machine-pipeline passes like greedy, regallocfast, machine-scheduler, and virt-reg-rewriter. Those names are useful for textual LLVM pipeline experiments, but Tileiras' normal MLIR pipeline reaches the NVPTX backend through its own target handoff rather than through an arbitrary user-supplied LLVM text pipeline.

Registry Depth

The registry breaks down into five disjoint groups. The 478 templated entries dominate; they exist because LLVM's pass framework derives a string from the C++ class name through getTypeName<T>() and registers the factory under that string. The 66 naked-class entries are passes whose registered name is hand-written (usually because the templated name would be unwieldy or would collide with a stock LLVM pass). The 5 aliases are short names that expand to multi-pass sequences. The 2 specials wire up the analysis-print and verify infrastructure that LLVM's pass parser depends on.

GroupCountExamplesWhy this group
getTypeName<T>() keys478InstCombinePass, LICMPass, MachineCSEPassDefault registration; key derived from C++ type name.
Naked-class string keys66printf-lowering, nvvm-pretreat, select-kernelsManually named NVIDIA passes plus a handful of upstream passes that opt out of the templated key.
Pipeline aliases5default<O2>, thinlto<O3>, lto<O2>Expand to multi-pass strings inside the parser.
Specials2print<analysis>, verifyWire up the analysis-print and verify infrastructure.
Total551

The 478 + 66 + 5 + 2 = 551 sum is the registry's full depth. There is no overflow path; an unknown name is a parser error, not a fallback to a generic factory.

Static-Init Registrar

The registrar is a single function that calls PassBuilder::registerPipelineParsingCallback once per entry. It runs at static initialization time because each RegisterPass<T> global constructor inserts into the same StringMap. The map's load factor and bucket count are sized at first use; the registrar uses StringMap::insert which is O(1) amortized. After static-init the map is never mutated.

void register_passbuilder_entries(PassBuilder &pb) {
    register_templated_module_passes(pb);     // contributes to the 478
    register_templated_function_passes(pb);   // contributes to the 478
    register_templated_loop_passes(pb);       // contributes to the 478
    register_templated_machine_passes(pb);    // contributes to the 478

    register_named_nvvm_passes(pb);           // contributes to the 66
    register_named_nvptx_passes(pb);          // contributes to the 66

    register_pipeline_aliases(pb);            // the 5
    register_print_and_verify(pb);            // the 2
}

The split between templated and named registration is what allows NVIDIA-private passes to be interleaved with upstream LLVM passes in the same registry: upstream passes register under their templated keys; NVIDIA passes register under hand-chosen names from the nv-*, nvvm-*, cnp-*, check-*, and lower-* families.

Textual Resolution

The parser resolves pass names in the context of the current pipeline level. The same string can appear at module, CGSCC, function, loop, and machine-function levels without collision because the parser only consults the registry slice for the manager it is currently constructing.

Expected<PassPlugin> parse_pass(PipelineLevel level, StringRef text) {
    auto [name, options] = split_name_and_options(text);  // "pass{key=value,...}"

    auto *info = lookup_registry_for_level(level, name);
    if (!info) {
        return make_error<StringError>(
            "unknown pass '" + name + "' at " + describe_level(level));
    }

    PassOptions parsed_opts;
    if (failed(parse_option_block(options, info->schema, parsed_opts))) {
        return make_error<StringError>(
            "invalid option block for pass '" + name + "'");
    }
    return info->construct(parsed_opts);
}

Name matching is case-sensitive and exact on the name portion. The optional {key=value,...} block is parsed against the per-pass schema after the lookup succeeds; an unrecognized option key is rejected rather than silently ignored.

Relationship to TileIR Passes

TileIR MLIR passes are scheduled by the Tileiras pipeline builder against MLIR's own registry, which is independent of this LLVM PassBuilder registry. The LLVM registry is consulted only after the inner pipeline reaches LLVM/NVVM IR or when a user supplies a textual LLVM pipeline through --passes= to the embedded NVPTX backend. A pass appearing here is not scheduled by Tileiras's default flow unless populate_pipeline or run_llvm_passbuilder_pipeline references it explicitly.

Cross-References

Compilation Pipeline Overview — Serialization Boundary describes where in the outer/inner split this registry is consulted. Pipeline Options Mapping names the options that the inner LLVM pipeline reads through the registry's factories. Pass List by Optimization Level — Handoff to LLVM/NVPTX is the MLIR-tier pass list that runs before this registry comes into play. NVPTX Backend Passes overview is where the NVIDIA-specific entries above are described pass by pass.