cranelift_codegen/isa/x64/
mod.rs

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