cranelift_codegen/isa/x64/
mod.rs1pub use self::inst::{AtomicRmwSeqOp, EmitInfo, EmitState, Inst, args, external};
4
5use super::{OwnedTargetIsa, TargetIsa};
6use crate::dominator_tree::DominatorTree;
7use crate::ir::{self, Function, Type, types};
8#[cfg(feature = "unwind")]
9use crate::isa::unwind::systemv;
10use crate::isa::x64::settings as x64_settings;
11use crate::isa::{Builder as IsaBuilder, FunctionAlignment, IsaFlagsHashKey};
12use crate::machinst::{
13 CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet,
14 TextSectionBuilder, VCode, compile,
15};
16use crate::result::{CodegenError, CodegenResult};
17use crate::settings::{self as shared_settings, Flags};
18use crate::{Final, MachBufferFinalized};
19use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
20use core::fmt;
21use cranelift_control::ControlPlane;
22use std::string::String;
23use target_lexicon::Triple;
24
25mod abi;
26mod inst;
27mod lower;
28mod pcc;
29pub mod settings;
30
31pub use inst::unwind::systemv::create_cie;
32
33pub(crate) struct X64Backend {
35 triple: Triple,
36 flags: Flags,
37 x64_flags: x64_settings::Flags,
38}
39
40impl X64Backend {
41 fn new_with_flags(
43 triple: Triple,
44 flags: Flags,
45 x64_flags: x64_settings::Flags,
46 ) -> CodegenResult<Self> {
47 if triple.pointer_width().unwrap() != target_lexicon::PointerWidth::U64 {
48 return Err(CodegenError::Unsupported(
49 "the x32 ABI is not supported".to_owned(),
50 ));
51 }
52
53 Ok(Self {
54 triple,
55 flags,
56 x64_flags,
57 })
58 }
59
60 fn compile_vcode(
61 &self,
62 func: &Function,
63 domtree: &DominatorTree,
64 ctrl_plane: &mut ControlPlane,
65 ) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
66 let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone());
69 let sigs = SigSet::new::<abi::X64ABIMachineSpec>(func, &self.flags)?;
70 let abi = abi::X64Callee::new(func, self, &self.x64_flags, &sigs)?;
71 compile::compile::<Self>(func, domtree, self, abi, emit_info, sigs, ctrl_plane)
72 }
73}
74
75impl TargetIsa for X64Backend {
76 fn compile_function(
77 &self,
78 func: &Function,
79 domtree: &DominatorTree,
80 want_disasm: bool,
81 ctrl_plane: &mut ControlPlane,
82 ) -> CodegenResult<CompiledCodeStencil> {
83 let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?;
84
85 let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane);
86 let frame_size = emit_result.frame_size;
87 let value_labels_ranges = emit_result.value_labels_ranges;
88 let buffer = emit_result.buffer;
89 let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
90 let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;
91
92 if let Some(disasm) = emit_result.disasm.as_ref() {
93 crate::trace!("disassembly:\n{}", disasm);
94 }
95
96 Ok(CompiledCodeStencil {
97 buffer,
98 frame_size,
99 vcode: emit_result.disasm,
100 value_labels_ranges,
101 sized_stackslot_offsets,
102 dynamic_stackslot_offsets,
103 bb_starts: emit_result.bb_offsets,
104 bb_edges: emit_result.bb_edges,
105 })
106 }
107
108 fn flags(&self) -> &Flags {
109 &self.flags
110 }
111
112 fn isa_flags(&self) -> Vec<shared_settings::Value> {
113 self.x64_flags.iter().collect()
114 }
115
116 fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> {
117 IsaFlagsHashKey(self.x64_flags.hash_key())
118 }
119
120 fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {
121 16
122 }
123
124 fn name(&self) -> &'static str {
125 "x64"
126 }
127
128 fn triple(&self) -> &Triple {
129 &self.triple
130 }
131
132 #[cfg(feature = "unwind")]
133 fn emit_unwind_info(
134 &self,
135 result: &CompiledCode,
136 kind: crate::isa::unwind::UnwindInfoKind,
137 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
138 emit_unwind_info(&result.buffer, kind)
139 }
140
141 #[cfg(feature = "unwind")]
142 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
143 Some(inst::unwind::systemv::create_cie())
144 }
145
146 #[cfg(feature = "unwind")]
147 fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {
148 inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
149 }
150
151 fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
152 Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))
153 }
154
155 fn function_alignment(&self) -> FunctionAlignment {
156 Inst::function_alignment()
157 }
158
159 fn page_size_align_log2(&self) -> u8 {
160 debug_assert_eq!(1 << 12, 0x1000);
161 12
162 }
163
164 #[cfg(feature = "disas")]
165 fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
166 use capstone::prelude::*;
167 Capstone::new()
168 .x86()
169 .mode(arch::x86::ArchMode::Mode64)
170 .syntax(arch::x86::ArchSyntax::Att)
171 .detail(true)
172 .build()
173 }
174
175 fn pretty_print_reg(&self, reg: Reg, size: u8) -> String {
176 inst::regs::pretty_print_reg(reg, size)
177 }
178
179 fn has_native_fma(&self) -> bool {
180 self.x64_flags.has_fma()
181 }
182
183 fn has_round(&self) -> bool {
184 self.x64_flags.has_sse41()
185 }
186
187 fn has_x86_blendv_lowering(&self, ty: Type) -> bool {
188 self.x64_flags.has_sse41() && ty != types::I16X8
193 }
194
195 fn has_x86_pshufb_lowering(&self) -> bool {
196 self.x64_flags.has_ssse3()
197 }
198
199 fn has_x86_pmulhrsw_lowering(&self) -> bool {
200 self.x64_flags.has_ssse3()
201 }
202
203 fn has_x86_pmaddubsw_lowering(&self) -> bool {
204 self.x64_flags.has_ssse3()
205 }
206
207 fn default_argument_extension(&self) -> ir::ArgumentExtension {
208 ir::ArgumentExtension::Uext
216 }
217}
218
219pub fn emit_unwind_info(
221 buffer: &MachBufferFinalized<Final>,
222 kind: crate::isa::unwind::UnwindInfoKind,
223) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
224 use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};
225 Ok(match kind {
226 UnwindInfoKind::SystemV => {
227 let mapper = self::inst::unwind::systemv::RegisterMapper;
228 Some(UnwindInfo::SystemV(
229 crate::isa::unwind::systemv::create_unwind_info_from_insts(
230 &buffer.unwind_info[..],
231 buffer.data().len(),
232 &mapper,
233 )?,
234 ))
235 }
236 UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
237 crate::isa::unwind::winx64::create_unwind_info_from_insts::<
238 self::inst::unwind::winx64::RegisterMapper,
239 >(&buffer.unwind_info[..])?,
240 )),
241 _ => None,
242 })
243}
244
245impl fmt::Display for X64Backend {
246 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
247 f.debug_struct("MachBackend")
248 .field("name", &self.name())
249 .field("triple", &self.triple())
250 .field("flags", &format!("{}", self.flags()))
251 .finish()
252 }
253}
254
255pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
257 IsaBuilder {
258 triple,
259 setup: x64_settings::builder(),
260 constructor: isa_constructor,
261 }
262}
263
264fn isa_constructor(
265 triple: Triple,
266 shared_flags: Flags,
267 builder: &shared_settings::Builder,
268) -> CodegenResult<OwnedTargetIsa> {
269 let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
270 let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags)?;
271 Ok(backend.wrapped())
272}