A pure Rust re-implementation of LLVM — no C++, no FFI, no llvm-sys. The full compiler pipeline from LLVM IR through optimization passes to machine code generation is implemented entirely in safe Rust.
The official LLVM is a C++ library that Rust projects consume through a fragile C FFI wrapper (llvm-sys). This project explores what a clean, idiomatic Rust implementation of the same pipeline looks like: arena-free ownership, type-safe index handles, trait-based pass infrastructure, and zero unsafe code in the core IR.
use llvm_in_rust_ir::{Builder, Context, Linkage, Module};
use llvm_in_rust_transforms::{build_pipeline, OptLevel};
fn main() {
// Build: i32 @add(i32 %a, i32 %b) { entry: %s = add i32 %a, %b ret i32 %s }
let mut ctx = Context::new();
let mut module = Module::new("example");
let mut b = Builder::new(&mut ctx, &mut module);
let i32_ty = b.ctx.i32_ty;
b.add_function(
"add",
i32_ty,
vec![i32_ty, i32_ty],
vec!["a".into(), "b".into()],
false,
Linkage::External,
);
let entry = b.add_block("entry");
b.position_at_end(entry);
let a = b.get_arg(0);
let bv = b.get_arg(1);
let sum = b.build_add("s", a, bv);
b.build_ret(sum);
drop(b);
// Run -O2 optimizations
let mut pm = build_pipeline(OptLevel::O2);
pm.run_until_fixed_point(&mut ctx, &mut module, 8);
println!(
"Optimized: {} functions, {} blocks",
module.functions.len(),
module.functions[0].blocks.len()
);
}See the src/llvm/examples/ directory for more runnable examples including dead-code
elimination (opt_pipeline.rs) and a full hello-world IR program (hello_world.rs).
LLVM-in-Rust is in a production-readiness stage, not a general drop-in LLVM replacement. Milestones A-U in the production roadmap are complete; the 2026-05-26 audit added release-blocking follow-up Milestones V-Z before any general production-ready declaration.
| Use case | Status | Boundary |
|---|---|---|
| Constrained production pilots | Supported with controls | Trusted LLVM 15+ opaque-pointer IR, pinned commits/releases, green release-blocking CI, and an explicitly supported backend/object-format combination. |
| General LLVM replacement | Not supported yet | The project still has open V-Z audit follow-ups, backend contract gaps, and RC burn-in requirements. |
| Untrusted or adversarial input | Not supported without sandboxing | Parser, optimizer, codegen, and JIT paths must run behind external process/container isolation, CPU/memory limits, and JIT disablement where inputs are not trusted. |
The workspace test inventory changes frequently and is intentionally not
hard-coded here. Treat CI plus the validation commands in
docs/production_operations.md as the current
source of truth for release-blocking quality status.
See docs/production_support_boundaries.md
for the public support contract, API stability matrix, and backend/platform
boundaries. See docs/sandbox_deployment.md
before routing untrusted or tenant-controlled input through parser,
optimization, codegen, object emission, or JIT paths.
LLVM-in-Rust follows Semantic Versioning with an explicit pre-1.0 stability policy:
0.x.yreleases: no public API stability guarantee. Any0.xminor-version bump may include breaking public API changes as the IR model, pass interfaces, and backend traits continue to mature.1.0.0readiness: the project will not declare a stable 1.0 API until the production-readiness roadmap's V-Z follow-up milestones are complete, release-candidate burn-in has passed, and maintainers have signed off at least one constrained production pilot with documented fallback.- Post-1.0 releases: standard SemVer rules apply. Breaking API changes are reserved for major versions and include a documented deprecation/migration cycle.
The pre-1.0 API stability matrix lives in
docs/production_support_boundaries.md.
Release notes live in CHANGELOG.md; the v0.1.0 GitHub release
links to the 0.1.0 changelog entry.
Benchmarks compare this project against LLVM 19.1.7 (Homebrew) on a 15-function
representative module (src/llvm-bench/fixtures/sample.ll, ~340 lines, integer/FP/memory ops).
Run the benchmarks yourself:
cargo bench -p llvm-in-rust-benchThe deterministic codegen corpus is locked by object checksums and runs in CI.
Unexpected drift should be investigated before updating baselines; intentional
updates use scripts/update_golden_codegen.sh --bless and require maintainer
sign-off. See docs/golden_codegen_gate.md.
Benchmarks use Criterion and run on stable Rust; no nightly-only bench harness is required.
| Pipeline stage | This project | LLVM 19 tool | LLVM 19 (processing only¹) |
|---|---|---|---|
Parse .ll → IR |
183 µs | llvm-as: 116 ms wall |
~36 ms |
Print IR → .ll |
33 µs | llvm-dis: 82 ms wall |
~2 ms |
| mem2reg pass | 80 µs² | opt -passes=mem2reg: 98 ms wall |
~10 ms |
| DCE pass | 55 µs² | opt -passes=dce: 90 ms wall |
~2 ms |
| x86_64 codegen | 116 µs | llc -O0: 108 ms wall |
~18 ms |
| Builder API (2 fns) | 2.4 µs | — | — |
¹ LLVM tool wall-clock includes ~80–90 ms process startup + dynamic library loading. "Processing only" subtracts the baseline measured with a trivial single-function input. This makes the comparison more representative of in-process library use.
² Mem2reg and DCE benchmarks include parsing the fixture on each iteration; net pass-only time is wall time minus the 183 µs parse cost.
-
This project runs in-process with zero startup cost, which explains most of the wall-clock advantage. LLVM tools (
llvm-as,opt,llc) pay 80–90 ms every invocation just to load the shared libraries — dwarfing the actual work on a small module. -
Processing-time comparison: even after subtracting startup overhead, this implementation is meaningfully faster for small-to-medium modules (~5–125×). The primary reasons:
- Focused implementation without LLVM's plugin, debug, metadata, and attribute infrastructure
- Vec-based flat arenas vs. LLVM's layered allocator hierarchy
- No LLVM pass-manager bookkeeping (analyses, invalidation, statistics)
-
Scalability caveat: LLVM is highly optimised for large programs (hundreds of thousands of IR instructions). At that scale LLVM's mature optimisations will outperform this project. These benchmarks target the small-module embedded-library use case.
-
Code quality: the repository has deterministic codegen, large-program, and performance-budget gates, but it does not claim broad LLVM
-O2parity. Treat output quality as scoped to the backend and workload contract documented in the production support boundaries.
This project is a standalone re-implementation, not a wrapper around LLVM. "LLVM compatibility" means compatibility with the LLVM IR text format (.ll files) that real LLVM tools (clang, opt, llc, llvm-as) read and write.
| LLVM release | .ll files this project emits |
.ll files from that LLVM version |
|---|---|---|
| ≤ 14 | Not readable by LLVM ≤14 (opaque-pointer syntax) | Not parseable (typed pointer syntax unsupported) |
| 15 | Compatible | Compatible (opaque pointers on by default) |
| 16 | Compatible | Compatible |
| 17 | Compatible | Compatible |
| 18 – 22 | Compatible | Compatible |
This table records the parser/printer compatibility target, not a claim about the latest upstream LLVM release.
| IR feature | This project | First LLVM version |
|---|---|---|
Opaque pointers (ptr) |
Yes — only pointer representation | Default in LLVM 15; exclusive in LLVM 17 |
Typed pointers (i32*, float*) |
No — not supported | Removed in LLVM 17 |
bfloat (BFloat16) type |
Yes | LLVM 7 |
Scalable vectors (<vscale x N x T>) |
Yes | LLVM 11 (SVE/RVV) |
nuw / nsw / exact flags |
Yes | LLVM 2.9 |
Fast-math flags (nnan, ninf, fast, …) |
Yes | LLVM 3.1 |
Tail-call kinds (tail, musttail, notail) |
Yes | LLVM 3.0 |
fneg instruction |
Yes | LLVM 9 |
freeze instruction |
Yes | LLVM 10 |
vp.* vector-predication intrinsics |
Yes — recognized as intrinsic calls and lowered through implemented vector paths | LLVM 11 |
| Inline assembly | Partial — parse/print plus nop template lowering on x86-64/AArch64 |
LLVM IR feature |
Atomics (fence, cmpxchg, atomicrmw) |
Yes — backend coverage varies by target and operation | LLVM IR feature |
EH paths (invoke, landingpad, funclet pads) |
Partial — IR round-trip and metadata/object support are present; runtime language interop remains experimental | LLVM IR feature |
- Reading LLVM 15+ output:
.llfiles generated byclang -S -emit-llvmwith LLVM 15 or later are accepted for the implemented subset. Unsupported IR constructs should fail with diagnostics rather than being treated as a production-supported path. - Reading LLVM ≤14 output: Not supported. LLVM 14 and earlier emit typed-pointer syntax
(
i32*,i8**) that this parser does not recognise. Pass those files throughopt --opaque-pointers -Swith LLVM 15 to upgrade them first. - Interop with LLVM tools:
.llfiles printed byllvm_ir::Printerare valid input toopt,llc, andllvm-asversion 15 or later.
The llvm-bitcode crate implements a custom compact binary format called LRIR, identified
by the magic bytes LRIR and format version 1. This is not the LLVM bitcode format (.bc)
and cannot be processed by LLVM tools (llvm-as, llvm-dis, llvm-link). LRIR exists solely
for fast round-trip serialization within this project. Use the text format (.ll) for
interoperability with external LLVM tools.
llvm-ir/ Core IR types: types, values, instructions, modules, builder, printer
llvm-ir-parser/ .ll text format parser
llvm-analysis/ CFG, dominator tree, use-def chains, loop info
llvm-transforms/ Optimization passes: mem2reg, DCE, const folding/prop, inliner
llvm-codegen/ Target-independent codegen: legalization, isel, regalloc, scheduling
llvm-target-x86/ x86_64 backend
llvm-target-arm/ AArch64 backend
llvm-bitcode/ Binary IR format (LRIR) reader/writer
llvm/ Top-level crate re-exporting everything
Crate dependency graph (arrows = "depends on"):
llvm-ir-parser ──┐
llvm-analysis ──┤
├──► llvm-ir
llvm-transforms──┤
llvm-codegen ──┘
│
├──► llvm-target-x86
└──► llvm-target-arm
llvm-bitcode ──► llvm-ir
llvm ──► all of the above
- Rust 1.75 or later (2021 edition)
- Cargo (ships with Rust)
Install Rust via rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh# Clone the repository
git clone https://github.com/yudongusa/LLVM-in-Rust.git
cd LLVM-in-Rust
# Debug build (fast compile, includes assertions)
cargo build
# Release build (optimised)
cargo build --release
# Type-check only (fastest feedback loop)
cargo checkcargo build -p llvm-in-rust-ir
cargo build -p llvm-in-rust-transforms
cargo build -p llvm-in-rust-target-x86# Run all tests
cargo test
# Run tests for a single crate
cargo test -p llvm-in-rust-ir
cargo test -p llvm-in-rust-ir-parser
cargo test -p llvm-in-rust-analysis
cargo test -p llvm-in-rust-transforms
cargo test -p llvm-in-rust-codegen
cargo test -p llvm-in-rust-target-x86
cargo test -p llvm-in-rust-target-arm
cargo test -p llvm-in-rust-bitcode
# Run a named test
cargo test roundtrip_add
cargo test mem2reg_simple_allocacargo clippy --all-targets # must be warning-free
cargo fmt --check # check formatting
cargo fmt # auto-format# Parser/optimizer/codegen fuzzing via llvm-stress corpus + cargo-fuzz
./scripts/llvm_stress_fuzz.sh --iterations 10000 --max-total-time 300
# Semantic differential fuzzing with CSmith (default 1000 programs)
./scripts/csmith_test.sh --count 1000
# Package a failing IR input for crash triage
scripts/reduce_ci_failure.sh \
--input failing.ll \
--predicate './repro.sh {{input}}' \
--evidence-dir ci-failures/example
# Sanitizer/UB hardening lanes (nightly Rust required)
scripts/sanitizer_matrix.sh asan-core
scripts/sanitizer_matrix.sh miri-core
scripts/sanitizer_matrix.sh tsan-core
# Platform matrix lanes
scripts/platform_matrix.sh host-core
scripts/platform_matrix.sh target-x86_64
scripts/platform_matrix.sh target-aarch64
scripts/platform_matrix.sh target-rv64gc
scripts/platform_matrix.sh known-issues
# Interoperability conformance lanes
scripts/interoperability_conformance.sh link
scripts/interoperability_conformance.sh debug
scripts/interoperability_conformance.sh abi
scripts/interoperability_conformance.sh mixed
scripts/interoperability_conformance.sh release
# Release artifact provenance dry-run
scripts/release_artifacts.sh dry-runCrash and miscompilation triage follows the SLO and evidence package process in
docs/crash_triage_runbook.md.
The release sanitizer/UB matrix and suppression policy are documented in
docs/sanitizer_ub_gate.md.
Supported platform tiers, Tier-1/Tier-2 expectations, and the release sign-off
checklist are documented in
docs/platform_support_policy.md. Tracked
platform exceptions live in
docs/platform_known_issues.json.
The M2 linker/debugger/ABI conformance suite and release sign-off process are
documented in
docs/interoperability_conformance.md.
Reproducible release artifacts, checksum publication, detached signatures, and
release provenance are covered by the Release Artifact Provenance workflow and
docs/release_artifact_pipeline.md.
Production operations, observability, incident response, contributor triage paths,
and the full runbook index are documented in
docs/production_operations.md.
This project is a Cargo workspace of library crates. Add whichever layers you need to your project's Cargo.toml:
[dependencies]
# Core IR types only
llvm-ir = { package = "llvm-in-rust-ir", git = "https://github.com/yudongusa/LLVM-in-Rust" }
# IR + .ll text parser
llvm-ir-parser = { package = "llvm-in-rust-ir-parser", git = "https://github.com/yudongusa/LLVM-in-Rust" }
# IR + optimization passes
llvm-transforms = { package = "llvm-in-rust-transforms", git = "https://github.com/yudongusa/LLVM-in-Rust" }
# Full pipeline including x86_64 backend
llvm = { package = "llvm-in-rust", git = "https://github.com/yudongusa/LLVM-in-Rust" }For a path dependency (local development):
[dependencies]
llvm-ir = { package = "llvm-in-rust-ir", path = "../LLVM-in-Rust/src/llvm-ir" }use llvm_ir::{Builder, Context, IntPredicate, Linkage, Module, Printer};
fn main() {
let mut ctx = Context::new();
let mut module = Module::new("example");
let mut b = Builder::new(&mut ctx, &mut module);
// define i32 @max(i32 %x, i32 %y)
let _fid = b.add_function(
"max",
b.ctx.i32_ty,
vec![b.ctx.i32_ty, b.ctx.i32_ty],
vec!["x".into(), "y".into()],
false,
Linkage::External,
);
let entry = b.add_block("entry");
let ret_x = b.add_block("ret_x");
let ret_y = b.add_block("ret_y");
b.position_at_end(entry);
let x = b.get_arg(0);
let y = b.get_arg(1);
let cond = b.build_icmp("cond", IntPredicate::Sgt, x, y);
b.build_cond_br(cond, ret_x, ret_y);
b.position_at_end(ret_x);
b.build_ret(x);
b.position_at_end(ret_y);
b.build_ret(y);
// Print LLVM IR text
let ir = Printer::new(b.ctx).print_module(b.module);
println!("{ir}");
}Output:
; Module: example
define i32 @max(i32 %x, i32 %y) {
entry:
%cond = icmp sgt i32 %x, %y
br i1 %cond, label %ret_x, label %ret_y
ret_x:
ret i32 %x
ret_y:
ret i32 %y
}use llvm_ir_parser::parse;
use llvm_ir::Printer;
fn main() {
let src = std::fs::read_to_string("input.ll").unwrap();
let (ctx, module) = parse(&src).expect("parse error");
// Round-trip back to text
let ir = Printer::new(&ctx).print_module(&module);
println!("{ir}");
}use llvm_ir::{Builder, Context, Linkage, Module};
use llvm_transforms::{
ConstProp, DeadCodeElim, Inliner, Mem2Reg,
FunctionPass, ModulePass, PassManager,
pass::FunctionPassAdapter,
};
fn main() {
// ... build or parse your module into (ctx, module) ...
let mut pm = PassManager::new();
pm.add(Box::new(FunctionPassAdapter { pass: Mem2Reg }));
pm.add(Box::new(FunctionPassAdapter { pass: ConstProp }));
pm.add(Box::new(FunctionPassAdapter { pass: DeadCodeElim }));
pm.add(Box::new(Inliner::new(/* size_limit */ 100)));
pm.run(&mut ctx, &mut module); // runs to fixed-point
}use llvm_ir::{Builder, Context, Linkage, Module};
use llvm_codegen::{emit_object, ObjectFormat};
use llvm_target_x86::X86Backend;
fn main() {
// ... build or parse your module ...
let backend = X86Backend::new();
let obj = emit_object(&ctx, &module, &backend, ObjectFormat::Elf)
.expect("codegen failed");
std::fs::write("output.o", &obj.bytes).unwrap();
}use llvm_bitcode::{read_bitcode, write_bitcode};
// Serialise
let bytes = write_bitcode(&ctx, &module).unwrap();
std::fs::write("module.lrir", &bytes).unwrap();
// Deserialise
let bytes = std::fs::read("module.lrir").unwrap();
let (ctx, module) = read_bitcode(&bytes).unwrap();All IR lives in SSA form. Ownership is structured around three stack values:
Context— interned type table and constant poolModule— functions and global variablesFunction— flat instruction pool;BasicBlockstoresVec<InstrId>indices into it
All handles (TypeId, BlockId, InstrId, ArgId, ConstId, GlobalId, FunctionId) are Copy u32 newtypes. Cross-entity references use ValueRef, a Copy enum:
pub enum ValueRef {
Instruction(InstrId),
Argument(ArgId),
Constant(ConstId),
Global(GlobalId),
}There is no Rc, no RefCell, no unsafe, and no external arena crate.
FunctionPass and ModulePass are simple traits:
pub trait FunctionPass {
fn run_on_function(&mut self, ctx: &mut Context, func: &mut Function) -> bool;
fn name(&self) -> &'static str;
}FunctionPassAdapter lifts any FunctionPass into a ModulePass. PassManager sequences passes and iterates until no pass reports a change.
Target backends implement IselBackend. The pipeline is:
IR → legalize → instruction selection (DAG lowering)
→ register allocation (linear scan)
→ instruction scheduling
→ machine-code encoding → ELF / Mach-O object file
The examples/tikv_jit crate shows how a project like
TiKV could embed LLVM-in-Rust to JIT-compile
coprocessor filter predicates — with no dependency on the LLVM C++ library.
// Clipped-difference range filter: return (value - threshold) when value > threshold, else 0.
i64 eval_predicate(i64 value, i64 threshold) {
if (value > threshold) return value - threshold;
return 0;
}use llvm_codegen::{
emit_object, isel::IselBackend, ObjectFormat,
regalloc::{apply_allocation, compute_live_intervals, insert_spill_reloads, linear_scan},
};
use llvm_ir::{Builder, Context, IntPredicate, Linkage, Module, Printer};
use llvm_target_x86::{instructions::{MOV_LOAD_MR, MOV_STORE_RM}, X86Backend, X86Emitter};
use llvm_transforms::{pass::PassManager, ConstProp, DeadCodeElim, Mem2Reg};
// 1. Build IR
let mut ctx = Context::new();
let mut module = Module::new("tikv_coprocessor");
let i64_ty = ctx.i64_ty;
{
let mut bldr = Builder::new(&mut ctx, &mut module);
bldr.add_function("eval_predicate", i64_ty,
vec![i64_ty, i64_ty], vec!["value".into(), "threshold".into()],
false, Linkage::External);
let entry = bldr.add_block("entry");
bldr.position_at_end(entry);
let value = bldr.get_arg(0);
let threshold = bldr.get_arg(1);
let cond = bldr.build_icmp("cond", IntPredicate::Sgt, value, threshold);
let then_bb = bldr.add_block("then");
let else_bb = bldr.add_block("else");
bldr.build_cond_br(cond, then_bb, else_bb);
let merge_bb = bldr.add_block("merge");
bldr.position_at_end(then_bb);
let diff = bldr.build_sub("diff", value, threshold);
bldr.build_br(merge_bb);
bldr.position_at_end(else_bb);
bldr.build_br(merge_bb);
bldr.position_at_end(merge_bb);
let zero = bldr.const_i64(0);
let result = bldr.build_phi("result", i64_ty, vec![(diff, then_bb), (zero, else_bb)]);
bldr.build_ret(result);
}
// 2. Print IR (optional — for logging / debugging)
let ir_text = Printer::new(&ctx).print_module(&module);
// 3. Optimise
let mut pm = PassManager::new();
pm.add_function_pass(Mem2Reg);
pm.add_function_pass(ConstProp);
pm.add_function_pass(DeadCodeElim);
pm.run(&mut ctx, &mut module);
// 4. x86-64 codegen
let func = module.functions.iter().find(|f| !f.is_declaration).unwrap();
let mut mf = X86Backend.lower_function(&ctx, &module, func);
let intervals = compute_live_intervals(&mf);
let mut result = linear_scan(&intervals, &mf.allocatable_pregs);
insert_spill_reloads(&mut mf, &mut result, MOV_LOAD_MR, MOV_STORE_RM);
apply_allocation(&mut mf, &result);
// 5. Emit ELF object file
let mut emitter = X86Emitter::new(ObjectFormat::Elf);
let obj = emit_object(&mf, &mut emitter);
std::fs::write("/tmp/eval_predicate.o", obj.to_bytes()).unwrap();
// Link with: cc /tmp/eval_predicate.o your_main.o -o binarycargo run -p tikv_jit
# Prints the IR before/after optimisation, then writes /tmp/eval_predicate.o
objdump -d /tmp/eval_predicate.o # inspect generated x86-64 assemblyLinux (ELF):
# Relocatable link
ld -r /tmp/eval_predicate.o -o /tmp/eval_predicate.linked.o
# Link an executable with system startup/runtime
cc /tmp/eval_predicate.o -o /tmp/eval_predicate_binThe default backend flow already uses an integrated assembler path: machine IR is encoded directly into section bytes and serialized to object files (ELF / Mach-O / COFF) without generating textual assembly as an intermediate.
llvm-codegen exposes this stage explicitly:
use llvm_codegen::{assemble_with_report, ObjectFormat};
use llvm_target_x86::X86Emitter;
let mut emitter = X86Emitter::new(ObjectFormat::Elf);
let assembled = assemble_with_report(&mf, &mut emitter);
std::fs::write("/tmp/out.o", &assembled.bytes)?;
println!("mc bytes: {}", assembled.report.bytes);Inline assembly support is intentionally small in v0.1.x: textual IR can parse
and print LLVM-style inline asm calls such as call void asm sideeffect "nop", ""(),
and x86-64/AArch64 lowering recognizes nop templates for direct machine-byte
emission. Constraint solving, output operands, and register allocation across
general asm operands remain outside the production support contract.
Exception-handling IR support covers the core invoke/landingpad and funclet
shapes used by Itanium-style and Windows-style unwinding: the parser, printer,
binary IR round-trip, CFG successors, value rewriting, LSDA/xdata builders, and
tier-1 backends preserve the relevant edges and metadata. Cross-language runtime
throw/catch behavior remains experimental and is scoped in
docs/unwind_compatibility_matrix.md.
macOS (Mach-O):
# Relocatable link
ld -r /tmp/eval_predicate.o -o /tmp/eval_predicate.linked.o
# Link an executable with system toolchain
cc /tmp/eval_predicate.o -o /tmp/eval_predicate_binWindows (COFF):
# Produce COFF object by selecting ObjectFormat::Coff in the emitter.
# Then inspect sections:
llvm-readobj --sections .\eval_predicate.obj
# Future milestone: link with debug info to PDB
lld-link /DEBUG /ENTRY:main /SUBSYSTEM:CONSOLE /OUT:eval_predicate.exe .\eval_predicate.objWhen LLVM IR carries !dbg / !DILocation metadata, ELF object emission adds
coherent DWARF sections: .debug_line, .debug_info, and .debug_abbrev.
Quick checks:
readelf -S /tmp/eval_predicate.o | grep -E 'debug_(line|info|abbrev)'
llvm-dwarfdump --verify /tmp/eval_predicate.o
llvm-dwarfdump --debug-line /tmp/eval_predicate.oCurrent limitations:
- Single compile unit per object/function emission path
- Single source-file path per function (
source_filename) - Minimal CU attributes (enough for valid line mapping and section coherence)
COFF emission now supports a first Windows debug milestone: when debug metadata
is present, emitted COFF objects include .debug$S with CV_SIGNATURE_C13
and a minimal DEBUG_S_SYMBOLS subsection carrying source/line hints.
For architecture and staged roadmap details, see:
docs/windows_debug_codeview.md.
Add the crates you need to your Cargo.toml. For a local checkout use path dependencies:
[dependencies]
llvm-ir = { package = "llvm-in-rust-ir", path = "path/to/LLVM-in-Rust/src/llvm-ir" }
llvm-transforms = { package = "llvm-in-rust-transforms", path = "path/to/LLVM-in-Rust/src/llvm-transforms" }
llvm-codegen = { package = "llvm-in-rust-codegen", path = "path/to/LLVM-in-Rust/src/llvm-codegen" }
llvm-target-x86 = { package = "llvm-in-rust-target-x86", path = "path/to/LLVM-in-Rust/src/llvm-target-x86" }
# optional: llvm-target-arm for AArch64 output
# optional: llvm-ir-parser to accept .ll text files as input
# optional: llvm-bitcode to read/write the LRIR binary formatBreaking changes to the public API, IR semantics (InstrKind/TypeData variants),
object-file format compatibility, or mandatory trait methods require an RFC before
implementation. An RFC is a short Markdown document that describes the motivation,
the precise before/after API change, a migration guide, and alternatives considered.
RFCs go through at least 7 days of open review followed by a 3-day Final Comment
Period before a maintainer merges them. See
docs/rfcs/README.md for the full process, triggers, and
submission instructions.
- Fork the repository and create a feature branch.
- Make your changes; ensure
cargo clippy --all-targetsis warning-free andcargo fmt --checkpasses. - Add tests covering new behaviour.
- Open a pull request against
main.
Bug reports and feature requests go to the issue tracker.
See SECURITY.md for how to report a vulnerability.
Licensed under the Apache License, Version 2.0.