//! Compilation backend pipeline: optimized IR to VCode / binemit. use crate::dominator_tree::DominatorTree; use crate::ir::pcc; use crate::ir::Function; use crate::isa::TargetIsa; use crate::machinst::*; use crate::settings::RegallocAlgorithm; use crate::timing; use crate::trace; use crate::CodegenError; use regalloc2::{Algorithm, RegallocOptions}; /// Compile the given function down to VCode with allocated registers, ready /// for binary emission. pub fn compile( f: &Function, domtree: &DominatorTree, b: &B, abi: Callee<<::MInst as MachInst>::ABIMachineSpec>, emit_info: ::Info, sigs: SigSet, ctrl_plane: &mut ControlPlane, ) -> CodegenResult<(VCode, regalloc2::Output)> { // Compute lowered block order. let block_order = BlockLoweringOrder::new(f, domtree, ctrl_plane); // Build the lowering context. let lower = crate::machinst::Lower::new(f, abi, emit_info, block_order, sigs, b.flags().clone())?; // Lower the IR. let mut vcode = { log::debug!( "Number of CLIF instructions to lower: {}", f.dfg.num_insts() ); log::debug!("Number of CLIF blocks to lower: {}", f.dfg.num_blocks()); let _tt = timing::vcode_lower(); lower.lower(b, ctrl_plane)? }; log::debug!( "Number of lowered vcode instructions: {}", vcode.num_insts() ); log::debug!("Number of lowered vcode blocks: {}", vcode.num_blocks()); trace!("vcode from lowering: \n{:?}", vcode); // Perform validation of proof-carrying-code facts, if requested. if b.flags().enable_pcc() { pcc::check_vcode_facts(f, &mut vcode, b).map_err(CodegenError::Pcc)?; } // Perform register allocation. let regalloc_result = { let _tt = timing::regalloc(); let mut options = RegallocOptions::default(); options.verbose_log = b.flags().regalloc_verbose_logs(); if cfg!(debug_assertions) { options.validate_ssa = true; } options.algorithm = match b.flags().regalloc_algorithm() { RegallocAlgorithm::Backtracking => Algorithm::Ion, RegallocAlgorithm::SinglePass => Algorithm::Fastalloc, }; regalloc2::run(&vcode, vcode.machine_env(), &options) .map_err(|err| { log::error!( "Register allocation error for vcode\n{:?}\nError: {:?}\nCLIF for error:\n{:?}", vcode, err, f, ); err }) .expect("register allocation") }; // Run the regalloc checker, if requested. if b.flags().regalloc_checker() { let _tt = timing::regalloc_checker(); let mut checker = regalloc2::checker::Checker::new(&vcode, vcode.machine_env()); checker.prepare(®alloc_result); checker .run() .map_err(|err| { log::error!( "Register allocation checker errors:\n{:?}\nfor vcode:\n{:?}", err, vcode ); err }) .expect("register allocation checker"); } Ok((vcode, regalloc_result)) }