cranelift-codegen 0.71.0

Low-level code generator library
Documentation
use crate::isa::unwind::input::UnwindInfo;
use crate::isa::x64::inst::{
    args::{AluRmiROpcode, Amode, OperandSize, RegMemImm, SyntheticAmode},
    regs, Inst,
};
use crate::machinst::{UnwindInfoContext, UnwindInfoGenerator};
use crate::result::CodegenResult;
use alloc::vec::Vec;
use regalloc::Reg;

#[cfg(feature = "unwind")]
pub(crate) mod systemv;

pub struct X64UnwindInfo;

impl UnwindInfoGenerator<Inst> for X64UnwindInfo {
    fn create_unwind_info(
        context: UnwindInfoContext<Inst>,
    ) -> CodegenResult<Option<UnwindInfo<Reg>>> {
        use crate::isa::unwind::input::{self, UnwindCode};
        let mut codes = Vec::new();
        const WORD_SIZE: u8 = 8;

        for i in context.prologue.clone() {
            let i = i as usize;
            let inst = &context.insts[i];
            let offset = context.insts_layout[i];

            match inst {
                Inst::Push64 {
                    src: RegMemImm::Reg { reg },
                } => {
                    codes.push((
                        offset,
                        UnwindCode::StackAlloc {
                            size: WORD_SIZE.into(),
                        },
                    ));
                    codes.push((
                        offset,
                        UnwindCode::SaveRegister {
                            reg: *reg,
                            stack_offset: 0,
                        },
                    ));
                }
                Inst::MovRR { src, dst, .. } => {
                    if *src == regs::rsp() {
                        codes.push((offset, UnwindCode::SetFramePointer { reg: dst.to_reg() }));
                    }
                }
                Inst::AluRmiR {
                    size: OperandSize::Size64,
                    op: AluRmiROpcode::Sub,
                    src: RegMemImm::Imm { simm32 },
                    dst,
                    ..
                } if dst.to_reg() == regs::rsp() => {
                    let imm = *simm32;
                    codes.push((offset, UnwindCode::StackAlloc { size: imm }));
                }
                Inst::MovRM {
                    src,
                    dst: SyntheticAmode::Real(Amode::ImmReg { simm32, base, .. }),
                    ..
                } if *base == regs::rsp() => {
                    // `mov reg, imm(rsp)`
                    let imm = *simm32;
                    codes.push((
                        offset,
                        UnwindCode::SaveRegister {
                            reg: *src,
                            stack_offset: imm,
                        },
                    ));
                }
                Inst::AluRmiR {
                    size: OperandSize::Size64,
                    op: AluRmiROpcode::Add,
                    src: RegMemImm::Imm { simm32 },
                    dst,
                    ..
                } if dst.to_reg() == regs::rsp() => {
                    let imm = *simm32;
                    codes.push((offset, UnwindCode::StackDealloc { size: imm }));
                }
                _ => {}
            }
        }

        let last_epilogue_end = context.len;
        let epilogues_unwind_codes = context
            .epilogues
            .iter()
            .map(|epilogue| {
                // TODO add logic to process epilogue instruction instead of
                // returning empty array.
                let end = epilogue.end as usize - 1;
                let end_offset = context.insts_layout[end];
                if end_offset == last_epilogue_end {
                    // Do not remember/restore for very last epilogue.
                    return vec![];
                }

                let start = epilogue.start as usize;
                let offset = context.insts_layout[start];
                vec![
                    (offset, UnwindCode::RememberState),
                    // TODO epilogue instructions
                    (end_offset, UnwindCode::RestoreState),
                ]
            })
            .collect();

        let prologue_size = context.insts_layout[context.prologue.end as usize];
        Ok(Some(input::UnwindInfo {
            prologue_size,
            prologue_unwind_codes: codes,
            epilogues_unwind_codes,
            function_size: context.len,
            word_size: WORD_SIZE,
            initial_sp_offset: WORD_SIZE,
        }))
    }
}