cranelift_codegen/machinst/
compile.rs

1//! Compilation backend pipeline: optimized IR to VCode / binemit.
2
3use crate::CodegenError;
4use crate::dominator_tree::DominatorTree;
5use crate::ir::Function;
6use crate::ir::pcc;
7use crate::isa::TargetIsa;
8use crate::machinst::*;
9use crate::settings::RegallocAlgorithm;
10use crate::timing;
11use crate::trace;
12
13use regalloc2::{Algorithm, RegallocOptions};
14
15/// Compile the given function down to VCode with allocated registers, ready
16/// for binary emission.
17pub 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            RegallocAlgorithm::SinglePass => Algorithm::Fastalloc,
70        };
71
72        regalloc2::run(&vcode, vcode.abi.machine_env(), &options)
73            .map_err(|err| {
74                log::error!(
75                    "Register allocation error for vcode\n{vcode:?}\nError: {err:?}\nCLIF for error:\n{f:?}",
76                );
77                err
78            })
79            .expect("register allocation")
80    };
81
82    // Run the regalloc checker, if requested.
83    if b.flags().regalloc_checker() {
84        let _tt = timing::regalloc_checker();
85        let mut checker = regalloc2::checker::Checker::new(&vcode, vcode.abi.machine_env());
86        checker.prepare(&regalloc_result);
87        checker
88            .run()
89            .map_err(|err| {
90                log::error!("Register allocation checker errors:\n{err:?}\nfor vcode:\n{vcode:?}");
91                err
92            })
93            .expect("register allocation checker");
94    }
95
96    Ok((vcode, regalloc_result))
97}