use crate::binemit::{CodeInfo, CodeOffset, StackMap};
use crate::ir::condcodes::IntCC;
use crate::ir::{Function, SourceLoc, StackSlot, Type, ValueLabel};
use crate::result::CodegenResult;
use crate::settings::{self, Flags};
use crate::value_label::ValueLabelsRanges;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt::Debug;
use core::hash::Hasher;
use cranelift_entity::PrimaryMap;
use regalloc::RegUsageCollector;
use regalloc::{
RealReg, RealRegUniverse, Reg, RegClass, RegUsageMapper, SpillSlot, VirtualReg, Writable,
};
use smallvec::{smallvec, SmallVec};
use std::string::String;
use target_lexicon::Triple;
#[cfg(feature = "unwind")]
use crate::isa::unwind::systemv::RegisterMappingError;
pub mod lower;
pub use lower::*;
pub mod vcode;
pub use vcode::*;
pub mod compile;
pub use compile::*;
pub mod blockorder;
pub use blockorder::*;
pub mod abi;
pub use abi::*;
pub mod abi_impl;
pub use abi_impl::*;
pub mod buffer;
pub use buffer::*;
pub mod adapter;
pub use adapter::*;
pub mod helpers;
pub use helpers::*;
pub mod inst_common;
pub use inst_common::*;
pub mod valueregs;
pub use valueregs::*;
pub mod debug;
pub trait MachInst: Clone + Debug {
fn get_regs(&self, collector: &mut RegUsageCollector);
fn map_regs<RUM: RegUsageMapper>(&mut self, maps: &RUM);
fn is_move(&self) -> Option<(Writable<Reg>, Reg)>;
fn is_term<'a>(&'a self) -> MachTerminator<'a>;
fn is_epilogue_placeholder(&self) -> bool;
fn is_included_in_clobbers(&self) -> bool {
true
}
fn stack_op_info(&self) -> Option<MachInstStackOpInfo> {
None
}
fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Self;
fn gen_constant<F: FnMut(Type) -> Writable<Reg>>(
to_regs: ValueRegs<Writable<Reg>>,
value: u128,
ty: Type,
alloc_tmp: F,
) -> SmallVec<[Self; 4]>;
fn maybe_direct_reload(&self, reg: VirtualReg, slot: SpillSlot) -> Option<Self>;
fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])>;
fn gen_jump(target: MachLabel) -> Self;
fn gen_nop(preferred_size: usize) -> Self;
fn reg_universe(flags: &Flags) -> RealRegUniverse;
fn align_basic_block(offset: CodeOffset) -> CodeOffset {
offset
}
fn worst_case_size() -> CodeOffset;
fn ref_type_regclass(_flags: &Flags) -> RegClass;
fn defines_value_label(&self) -> Option<(ValueLabel, Reg)> {
None
}
fn gen_value_label_marker(_label: ValueLabel, _reg: Reg) -> Self {
Self::gen_nop(0)
}
type LabelUse: MachInstLabelUse;
}
pub trait MachInstLabelUse: Clone + Copy + Debug + Eq {
const ALIGN: CodeOffset;
fn max_pos_range(self) -> CodeOffset;
fn max_neg_range(self) -> CodeOffset;
fn patch_size(self) -> CodeOffset;
fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset);
fn supports_veneer(self) -> bool;
fn veneer_size(self) -> CodeOffset;
fn generate_veneer(self, buffer: &mut [u8], veneer_offset: CodeOffset) -> (CodeOffset, Self);
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MachTerminator<'a> {
None,
Ret,
Uncond(MachLabel),
Cond(MachLabel, MachLabel),
Indirect(&'a [MachLabel]),
}
impl<'a> MachTerminator<'a> {
pub fn get_succs(&self) -> SmallVec<[MachLabel; 2]> {
let mut ret = smallvec![];
match self {
&MachTerminator::Uncond(l) => {
ret.push(l);
}
&MachTerminator::Cond(l1, l2) => {
ret.push(l1);
ret.push(l2);
}
&MachTerminator::Indirect(ls) => {
ret.extend(ls.iter().cloned());
}
_ => {}
}
ret
}
pub fn is_term(&self) -> bool {
match self {
MachTerminator::None => false,
_ => true,
}
}
}
pub trait MachInstEmit: MachInst {
type State: MachInstEmitState<Self>;
type Info: MachInstEmitInfo;
fn emit(&self, code: &mut MachBuffer<Self>, info: &Self::Info, state: &mut Self::State);
fn pretty_print(&self, mb_rru: Option<&RealRegUniverse>, state: &mut Self::State) -> String;
}
pub trait MachInstEmitInfo {
fn flags(&self) -> &Flags;
}
pub trait MachInstEmitState<I: MachInst>: Default + Clone + Debug {
fn new(abi: &dyn ABICallee<I = I>) -> Self;
fn pre_safepoint(&mut self, _stack_map: StackMap) {}
fn pre_sourceloc(&mut self, _srcloc: SourceLoc) {}
}
pub struct MachCompileResult {
pub buffer: MachBufferFinalized,
pub frame_size: u32,
pub disasm: Option<String>,
pub value_labels_ranges: ValueLabelsRanges,
pub stackslot_offsets: PrimaryMap<StackSlot, u32>,
pub bb_starts: Vec<CodeOffset>,
pub bb_edges: Vec<(CodeOffset, CodeOffset)>,
}
impl MachCompileResult {
pub fn code_info(&self) -> CodeInfo {
let code_size = self.buffer.total_size();
CodeInfo {
code_size,
jumptables_size: 0,
rodata_size: 0,
total_size: code_size,
}
}
}
pub trait MachBackend {
fn compile_function(
&self,
func: &Function,
want_disasm: bool,
) -> CodegenResult<MachCompileResult>;
fn flags(&self) -> &Flags;
fn isa_flags(&self) -> Vec<settings::Value>;
fn hash_all_flags(&self, hasher: &mut dyn Hasher);
fn triple(&self) -> Triple;
fn name(&self) -> &'static str;
fn reg_universe(&self) -> &RealRegUniverse;
fn unsigned_add_overflow_condition(&self) -> IntCC;
fn unsigned_sub_overflow_condition(&self) -> IntCC;
#[cfg(feature = "unwind")]
fn emit_unwind_info(
&self,
_result: &MachCompileResult,
_kind: UnwindInfoKind,
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
Ok(None)
}
#[cfg(feature = "unwind")]
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
None
}
#[cfg(feature = "unwind")]
fn map_reg_to_dwarf(&self, _: Reg) -> Result<u16, RegisterMappingError> {
Err(RegisterMappingError::UnsupportedArchitecture)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum UnwindInfoKind {
None,
#[cfg(feature = "unwind")]
SystemV,
#[cfg(feature = "unwind")]
Windows,
}
#[derive(Clone, Copy, Debug)]
pub enum MachInstStackOpInfo {
LoadNomSPOff(Reg, i64),
StoreNomSPOff(Reg, i64),
NomSPAdj(i64),
}