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 CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet, TextSectionBuilder, VCode,
14 compile,
15};
16use crate::result::{CodegenError, CodegenResult};
17use crate::settings::{self as shared_settings, Flags};
18use crate::{Final, MachBufferFinalized};
19use alloc::string::String;
20use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
21use core::fmt;
22use cranelift_control::ControlPlane;
23use target_lexicon::Triple;
24
25mod abi;
26mod inst;
27mod lower;
28pub mod settings;
29
30#[cfg(feature = "unwind")]
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 regalloc_ctx: &mut regalloc2::Ctx,
65 ctrl_plane: &mut ControlPlane,
66 ) -> CodegenResult<VCode<inst::Inst>> {
67 let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone());
70 let sigs = SigSet::new::<abi::X64ABIMachineSpec>(func, &self.flags)?;
71 let abi = abi::X64Callee::new(func, self, &self.x64_flags, &sigs)?;
72 compile::compile::<Self>(
73 func,
74 domtree,
75 regalloc_ctx,
76 self,
77 abi,
78 emit_info,
79 sigs,
80 ctrl_plane,
81 )
82 }
83}
84
85impl TargetIsa for X64Backend {
86 fn compile_function(
87 &self,
88 func: &Function,
89 domtree: &DominatorTree,
90 regalloc_ctx: &mut regalloc2::Ctx,
91 want_disasm: bool,
92 ctrl_plane: &mut ControlPlane,
93 ) -> CodegenResult<CompiledCodeStencil> {
94 let vcode = self.compile_vcode(func, domtree, regalloc_ctx, ctrl_plane)?;
95
96 let emit_result = vcode.emit(®alloc_ctx.output, want_disasm, &self.flags, ctrl_plane)?;
97 let value_labels_ranges = emit_result.value_labels_ranges;
98 let buffer = emit_result.buffer;
99
100 if let Some(disasm) = emit_result.disasm.as_ref() {
101 crate::trace!("disassembly:\n{}", disasm);
102 }
103
104 Ok(CompiledCodeStencil {
105 buffer,
106 vcode: emit_result.disasm,
107 value_labels_ranges,
108 bb_starts: emit_result.bb_offsets,
109 bb_edges: emit_result.bb_edges,
110 })
111 }
112
113 fn flags(&self) -> &Flags {
114 &self.flags
115 }
116
117 fn isa_flags(&self) -> Vec<shared_settings::Value> {
118 self.x64_flags.iter().collect()
119 }
120
121 fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> {
122 IsaFlagsHashKey(self.x64_flags.hash_key())
123 }
124
125 fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {
126 16
127 }
128
129 fn name(&self) -> &'static str {
130 "x64"
131 }
132
133 fn triple(&self) -> &Triple {
134 &self.triple
135 }
136
137 #[cfg(feature = "unwind")]
138 fn emit_unwind_info(
139 &self,
140 result: &crate::machinst::CompiledCode,
141 kind: crate::isa::unwind::UnwindInfoKind,
142 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
143 emit_unwind_info(&result.buffer, kind)
144 }
145
146 #[cfg(feature = "unwind")]
147 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
148 Some(inst::unwind::systemv::create_cie())
149 }
150
151 #[cfg(feature = "unwind")]
152 fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {
153 inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
154 }
155
156 fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
157 Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))
158 }
159
160 fn function_alignment(&self) -> FunctionAlignment {
161 Inst::function_alignment()
162 }
163
164 fn page_size_align_log2(&self) -> u8 {
165 debug_assert_eq!(1 << 12, 0x1000);
166 12
167 }
168
169 #[cfg(feature = "disas")]
170 fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
171 use capstone::prelude::*;
172 Capstone::new()
173 .x86()
174 .mode(arch::x86::ArchMode::Mode64)
175 .syntax(arch::x86::ArchSyntax::Att)
176 .detail(true)
177 .build()
178 }
179
180 fn pretty_print_reg(&self, reg: Reg, size: u8) -> String {
181 inst::regs::pretty_print_reg(reg, size)
182 }
183
184 fn has_native_fma(&self) -> bool {
185 self.x64_flags.has_avx() && self.x64_flags.has_fma()
186 }
187
188 fn has_round(&self) -> bool {
189 self.x64_flags.has_sse41()
190 }
191
192 fn has_blendv_lowering(&self, ty: Type) -> bool {
193 self.x64_flags.has_sse41() && ty != types::I16X8
198 }
199
200 fn has_x86_pshufb_lowering(&self) -> bool {
201 self.x64_flags.has_ssse3()
202 }
203
204 fn has_x86_pmulhrsw_lowering(&self) -> bool {
205 self.x64_flags.has_ssse3()
206 }
207
208 fn has_x86_pmaddubsw_lowering(&self) -> bool {
209 self.x64_flags.has_ssse3()
210 }
211
212 fn default_argument_extension(&self) -> ir::ArgumentExtension {
213 ir::ArgumentExtension::Uext
221 }
222}
223
224pub fn emit_unwind_info(
226 buffer: &MachBufferFinalized<Final>,
227 kind: crate::isa::unwind::UnwindInfoKind,
228) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
229 #[cfg(feature = "unwind")]
230 use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};
231 #[cfg(not(feature = "unwind"))]
232 let _ = buffer;
233 Ok(match kind {
234 #[cfg(feature = "unwind")]
235 UnwindInfoKind::SystemV => {
236 let mapper = self::inst::unwind::systemv::RegisterMapper;
237 Some(UnwindInfo::SystemV(
238 crate::isa::unwind::systemv::create_unwind_info_from_insts(
239 &buffer.unwind_info[..],
240 buffer.data().len(),
241 &mapper,
242 )?,
243 ))
244 }
245 #[cfg(feature = "unwind")]
246 UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
247 crate::isa::unwind::winx64::create_unwind_info_from_insts::<
248 self::inst::unwind::winx64::RegisterMapper,
249 >(&buffer.unwind_info[..])?,
250 )),
251 _ => None,
252 })
253}
254
255impl fmt::Display for X64Backend {
256 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257 f.debug_struct("MachBackend")
258 .field("name", &self.name())
259 .field("triple", &self.triple())
260 .field("flags", &format!("{}", self.flags()))
261 .finish()
262 }
263}
264
265pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
267 IsaBuilder {
268 triple,
269 setup: x64_settings::builder(),
270 constructor: isa_constructor,
271 }
272}
273
274fn isa_constructor(
275 triple: Triple,
276 shared_flags: Flags,
277 builder: &shared_settings::Builder,
278) -> CodegenResult<OwnedTargetIsa> {
279 let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
280 let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags)?;
281 Ok(backend.wrapped())
282}