Path: blob/main/cranelift/codegen/src/isa/x64/mod.rs
3050 views
//! X86_64-bit Instruction Set Architecture.12pub use self::inst::{AtomicRmwSeqOp, EmitInfo, EmitState, Inst, args, external};34use super::{OwnedTargetIsa, TargetIsa};5use crate::dominator_tree::DominatorTree;6use crate::ir::{self, Function, Type, types};7#[cfg(feature = "unwind")]8use crate::isa::unwind::systemv;9use crate::isa::x64::settings as x64_settings;10use crate::isa::{Builder as IsaBuilder, FunctionAlignment, IsaFlagsHashKey};11use crate::machinst::{12CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet, TextSectionBuilder, VCode,13compile,14};15use crate::result::{CodegenError, CodegenResult};16use crate::settings::{self as shared_settings, Flags};17use crate::{Final, MachBufferFinalized};18use alloc::string::String;19use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};20use core::fmt;21use cranelift_control::ControlPlane;22use target_lexicon::Triple;2324mod abi;25mod inst;26mod lower;27mod pcc;28pub mod settings;2930#[cfg(feature = "unwind")]31pub use inst::unwind::systemv::create_cie;3233/// An X64 backend.34pub(crate) struct X64Backend {35triple: Triple,36flags: Flags,37x64_flags: x64_settings::Flags,38}3940impl X64Backend {41/// Create a new X64 backend with the given (shared) flags.42fn new_with_flags(43triple: Triple,44flags: Flags,45x64_flags: x64_settings::Flags,46) -> CodegenResult<Self> {47if triple.pointer_width().unwrap() != target_lexicon::PointerWidth::U64 {48return Err(CodegenError::Unsupported(49"the x32 ABI is not supported".to_owned(),50));51}5253Ok(Self {54triple,55flags,56x64_flags,57})58}5960fn compile_vcode(61&self,62func: &Function,63domtree: &DominatorTree,64ctrl_plane: &mut ControlPlane,65) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {66// This performs lowering to VCode, register-allocates the code, computes67// block layout and finalizes branches. The result is ready for binary emission.68let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone());69let sigs = SigSet::new::<abi::X64ABIMachineSpec>(func, &self.flags)?;70let abi = abi::X64Callee::new(func, self, &self.x64_flags, &sigs)?;71compile::compile::<Self>(func, domtree, self, abi, emit_info, sigs, ctrl_plane)72}73}7475impl TargetIsa for X64Backend {76fn compile_function(77&self,78func: &Function,79domtree: &DominatorTree,80want_disasm: bool,81ctrl_plane: &mut ControlPlane,82) -> CodegenResult<CompiledCodeStencil> {83let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?;8485let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane);86let value_labels_ranges = emit_result.value_labels_ranges;87let buffer = emit_result.buffer;8889if let Some(disasm) = emit_result.disasm.as_ref() {90crate::trace!("disassembly:\n{}", disasm);91}9293Ok(CompiledCodeStencil {94buffer,95vcode: emit_result.disasm,96value_labels_ranges,97bb_starts: emit_result.bb_offsets,98bb_edges: emit_result.bb_edges,99})100}101102fn flags(&self) -> &Flags {103&self.flags104}105106fn isa_flags(&self) -> Vec<shared_settings::Value> {107self.x64_flags.iter().collect()108}109110fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> {111IsaFlagsHashKey(self.x64_flags.hash_key())112}113114fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {11516116}117118fn name(&self) -> &'static str {119"x64"120}121122fn triple(&self) -> &Triple {123&self.triple124}125126#[cfg(feature = "unwind")]127fn emit_unwind_info(128&self,129result: &crate::machinst::CompiledCode,130kind: crate::isa::unwind::UnwindInfoKind,131) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {132emit_unwind_info(&result.buffer, kind)133}134135#[cfg(feature = "unwind")]136fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {137Some(inst::unwind::systemv::create_cie())138}139140#[cfg(feature = "unwind")]141fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {142inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)143}144145fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {146Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))147}148149fn function_alignment(&self) -> FunctionAlignment {150Inst::function_alignment()151}152153fn page_size_align_log2(&self) -> u8 {154debug_assert_eq!(1 << 12, 0x1000);15512156}157158#[cfg(feature = "disas")]159fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {160use capstone::prelude::*;161Capstone::new()162.x86()163.mode(arch::x86::ArchMode::Mode64)164.syntax(arch::x86::ArchSyntax::Att)165.detail(true)166.build()167}168169fn pretty_print_reg(&self, reg: Reg, size: u8) -> String {170inst::regs::pretty_print_reg(reg, size)171}172173fn has_native_fma(&self) -> bool {174self.x64_flags.has_avx() && self.x64_flags.has_fma()175}176177fn has_round(&self) -> bool {178self.x64_flags.has_sse41()179}180181fn has_blendv_lowering(&self, ty: Type) -> bool {182// The `blendvpd`, `blendvps`, and `pblendvb` instructions are all only183// available from SSE 4.1 and onwards. Otherwise the i16x8 type has no184// equivalent instruction which only looks at the top bit for a select185// operation, so that always returns `false`186self.x64_flags.has_sse41() && ty != types::I16X8187}188189fn has_x86_pshufb_lowering(&self) -> bool {190self.x64_flags.has_ssse3()191}192193fn has_x86_pmulhrsw_lowering(&self) -> bool {194self.x64_flags.has_ssse3()195}196197fn has_x86_pmaddubsw_lowering(&self) -> bool {198self.x64_flags.has_ssse3()199}200201fn default_argument_extension(&self) -> ir::ArgumentExtension {202// This is copied/carried over from a historical piece of code in203// Wasmtime:204//205// https://github.com/bytecodealliance/wasmtime/blob/a018a5a9addb77d5998021a0150192aa955c71bf/crates/cranelift/src/lib.rs#L366-L374206//207// Whether or not it is still applicable here is unsure, but it's left208// the same as-is for now to reduce the likelihood of problems arising.209ir::ArgumentExtension::Uext210}211}212213/// Emit unwind info for an x86 target.214pub fn emit_unwind_info(215buffer: &MachBufferFinalized<Final>,216kind: crate::isa::unwind::UnwindInfoKind,217) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {218#[cfg(feature = "unwind")]219use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};220#[cfg(not(feature = "unwind"))]221let _ = buffer;222Ok(match kind {223#[cfg(feature = "unwind")]224UnwindInfoKind::SystemV => {225let mapper = self::inst::unwind::systemv::RegisterMapper;226Some(UnwindInfo::SystemV(227crate::isa::unwind::systemv::create_unwind_info_from_insts(228&buffer.unwind_info[..],229buffer.data().len(),230&mapper,231)?,232))233}234#[cfg(feature = "unwind")]235UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(236crate::isa::unwind::winx64::create_unwind_info_from_insts::<237self::inst::unwind::winx64::RegisterMapper,238>(&buffer.unwind_info[..])?,239)),240_ => None,241})242}243244impl fmt::Display for X64Backend {245fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {246f.debug_struct("MachBackend")247.field("name", &self.name())248.field("triple", &self.triple())249.field("flags", &format!("{}", self.flags()))250.finish()251}252}253254/// Create a new `isa::Builder`.255pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {256IsaBuilder {257triple,258setup: x64_settings::builder(),259constructor: isa_constructor,260}261}262263fn isa_constructor(264triple: Triple,265shared_flags: Flags,266builder: &shared_settings::Builder,267) -> CodegenResult<OwnedTargetIsa> {268let isa_flags = x64_settings::Flags::new(&shared_flags, builder);269let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags)?;270Ok(backend.wrapped())271}272273274