1 //! Compilation backend pipeline: optimized IR to VCode / binemit. 2 3 use crate::CodegenError; 4 use crate::dominator_tree::DominatorTree; 5 use crate::ir::Function; 6 use crate::ir::pcc; 7 use crate::isa::TargetIsa; 8 use crate::machinst::*; 9 use crate::settings::RegallocAlgorithm; 10 use crate::timing; 11 use crate::trace; 12 13 use regalloc2::{Algorithm, RegallocOptions}; 14 15 /// Compile the given function down to VCode with allocated registers, ready 16 /// for binary emission. 17 pub fn compile<B: LowerBackend + TargetIsa>( 18 f: &Function, 19 domtree: &DominatorTree, 20 b: &B, 21 abi: Callee<<<B as LowerBackend>::MInst as MachInst>::ABIMachineSpec>, 22 emit_info: <B::MInst as MachInstEmit>::Info, 23 sigs: SigSet, 24 ctrl_plane: &mut ControlPlane, 25 ) -> CodegenResult<(VCode<B::MInst>, regalloc2::Output)> { 26 // Compute lowered block order. 27 let block_order = BlockLoweringOrder::new(f, domtree, ctrl_plane); 28 29 // Build the lowering context. 30 let lower = 31 crate::machinst::Lower::new(f, abi, emit_info, block_order, sigs, b.flags().clone())?; 32 33 // Lower the IR. 34 let mut vcode = { 35 log::debug!( 36 "Number of CLIF instructions to lower: {}", 37 f.dfg.num_insts() 38 ); 39 log::debug!("Number of CLIF blocks to lower: {}", f.dfg.num_blocks()); 40 41 let _tt = timing::vcode_lower(); 42 lower.lower(b, ctrl_plane)? 43 }; 44 45 log::debug!( 46 "Number of lowered vcode instructions: {}", 47 vcode.num_insts() 48 ); 49 log::debug!("Number of lowered vcode blocks: {}", vcode.num_blocks()); 50 trace!("vcode from lowering: \n{:?}", vcode); 51 52 // Perform validation of proof-carrying-code facts, if requested. 53 if b.flags().enable_pcc() { 54 pcc::check_vcode_facts(f, &mut vcode, b).map_err(CodegenError::Pcc)?; 55 } 56 57 // Perform register allocation. 58 let regalloc_result = { 59 let _tt = timing::regalloc(); 60 let mut options = RegallocOptions::default(); 61 options.verbose_log = b.flags().regalloc_verbose_logs(); 62 63 if cfg!(debug_assertions) { 64 options.validate_ssa = true; 65 } 66 67 options.algorithm = match b.flags().regalloc_algorithm() { 68 RegallocAlgorithm::Backtracking => Algorithm::Ion, 69 // Note: single-pass is currently disabled 70 // (https://github.com/bytecodealliance/regalloc2/issues/217). 71 }; 72 73 regalloc2::run(&vcode, vcode.abi.machine_env(), &options) 74 .map_err(|err| { 75 log::error!( 76 "Register allocation error for vcode\n{:?}\nError: {:?}\nCLIF for error:\n{:?}", 77 vcode, 78 err, 79 f, 80 ); 81 err 82 }) 83 .expect("register allocation") 84 }; 85 86 // Run the regalloc checker, if requested. 87 if b.flags().regalloc_checker() { 88 let _tt = timing::regalloc_checker(); 89 let mut checker = regalloc2::checker::Checker::new(&vcode, vcode.abi.machine_env()); 90 checker.prepare(®alloc_result); 91 checker 92 .run() 93 .map_err(|err| { 94 log::error!( 95 "Register allocation checker errors:\n{:?}\nfor vcode:\n{:?}", 96 err, 97 vcode 98 ); 99 err 100 }) 101 .expect("register allocation checker"); 102 } 103 104 Ok((vcode, regalloc_result)) 105 } 106