Path: blob/main/cranelift/codegen/src/isa/x64/mod.rs
1693 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::{12CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet,13TextSectionBuilder, VCode, compile,14};15use crate::result::CodegenResult;16use crate::settings::{self as shared_settings, Flags};17use crate::{Final, MachBufferFinalized};18use alloc::{boxed::Box, vec::Vec};19use core::fmt;20use cranelift_control::ControlPlane;21use std::string::String;22use target_lexicon::Triple;2324mod abi;25mod inst;26mod lower;27mod pcc;28pub mod settings;2930pub use inst::unwind::systemv::create_cie;3132/// An X64 backend.33pub(crate) struct X64Backend {34triple: Triple,35flags: Flags,36x64_flags: x64_settings::Flags,37}3839impl X64Backend {40/// Create a new X64 backend with the given (shared) flags.41fn new_with_flags(triple: Triple, flags: Flags, x64_flags: x64_settings::Flags) -> Self {42Self {43triple,44flags,45x64_flags,46}47}4849fn compile_vcode(50&self,51func: &Function,52domtree: &DominatorTree,53ctrl_plane: &mut ControlPlane,54) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {55// This performs lowering to VCode, register-allocates the code, computes56// block layout and finalizes branches. The result is ready for binary emission.57let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone());58let sigs = SigSet::new::<abi::X64ABIMachineSpec>(func, &self.flags)?;59let abi = abi::X64Callee::new(func, self, &self.x64_flags, &sigs)?;60compile::compile::<Self>(func, domtree, self, abi, emit_info, sigs, ctrl_plane)61}62}6364impl TargetIsa for X64Backend {65fn compile_function(66&self,67func: &Function,68domtree: &DominatorTree,69want_disasm: bool,70ctrl_plane: &mut ControlPlane,71) -> CodegenResult<CompiledCodeStencil> {72let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?;7374let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane);75let frame_size = emit_result.frame_size;76let value_labels_ranges = emit_result.value_labels_ranges;77let buffer = emit_result.buffer;78let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;79let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;8081if let Some(disasm) = emit_result.disasm.as_ref() {82crate::trace!("disassembly:\n{}", disasm);83}8485Ok(CompiledCodeStencil {86buffer,87frame_size,88vcode: emit_result.disasm,89value_labels_ranges,90sized_stackslot_offsets,91dynamic_stackslot_offsets,92bb_starts: emit_result.bb_offsets,93bb_edges: emit_result.bb_edges,94})95}9697fn flags(&self) -> &Flags {98&self.flags99}100101fn isa_flags(&self) -> Vec<shared_settings::Value> {102self.x64_flags.iter().collect()103}104105fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> {106IsaFlagsHashKey(self.x64_flags.hash_key())107}108109fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {11016111}112113fn name(&self) -> &'static str {114"x64"115}116117fn triple(&self) -> &Triple {118&self.triple119}120121#[cfg(feature = "unwind")]122fn emit_unwind_info(123&self,124result: &CompiledCode,125kind: crate::isa::unwind::UnwindInfoKind,126) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {127emit_unwind_info(&result.buffer, kind)128}129130#[cfg(feature = "unwind")]131fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {132Some(inst::unwind::systemv::create_cie())133}134135#[cfg(feature = "unwind")]136fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {137inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)138}139140fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {141Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))142}143144fn function_alignment(&self) -> FunctionAlignment {145Inst::function_alignment()146}147148fn page_size_align_log2(&self) -> u8 {149debug_assert_eq!(1 << 12, 0x1000);15012151}152153#[cfg(feature = "disas")]154fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {155use capstone::prelude::*;156Capstone::new()157.x86()158.mode(arch::x86::ArchMode::Mode64)159.syntax(arch::x86::ArchSyntax::Att)160.detail(true)161.build()162}163164fn pretty_print_reg(&self, reg: Reg, size: u8) -> String {165inst::regs::pretty_print_reg(reg, size)166}167168fn has_native_fma(&self) -> bool {169self.x64_flags.use_fma()170}171172fn has_round(&self) -> bool {173self.x64_flags.use_sse41()174}175176fn has_x86_blendv_lowering(&self, ty: Type) -> bool {177// The `blendvpd`, `blendvps`, and `pblendvb` instructions are all only178// available from SSE 4.1 and onwards. Otherwise the i16x8 type has no179// equivalent instruction which only looks at the top bit for a select180// operation, so that always returns `false`181self.x64_flags.use_sse41() && ty != types::I16X8182}183184fn has_x86_pshufb_lowering(&self) -> bool {185self.x64_flags.use_ssse3()186}187188fn has_x86_pmulhrsw_lowering(&self) -> bool {189self.x64_flags.use_ssse3()190}191192fn has_x86_pmaddubsw_lowering(&self) -> bool {193self.x64_flags.use_ssse3()194}195196fn default_argument_extension(&self) -> ir::ArgumentExtension {197// This is copied/carried over from a historical piece of code in198// Wasmtime:199//200// https://github.com/bytecodealliance/wasmtime/blob/a018a5a9addb77d5998021a0150192aa955c71bf/crates/cranelift/src/lib.rs#L366-L374201//202// Whether or not it is still applicable here is unsure, but it's left203// the same as-is for now to reduce the likelihood of problems arising.204ir::ArgumentExtension::Uext205}206}207208/// Emit unwind info for an x86 target.209pub fn emit_unwind_info(210buffer: &MachBufferFinalized<Final>,211kind: crate::isa::unwind::UnwindInfoKind,212) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {213use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};214Ok(match kind {215UnwindInfoKind::SystemV => {216let mapper = self::inst::unwind::systemv::RegisterMapper;217Some(UnwindInfo::SystemV(218crate::isa::unwind::systemv::create_unwind_info_from_insts(219&buffer.unwind_info[..],220buffer.data().len(),221&mapper,222)?,223))224}225UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(226crate::isa::unwind::winx64::create_unwind_info_from_insts::<227self::inst::unwind::winx64::RegisterMapper,228>(&buffer.unwind_info[..])?,229)),230_ => None,231})232}233234impl fmt::Display for X64Backend {235fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {236f.debug_struct("MachBackend")237.field("name", &self.name())238.field("triple", &self.triple())239.field("flags", &format!("{}", self.flags()))240.finish()241}242}243244/// Create a new `isa::Builder`.245pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {246IsaBuilder {247triple,248setup: x64_settings::builder(),249constructor: isa_constructor,250}251}252253fn isa_constructor(254triple: Triple,255shared_flags: Flags,256builder: &shared_settings::Builder,257) -> CodegenResult<OwnedTargetIsa> {258let isa_flags = x64_settings::Flags::new(&shared_flags, builder);259let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags);260Ok(backend.wrapped())261}262263264