cranelift_codegen/isa/x64/
mod.rs

1//! X86_64-bit Instruction Set Architecture.
2
3pub use self::inst::{args, EmitInfo, EmitState, Inst};
4
5use super::{OwnedTargetIsa, TargetIsa};
6use crate::dominator_tree::DominatorTree;
7use crate::ir::{types, Function, Type};
8#[cfg(feature = "unwind")]
9use crate::isa::unwind::systemv;
10use crate::isa::x64::settings as x64_settings;
11use crate::isa::{Builder as IsaBuilder, FunctionAlignment};
12use crate::machinst::{
13    compile, CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet,
14    TextSectionBuilder, VCode,
15};
16use crate::result::CodegenResult;
17use crate::settings::{self as shared_settings, Flags};
18use crate::{Final, MachBufferFinalized};
19use alloc::{boxed::Box, vec::Vec};
20use core::fmt;
21use cranelift_control::ControlPlane;
22use target_lexicon::Triple;
23
24mod abi;
25pub mod encoding;
26mod inst;
27mod lower;
28mod pcc;
29pub mod settings;
30
31pub use inst::unwind::systemv::create_cie;
32
33/// An X64 backend.
34pub(crate) struct X64Backend {
35    triple: Triple,
36    flags: Flags,
37    x64_flags: x64_settings::Flags,
38}
39
40impl X64Backend {
41    /// Create a new X64 backend with the given (shared) flags.
42    fn new_with_flags(triple: Triple, flags: Flags, x64_flags: x64_settings::Flags) -> Self {
43        Self {
44            triple,
45            flags,
46            x64_flags,
47        }
48    }
49
50    fn compile_vcode(
51        &self,
52        func: &Function,
53        domtree: &DominatorTree,
54        ctrl_plane: &mut ControlPlane,
55    ) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
56        // This performs lowering to VCode, register-allocates the code, computes
57        // block layout and finalizes branches. The result is ready for binary emission.
58        let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone());
59        let sigs = SigSet::new::<abi::X64ABIMachineSpec>(func, &self.flags)?;
60        let abi = abi::X64Callee::new(func, self, &self.x64_flags, &sigs)?;
61        compile::compile::<Self>(func, domtree, self, abi, emit_info, sigs, ctrl_plane)
62    }
63}
64
65impl TargetIsa for X64Backend {
66    fn compile_function(
67        &self,
68        func: &Function,
69        domtree: &DominatorTree,
70        want_disasm: bool,
71        ctrl_plane: &mut ControlPlane,
72    ) -> CodegenResult<CompiledCodeStencil> {
73        let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?;
74
75        let emit_result = vcode.emit(&regalloc_result, want_disasm, &self.flags, ctrl_plane);
76        let frame_size = emit_result.frame_size;
77        let value_labels_ranges = emit_result.value_labels_ranges;
78        let buffer = emit_result.buffer;
79        let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
80        let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;
81
82        if let Some(disasm) = emit_result.disasm.as_ref() {
83            crate::trace!("disassembly:\n{}", disasm);
84        }
85
86        Ok(CompiledCodeStencil {
87            buffer,
88            frame_size,
89            vcode: emit_result.disasm,
90            value_labels_ranges,
91            sized_stackslot_offsets,
92            dynamic_stackslot_offsets,
93            bb_starts: emit_result.bb_offsets,
94            bb_edges: emit_result.bb_edges,
95        })
96    }
97
98    fn flags(&self) -> &Flags {
99        &self.flags
100    }
101
102    fn isa_flags(&self) -> Vec<shared_settings::Value> {
103        self.x64_flags.iter().collect()
104    }
105
106    fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {
107        16
108    }
109
110    fn name(&self) -> &'static str {
111        "x64"
112    }
113
114    fn triple(&self) -> &Triple {
115        &self.triple
116    }
117
118    #[cfg(feature = "unwind")]
119    fn emit_unwind_info(
120        &self,
121        result: &CompiledCode,
122        kind: crate::isa::unwind::UnwindInfoKind,
123    ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
124        emit_unwind_info(&result.buffer, kind)
125    }
126
127    #[cfg(feature = "unwind")]
128    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
129        Some(inst::unwind::systemv::create_cie())
130    }
131
132    #[cfg(feature = "unwind")]
133    fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {
134        inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
135    }
136
137    fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
138        Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))
139    }
140
141    fn function_alignment(&self) -> FunctionAlignment {
142        Inst::function_alignment()
143    }
144
145    fn page_size_align_log2(&self) -> u8 {
146        debug_assert_eq!(1 << 12, 0x1000);
147        12
148    }
149
150    #[cfg(feature = "disas")]
151    fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
152        use capstone::prelude::*;
153        Capstone::new()
154            .x86()
155            .mode(arch::x86::ArchMode::Mode64)
156            .syntax(arch::x86::ArchSyntax::Att)
157            .detail(true)
158            .build()
159    }
160
161    fn has_native_fma(&self) -> bool {
162        self.x64_flags.use_fma()
163    }
164
165    fn has_x86_blendv_lowering(&self, ty: Type) -> bool {
166        // The `blendvpd`, `blendvps`, and `pblendvb` instructions are all only
167        // available from SSE 4.1 and onwards. Otherwise the i16x8 type has no
168        // equivalent instruction which only looks at the top bit for a select
169        // operation, so that always returns `false`
170        self.x64_flags.use_sse41() && ty != types::I16X8
171    }
172
173    fn has_x86_pshufb_lowering(&self) -> bool {
174        self.x64_flags.use_ssse3()
175    }
176
177    fn has_x86_pmulhrsw_lowering(&self) -> bool {
178        self.x64_flags.use_ssse3()
179    }
180
181    fn has_x86_pmaddubsw_lowering(&self) -> bool {
182        self.x64_flags.use_ssse3()
183    }
184}
185
186/// Emit unwind info for an x86 target.
187pub fn emit_unwind_info(
188    buffer: &MachBufferFinalized<Final>,
189    kind: crate::isa::unwind::UnwindInfoKind,
190) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
191    use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};
192    Ok(match kind {
193        UnwindInfoKind::SystemV => {
194            let mapper = self::inst::unwind::systemv::RegisterMapper;
195            Some(UnwindInfo::SystemV(
196                crate::isa::unwind::systemv::create_unwind_info_from_insts(
197                    &buffer.unwind_info[..],
198                    buffer.data().len(),
199                    &mapper,
200                )?,
201            ))
202        }
203        UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
204            crate::isa::unwind::winx64::create_unwind_info_from_insts::<
205                self::inst::unwind::winx64::RegisterMapper,
206            >(&buffer.unwind_info[..])?,
207        )),
208        _ => None,
209    })
210}
211
212impl fmt::Display for X64Backend {
213    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214        f.debug_struct("MachBackend")
215            .field("name", &self.name())
216            .field("triple", &self.triple())
217            .field("flags", &format!("{}", self.flags()))
218            .finish()
219    }
220}
221
222/// Create a new `isa::Builder`.
223pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
224    IsaBuilder {
225        triple,
226        setup: x64_settings::builder(),
227        constructor: isa_constructor,
228    }
229}
230
231fn isa_constructor(
232    triple: Triple,
233    shared_flags: Flags,
234    builder: &shared_settings::Builder,
235) -> CodegenResult<OwnedTargetIsa> {
236    let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
237    let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags);
238    Ok(backend.wrapped())
239}