Expand description
§Lamina Compiler Library
Lamina is a modern compiler that generates efficient machine code from a high-level intermediate representation (IR). It supports multiple target architectures and provides a comprehensive set of tools for building compilers, interpreters, and language runtimes.
§Overview
Lamina consists of several key components:
- IR (Intermediate Representation): A low-level, architecture-agnostic representation of programs that serves as the bridge between high-level source code and machine code.
- Parser: Converts text-based IR into structured data that can be processed by the compiler.
- Code Generator: Translates IR into native assembly code for various target architectures.
- Error Handling: Comprehensive error reporting and recovery mechanisms.
§Quick Start
use lamina::{compile_lamina_ir_to_assembly};
use lamina::target::Target;
use std::io::Write;
// Detect the host architecture
let target = Target::detect_host();
println!("Host target: {}", target);
println!("Architecture: {}", target.architecture);
// Compile IR to assembly
let ir_code = r#"
fn @main() -> i64 {
entry:
%result = add.i64 42, 8
ret.i64 %result
}
"#;
let mut assembly = Vec::new();
compile_lamina_ir_to_assembly(ir_code, &mut assembly)?;
println!("Generated assembly:\n{}", String::from_utf8(assembly)?);§Architecture Support
Lamina currently supports the following target architectures:
-
x86_64: Intel/AMD 64-bit processors
x86_64_unknown- Generic x86_64 (uses ELF conventions for compatibility)x86_64_linux- Linux x86_64x86_64_windows- Windows x86_64x86_64_macos- macOS x86_64 (Intel Macs)
-
AArch64: ARM 64-bit processors
aarch64_unknown- Generic AArch64 (uses ELF conventions for compatibility)aarch64_linux- Linux AArch64aarch64_windows- Windows AArch64aarch64_macos- macOS AArch64 (Apple Silicon)
§Core Modules
§IR (Intermediate Representation)
The IR module provides the fundamental data structures for representing programs:
- Types: Primitive types, structs, arrays, tuples, and function signatures
- Instructions: Arithmetic, memory operations, control flow, and function calls
- Functions: Complete function definitions with basic blocks
- Modules: Top-level containers for functions, types, and globals
- Builder: Fluent API for programmatically constructing IR
§Code Generation
The codegen module translates IR into native assembly:
- Architecture-specific backends: Separate implementations for x86_64 and AArch64
- Register allocation: Efficient use of target architecture registers
- Instruction selection: Optimal instruction choice for IR operations
- ABI compliance: Proper calling conventions and stack management
§Error Handling
Comprehensive error reporting with detailed context:
- Parse errors: Syntax and semantic errors in IR input
- Codegen errors: Architecture-specific compilation issues
- Type errors: Type checking and validation failures
- Memory errors: Stack overflow, invalid memory access, etc.
§Memory Management
Lamina provides sophisticated memory management capabilities:
- Stack allocation: Fast, automatic memory management for local variables
- Heap allocation: Manual memory management for persistent data
- Pointer arithmetic: Safe array and struct field access
- Memory safety: Bounds checking and validation (where possible)
§Examples
§Basic Arithmetic
use lamina::ir::{IRBuilder, Type, PrimitiveType, BinaryOp};
use lamina::ir::builder::{var, i32, i64};
let mut builder = IRBuilder::new();
builder
.function("add_numbers", Type::Primitive(PrimitiveType::I32))
.binary(BinaryOp::Add, "sum", PrimitiveType::I32, i32(10), i32(32))
.ret(Type::Primitive(PrimitiveType::I32), var("sum"));§Memory Operations
use lamina::ir::{IRBuilder, Type, PrimitiveType};
use lamina::ir::builder::{var, i32};
let mut builder = IRBuilder::new();
builder
.function("memory_demo", Type::Void)
.alloc_stack("local", Type::Primitive(PrimitiveType::I32))
.store(Type::Primitive(PrimitiveType::I32), var("local"), i32(42))
.load("value", Type::Primitive(PrimitiveType::I32), var("local"))
.print(var("value"))
.ret_void();§Complete Builder Example: Memory Workflow
use lamina::ir::{IRBuilder, Type, PrimitiveType, BinaryOp};
use lamina::ir::builder::{var, i32};
// Create a new IR builder
let mut builder = IRBuilder::new();
// Define a function that demonstrates memory operations
builder
.function_with_params("memory_workflow", vec![
lamina::ir::FunctionParameter {
name: "input",
ty: Type::Primitive(PrimitiveType::I32),
annotations: vec![]
}
], Type::Primitive(PrimitiveType::I32))
// Step 1: Allocate memory on stack
.alloc_stack("buffer", Type::Primitive(PrimitiveType::I32))
// Step 2: Store the input value in our buffer
.store(Type::Primitive(PrimitiveType::I32), var("buffer"), var("input"))
// Step 3: Load the value back from memory
.load("loaded", Type::Primitive(PrimitiveType::I32), var("buffer"))
// Step 4: Perform arithmetic on the loaded value
.binary(BinaryOp::Add, "result", PrimitiveType::I32, var("loaded"), i32(10))
// Step 5: Store the result back to memory
.store(Type::Primitive(PrimitiveType::I32), var("buffer"), var("result"))
// Step 6: Load and return the final value
.load("final", Type::Primitive(PrimitiveType::I32), var("buffer"))
.ret(Type::Primitive(PrimitiveType::I32), var("final"));
// Build the module
let module = builder.build();
// The module now contains our memory_workflow function
assert!(module.functions.contains_key("memory_workflow"));§Advanced Builder Example: Control Flow with Memory
use lamina::ir::{IRBuilder, Type, PrimitiveType, BinaryOp, CmpOp};
use lamina::ir::builder::{var, i32, string};
let mut builder = IRBuilder::new();
builder
.function_with_params("process_data", vec![
lamina::ir::FunctionParameter {
name: "data",
ty: Type::Primitive(PrimitiveType::I32),
annotations: vec![]
}
], Type::Void)
// Allocate memory for processing
.alloc_stack("temp", Type::Primitive(PrimitiveType::I32))
.store(Type::Primitive(PrimitiveType::I32), var("temp"), var("data"))
// Check if data is positive
.cmp(CmpOp::Gt, "is_positive", PrimitiveType::I32, var("data"), i32(0))
.branch(var("is_positive"), "positive_path", "negative_path")
// Positive path: double the value
.block("positive_path")
.load("current", Type::Primitive(PrimitiveType::I32), var("temp"))
.binary(BinaryOp::Mul, "doubled", PrimitiveType::I32, var("current"), i32(2))
.store(Type::Primitive(PrimitiveType::I32), var("temp"), var("doubled"))
.print(string("Processed positive value"))
.jump("cleanup")
// Negative path: take absolute value
.block("negative_path")
.load("current", Type::Primitive(PrimitiveType::I32), var("temp"))
.binary(BinaryOp::Sub, "abs", PrimitiveType::I32, i32(0), var("current"))
.store(Type::Primitive(PrimitiveType::I32), var("temp"), var("abs"))
.print(string("Processed negative value"))
.jump("cleanup")
// Cleanup: print final result
.block("cleanup")
.load("final_result", Type::Primitive(PrimitiveType::I32), var("temp"))
.print(var("final_result"))
.ret_void();
let module = builder.build();§Control Flow
use lamina::ir::{IRBuilder, Type, PrimitiveType, CmpOp};
use lamina::ir::builder::{var, i32};
let mut builder = IRBuilder::new();
builder
.function("conditional", Type::Primitive(PrimitiveType::I32))
.cmp(CmpOp::Lt, "is_negative", PrimitiveType::I32, var("x"), i32(0))
.branch(var("is_negative"), "negative", "positive")
.block("negative")
.ret(Type::Primitive(PrimitiveType::I32), i32(-1))
.block("positive")
.ret(Type::Primitive(PrimitiveType::I32), i32(1));§Performance Considerations
- Zero-copy parsing: IR uses string references to avoid unnecessary allocations
- Efficient data structures: HashMaps for O(1) lookups of functions and types
- SSA form: Single Static Assignment form enables powerful optimizations
- Architecture-specific optimizations: Tailored code generation for each target
§Thread Safety
Lamina’s IR structures are designed to be thread-safe when used correctly:
- Immutable by default: IR structures are typically built once and then read-only
- Copy semantics: Most IR types implement
Clonefor easy duplication - Lifetime management: Uses Rust’s lifetime system to ensure memory safety
§Error Recovery
The compiler provides detailed error messages to help with debugging:
- Source location: Errors include line and column information
- Context information: Additional details about what went wrong
- Suggestions: Helpful hints for fixing common issues
- Multiple errors: Reports all errors found, not just the first one
§Nightly Features
Lamina includes experimental features that are gated behind the nightly feature flag:
- Atomic Operations: Thread-safe memory operations with memory ordering constraints
- Module Annotations: Module-level attributes for optimization and debugging hints
- Experimental Targets: Additional target architectures (e.g., RISC-V 128-bit)
To enable nightly features, compile with:
[dependencies]
lamina = { version = "0.0.7", features = ["nightly"] }Note: Nightly features are experimental and may change or be removed in future versions.
§Future Roadmap
- Additional architectures: RISC-V, WebAssembly, and more
- Optimization passes: Dead code elimination, constant folding, etc.
- Debug information: Source-level debugging support
- Standard library: Common functions and data structures
- Language bindings: C, Python, JavaScript, and other language interfaces
Re-exports§
pub use codegen::generate_x86_64_assembly;pub use error::LaminaError;pub use ir::function::BasicBlock;pub use ir::function::Function;pub use ir::function::FunctionAnnotation;pub use ir::function::FunctionParameter;pub use ir::function::FunctionSignature;pub use ir::instruction::AllocType;pub use ir::instruction::BinaryOp;pub use ir::instruction::CmpOp;pub use ir::instruction::Instruction;pub use ir::module::GlobalDeclaration;pub use ir::module::Module;pub use ir::module::TypeDeclaration;pub use ir::types::Identifier;pub use ir::types::Label;pub use ir::types::Literal;pub use ir::types::PrimitiveType;pub use ir::types::StructField;pub use ir::types::Type;pub use ir::types::Value;pub use mir_codegen::generate_mir_to_target;
Modules§
- codegen
- Code generation module for multiple target architectures.
- error
- Error types for the Lamina compiler.
- ir
- Lamina Intermediate Representation (IR)
- mir
- mir_
codegen - MIR-based code generation for multiple target architectures.
- parser
- Lamina IR parser.
- target
Functions§
- compile_
lamina_ ir_ to_ assembly - Parses Lamina IR text and generates assembly code using the host system’s architecture.
- compile_
lamina_ ir_ to_ target_ assembly - Parses Lamina IR text and generates assembly code for a specific target architecture.