### Manage Program Points in Rust Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Shows how to create, navigate, and order program points representing positions before or after instructions. ```rust use regalloc2::{ProgPoint, Inst, InstPosition}; let inst = Inst::new(10); // Create program points let before = ProgPoint::before(inst); let after = ProgPoint::after(inst); // Or with explicit position let pp = ProgPoint::new(inst, InstPosition::Before); // Access components assert_eq!(before.inst(), inst); assert_eq!(before.pos(), InstPosition::Before); assert_eq!(after.pos(), InstPosition::After); // Navigation let next = before.next(); // Points to after same instruction let prev = after.prev(); // Points to before same instruction assert_eq!(next, after); assert_eq!(prev, before); // Ordering - before comes before after assert!(before < after); // Convert to/from index for serialization let idx = before.to_index(); let restored = ProgPoint::from_index(idx); assert_eq!(before, restored); ``` -------------------------------- ### Handle Block and Instruction Indexing in Rust Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Illustrates the use of indices for blocks and instructions, including validation checks and instruction range iteration. ```rust use regalloc2::{Block, Inst, InstRange}; // Create block and instruction indices let block0 = Block::new(0); let block1 = Block::new(1); let inst5 = Inst::new(5); // Access raw index assert_eq!(block0.index(), 0); assert_eq!(inst5.index(), 5); // Invalid values for initialization let invalid_block = Block::invalid(); let invalid_inst = Inst::invalid(); assert!(!invalid_block.is_valid()); assert!(!invalid_inst.is_valid()); // Instruction ranges for blocks let range = InstRange::new(Inst::new(0), Inst::new(5)); assert_eq!(range.len(), 5); assert_eq!(range.first(), Inst::new(0)); assert_eq!(range.last(), Inst::new(4)); // Iterate over instructions in a range for inst in range.iter() { println!("Instruction {}", inst.index()); } // Get remaining range after first instruction let rest = range.rest(); assert_eq!(rest.first(), Inst::new(1)); ``` -------------------------------- ### run() - Register Allocation Entry Point Source: https://context7.com/bytecodealliance/regalloc2/llms.txt The primary function to execute the register allocation process given a function, machine environment, and configuration options. ```APIDOC ## run(func, env, options) ### Description Executes the register allocation algorithm on the provided function representation using the specified machine environment and configuration options. ### Parameters - **func** (Function) - Required - The implementation of the Function trait describing the IR. - **env** (MachineEnv) - Required - The machine environment defining physical registers, scratch registers, and stack slots. - **options** (RegallocOptions) - Required - Configuration options including the choice of algorithm (Ion or Fastalloc) and validation settings. ### Response - **Result** - Returns the allocation output containing register/stack assignments or an error if allocation fails. ``` -------------------------------- ### Select Allocation Algorithm Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Configure the allocator to use either Ion for high-quality code or Fastalloc for faster compilation speeds. ```rust use regalloc2::{run, RegallocOptions, Algorithm, Function, MachineEnv}; fn allocate_with_algorithm( func: &F, env: &MachineEnv, prefer_speed: bool, ) { let options = RegallocOptions { verbose_log: false, validate_ssa: true, algorithm: if prefer_speed { // Fastalloc: Linear scan, faster compile times // Best for JIT compilation or debug builds Algorithm::Fastalloc } else { // Ion: Backtracking allocator, better code quality // Best for release builds or AOT compilation Algorithm::Ion }, }; match run(func, env, &options) { Ok(output) => { println!("Allocated with {} spillslots", output.num_spillslots); } Err(e) => { println!("Allocation failed: {:?}", e); } } } ``` -------------------------------- ### Create Virtual Registers Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Initialize virtual registers with specific register classes and access their properties. ```rust use regalloc2::{VReg, RegClass}; // Create integer virtual registers let v0 = VReg::new(0, RegClass::Int); let v1 = VReg::new(1, RegClass::Int); let v2 = VReg::new(2, RegClass::Int); // Create floating-point virtual registers let f0 = VReg::new(3, RegClass::Float); let f1 = VReg::new(4, RegClass::Float); // Create vector virtual registers let vec0 = VReg::new(5, RegClass::Vector); // Access properties assert_eq!(v0.vreg(), 0); assert_eq!(v0.class(), RegClass::Int); assert_eq!(f0.class(), RegClass::Float); // Invalid vreg for initialization let invalid = VReg::invalid(); ``` -------------------------------- ### Manage Spillslots and Stack Allocation Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Demonstrates creating, validating, and converting SpillSlots and Allocation types for stack-based storage. ```rust use regalloc2::{SpillSlot, Allocation, AllocationKind}; // Create spillslot let slot0 = SpillSlot::new(0); let slot1 = SpillSlot::new(1); // Access properties assert_eq!(slot0.index(), 0); assert!(slot0.is_valid()); // Invalid spillslot for initialization let invalid = SpillSlot::invalid(); assert!(invalid.is_invalid()); assert!(!invalid.is_valid()); // Offset for multi-slot values let slot_plus_2 = slot0.plus(2); assert_eq!(slot_plus_2.index(), 2); // Convert to allocation let alloc = Allocation::stack(slot0); assert!(alloc.is_stack()); assert!(!alloc.is_reg()); assert_eq!(alloc.kind(), AllocationKind::Stack); assert_eq!(alloc.as_stack().unwrap(), slot0); // None allocation for initialization let none = Allocation::none(); assert!(none.is_none()); assert!(!none.is_some()); ``` -------------------------------- ### Process Allocator Output in Rust Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Demonstrates how to extract spill slots, instruction allocations, and interleaved edits from the Output struct. ```rust use regalloc2::{Output, Inst, Block, Edit, InstOrEdit, Allocation, AllocationKind}; fn process_output(output: &Output, func: &impl regalloc2::Function) { // Get number of spillslots needed in stack frame let frame_size = output.num_spillslots; println!("Need {} spillslots", frame_size); // Get allocations for a specific instruction let inst = Inst::new(5); let allocs = output.inst_allocs(inst); for (i, alloc) in allocs.iter().enumerate() { match alloc.kind() { AllocationKind::Reg => { let preg = alloc.as_reg().unwrap(); println!("Operand {}: register hw={}", i, preg.hw_enc()); } AllocationKind::Stack => { let slot = alloc.as_stack().unwrap(); println!("Operand {}: stack slot {}", i, slot.index()); } AllocationKind::None => { println!("Operand {}: no allocation", i); } } } // Process a block with interleaved edits let block = Block::new(0); for item in output.block_insts_and_edits(func, block) { match item { InstOrEdit::Inst(inst) => { let allocs = output.inst_allocs(inst); // Emit instruction with allocated registers println!("Instruction {} with {} operands", inst.index(), allocs.len()); } InstOrEdit::Edit(edit) => { match edit { Edit::Move { from, to } => { // Emit move from one allocation to another println!("Move from {:?} to {:?}", from, to); } } } } } // Process all edits in order for (progpoint, edit) in &output.edits { let inst = progpoint.inst(); let pos = progpoint.pos(); // Before or After println!("Edit at inst {} ({:?}): {:?}", inst.index(), pos, edit); } } ``` -------------------------------- ### Run the Register Allocator Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Configures the machine environment and options before invoking the run function on a target function. ```rust use regalloc2::{run, Function, MachineEnv, RegallocOptions, Output, RegAllocError}; use regalloc2::{PReg, PRegSet, RegClass, Algorithm}; // Define available physical registers for the target architecture let mut preferred_int = PRegSet::empty(); preferred_int.add(PReg::new(0, RegClass::Int)); // r0 preferred_int.add(PReg::new(1, RegClass::Int)); // r1 preferred_int.add(PReg::new(2, RegClass::Int)); // r2 let mut non_preferred_int = PRegSet::empty(); non_preferred_int.add(PReg::new(3, RegClass::Int)); // r3 - callee-saved let mut preferred_float = PRegSet::empty(); preferred_float.add(PReg::new(0, RegClass::Float)); // f0 preferred_float.add(PReg::new(1, RegClass::Float)); // f1 let env = MachineEnv { preferred_regs_by_class: [preferred_int, preferred_float, PRegSet::empty()], non_preferred_regs_by_class: [non_preferred_int, PRegSet::empty(), PRegSet::empty()], scratch_by_class: [ Some(PReg::new(15, RegClass::Int)), // Scratch register for moves Some(PReg::new(15, RegClass::Float)), None, ], fixed_stack_slots: vec![], }; let options = RegallocOptions { verbose_log: false, validate_ssa: true, algorithm: Algorithm::Ion, // Or Algorithm::Fastalloc for speed }; // func implements the Function trait // let result: Result = run(&func, &env, &options); ``` -------------------------------- ### Create Physical Registers Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Define hardware registers, manage sets of physical registers, and perform set operations. ```rust use regalloc2::{PReg, PRegSet, RegClass}; // Create physical registers (hw_enc is the hardware register number) let r0 = PReg::new(0, RegClass::Int); // Integer register 0 let r1 = PReg::new(1, RegClass::Int); // Integer register 1 let f0 = PReg::new(0, RegClass::Float); // Float register 0 // Access properties assert_eq!(r0.hw_enc(), 0); assert_eq!(r0.class(), RegClass::Int); assert_eq!(r0.index(), 0); // Unique index across all classes assert_eq!(f0.index(), 64); // Float regs start at index 64 // Build a set of physical registers let mut regs = PRegSet::empty(); regs.add(r0); regs.add(r1); regs.add(f0); assert!(regs.contains(r0)); assert_eq!(regs.len(), 3); // Iterate over registers in a set for preg in ®s { println!("Register: hw={}, class={:?}", preg.hw_enc(), preg.class()); } // Set operations let other = PRegSet::empty().with(r0).with(PReg::new(2, RegClass::Int)); let intersection = regs & other; let union = regs | other; ``` -------------------------------- ### Implement the Function Trait Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Provides the necessary interface for the allocator to traverse the control flow graph and inspect instructions. ```rust use regalloc2::{Function, Block, Inst, InstRange, Operand, VReg, PRegSet, RegClass}; struct MyFunction { blocks: Vec, instructions: Vec, num_vregs: usize, } impl Function for MyFunction { fn num_insts(&self) -> usize { self.instructions.len() } fn num_blocks(&self) -> usize { self.blocks.len() } fn entry_block(&self) -> Block { Block::new(0) } fn block_insns(&self, block: Block) -> InstRange { let b = &self.blocks[block.index()]; InstRange::new(Inst::new(b.start), Inst::new(b.end)) } fn block_succs(&self, block: Block) -> &[Block] { &self.blocks[block.index()].successors } fn block_preds(&self, block: Block) -> &[Block] { &self.blocks[block.index()].predecessors } fn block_params(&self, block: Block) -> &[VReg] { &self.blocks[block.index()].params } fn is_ret(&self, insn: Inst) -> bool { self.instructions[insn.index()].is_return } fn is_branch(&self, insn: Inst) -> bool { self.instructions[insn.index()].is_branch } fn branch_blockparams(&self, _block: Block, insn: Inst, succ_idx: usize) -> &[VReg] { &self.instructions[insn.index()].branch_args[succ_idx] } fn inst_operands(&self, insn: Inst) -> &[Operand] { &self.instructions[insn.index()].operands } fn inst_clobbers(&self, insn: Inst) -> PRegSet { self.instructions[insn.index()].clobbers } fn num_vregs(&self) -> usize { self.num_vregs } fn spillslot_size(&self, regclass: RegClass) -> usize { match regclass { RegClass::Int => 1, RegClass::Float => 2, RegClass::Vector => 4, } } } ``` -------------------------------- ### Define Operand Constraints Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Configure how instructions use and define virtual registers using various constraint types. ```rust use regalloc2::{Operand, VReg, PReg, RegClass, OperandKind, OperandPos, OperandConstraint}; let v0 = VReg::new(0, RegClass::Int); let v1 = VReg::new(1, RegClass::Int); let v2 = VReg::new(2, RegClass::Int); // Basic register use (early) - input that can be overwritten after let use_op = Operand::reg_use(v0); // Register use at end (late) - input preserved until instruction completes let use_late = Operand::reg_use_at_end(v1); // Basic register def (late) - output that may reuse input registers let def_op = Operand::reg_def(v2); // Early def - output that must not conflict with any inputs // Useful for temporary registers within an instruction let def_early = Operand::reg_def_at_start(v2); // Reuse-input def - output must use same register as input operand 0 let reuse_def = Operand::reg_reuse_def(v2, 0); // Fixed register constraint - must use specific physical register let rax = PReg::new(0, RegClass::Int); let fixed_use = Operand::reg_fixed_use(v0, rax); let fixed_def = Operand::reg_fixed_def(v2, rax); // Any location (register or stack) let any_use = Operand::any_use(v0); let any_def = Operand::any_def(v2); // Temporary register within instruction let temp = Operand::reg_temp(VReg::new(3, RegClass::Int)); // Access operand properties assert_eq!(use_op.vreg(), v0); assert_eq!(use_op.kind(), OperandKind::Use); assert_eq!(use_op.pos(), OperandPos::Early); assert_eq!(def_op.kind(), OperandKind::Def); assert_eq!(def_op.pos(), OperandPos::Late); ``` -------------------------------- ### Verify Allocation with Checker Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Validates that the allocator output maintains correct dataflow and handles potential checker errors. ```rust use regalloc2::checker::{Checker, CheckerErrors, CheckerError}; use regalloc2::{Function, MachineEnv, Output}; fn verify_allocation( func: &F, env: &MachineEnv, output: &Output, ) -> Result<(), CheckerErrors> { let mut checker = Checker::new(func, env); checker.prepare(output); checker.run()?; Ok(()) } fn handle_checker_errors(errors: CheckerErrors) { for error in errors.errors.iter() { match error { CheckerError::MissingAllocation { inst, op } => { println!("Missing allocation at inst {} for {:?}", inst.index(), op); } CheckerError::UnknownValueInAllocation { inst, op, alloc } => { println!("Unknown value in {:?} at inst {} for {:?}", alloc, inst.index(), op); } CheckerError::IncorrectValuesInAllocation { inst, op, alloc, actual } => { println!("Wrong values in {:?} at inst {}: expected {:?}, got {:?}", alloc, inst.index(), op.vreg(), actual); } CheckerError::ConstraintViolated { inst, op, alloc } => { println!("Constraint violated: {:?} doesn't satisfy {:?} at inst {}", alloc, op.constraint(), inst.index()); } _ => println!("Checker error: {:?}", error), } } } ``` -------------------------------- ### Reuse Allocation Context Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Reuse a Ctx instance across multiple function allocations to reduce memory allocation overhead. ```rust use regalloc2::{run_with_ctx, Ctx, Function, MachineEnv, RegallocOptions, Output}; fn allocate_many_functions( functions: &[F], env: &MachineEnv, options: &RegallocOptions, ) -> Vec { let mut ctx = Ctx::default(); let mut outputs = Vec::new(); for func in functions { // Context is reused, reducing allocations match run_with_ctx(func, env, options, &mut ctx) { Ok(output) => { // Clone or take ownership of output outputs.push(std::mem::take(&mut ctx.output)); } Err(e) => { println!("Allocation failed: {:?}", e); } } } outputs } ``` -------------------------------- ### Function Trait Implementation Source: https://context7.com/bytecodealliance/regalloc2/llms.txt The Function trait defines the interface required for the allocator to understand the structure of the input program. ```APIDOC ## trait Function ### Description Clients must implement this trait to provide the allocator with information about basic blocks, instructions, operands, and register constraints. ### Required Methods - **num_insts()** - Returns the total number of instructions. - **num_blocks()** - Returns the total number of basic blocks. - **entry_block()** - Returns the entry block of the function. - **block_insns(block)** - Returns the range of instructions for a given block. - **block_succs(block)** - Returns the successor blocks for a given block. - **block_preds(block)** - Returns the predecessor blocks for a given block. - **block_params(block)** - Returns the block parameters for a given block. - **is_ret(insn)** - Returns true if the instruction is a return. - **is_branch(insn)** - Returns true if the instruction is a branch. - **branch_blockparams(block, insn, succ_idx)** - Returns the block parameters passed to a successor. - **inst_operands(insn)** - Returns the operands for a given instruction. - **inst_clobbers(insn)** - Returns the set of physical registers clobbered by an instruction. - **num_vregs()** - Returns the total number of virtual registers. - **spillslot_size(regclass)** - Returns the size of a spill slot for a given register class. ``` -------------------------------- ### Handle Allocator Errors in Rust Source: https://context7.com/bytecodealliance/regalloc2/llms.txt Matches on RegAllocError variants to diagnose specific allocation failures such as critical edges, SSA violations, or constraint issues. ```rust use regalloc2::{RegAllocError, Block, Inst, VReg, RegClass}; fn handle_error(err: RegAllocError) { match err { RegAllocError::CritEdge(from, to) => { // Critical edge not split - add intermediate block println!("Critical edge from block {} to block {} must be split", from.index(), to.index()); } RegAllocError::SSA(vreg, inst) => { // SSA violation - multiple defs or use before def if inst.is_valid() { println!("SSA error for vreg {} at instruction {}", vreg.vreg(), inst.index()); } else { println!("SSA error for vreg {} (block param)", vreg.vreg()); } } RegAllocError::BB(block) => { // Block doesn't end in branch/ret or has branch in middle println!("Invalid basic block {}", block.index()); } RegAllocError::Branch(inst) => { // Branch blockparam count mismatch println!("Invalid branch at instruction {}", inst.index()); } RegAllocError::EntryLivein => { // Entry block has live-in values (undefined) println!("Entry block cannot have live-in values"); } RegAllocError::DisallowedBranchArg(inst) => { // Branch arg on edge needing moves println!("Disallowed branch arg at instruction {}", inst.index()); } RegAllocError::TooManyLiveRegs => { // Impossible constraints - too many fixed regs needed println!("Too many live registers at once"); } RegAllocError::TooManyOperands => { // More than 2^16 - 1 operands on one instruction println!("Too many operands on instruction"); } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.