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::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;
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(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 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(®alloc_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 isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> {
107 IsaFlagsHashKey(self.x64_flags.hash_key())
108 }
109
110 fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {
111 16
112 }
113
114 fn name(&self) -> &'static str {
115 "x64"
116 }
117
118 fn triple(&self) -> &Triple {
119 &self.triple
120 }
121
122 #[cfg(feature = "unwind")]
123 fn emit_unwind_info(
124 &self,
125 result: &CompiledCode,
126 kind: crate::isa::unwind::UnwindInfoKind,
127 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
128 emit_unwind_info(&result.buffer, kind)
129 }
130
131 #[cfg(feature = "unwind")]
132 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
133 Some(inst::unwind::systemv::create_cie())
134 }
135
136 #[cfg(feature = "unwind")]
137 fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {
138 inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
139 }
140
141 fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
142 Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))
143 }
144
145 fn function_alignment(&self) -> FunctionAlignment {
146 Inst::function_alignment()
147 }
148
149 fn page_size_align_log2(&self) -> u8 {
150 debug_assert_eq!(1 << 12, 0x1000);
151 12
152 }
153
154 #[cfg(feature = "disas")]
155 fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
156 use capstone::prelude::*;
157 Capstone::new()
158 .x86()
159 .mode(arch::x86::ArchMode::Mode64)
160 .syntax(arch::x86::ArchSyntax::Att)
161 .detail(true)
162 .build()
163 }
164
165 fn pretty_print_reg(&self, reg: Reg, size: u8) -> String {
166 inst::regs::pretty_print_reg(reg, size)
167 }
168
169 fn has_native_fma(&self) -> bool {
170 self.x64_flags.use_fma()
171 }
172
173 fn has_round(&self) -> bool {
174 self.x64_flags.use_sse41()
175 }
176
177 fn has_x86_blendv_lowering(&self, ty: Type) -> bool {
178 self.x64_flags.use_sse41() && ty != types::I16X8
183 }
184
185 fn has_x86_pshufb_lowering(&self) -> bool {
186 self.x64_flags.use_ssse3()
187 }
188
189 fn has_x86_pmulhrsw_lowering(&self) -> bool {
190 self.x64_flags.use_ssse3()
191 }
192
193 fn has_x86_pmaddubsw_lowering(&self) -> bool {
194 self.x64_flags.use_ssse3()
195 }
196
197 fn default_argument_extension(&self) -> ir::ArgumentExtension {
198 ir::ArgumentExtension::Uext
206 }
207}
208
209pub fn emit_unwind_info(
211 buffer: &MachBufferFinalized<Final>,
212 kind: crate::isa::unwind::UnwindInfoKind,
213) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
214 use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};
215 Ok(match kind {
216 UnwindInfoKind::SystemV => {
217 let mapper = self::inst::unwind::systemv::RegisterMapper;
218 Some(UnwindInfo::SystemV(
219 crate::isa::unwind::systemv::create_unwind_info_from_insts(
220 &buffer.unwind_info[..],
221 buffer.data().len(),
222 &mapper,
223 )?,
224 ))
225 }
226 UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
227 crate::isa::unwind::winx64::create_unwind_info_from_insts::<
228 self::inst::unwind::winx64::RegisterMapper,
229 >(&buffer.unwind_info[..])?,
230 )),
231 _ => None,
232 })
233}
234
235impl fmt::Display for X64Backend {
236 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237 f.debug_struct("MachBackend")
238 .field("name", &self.name())
239 .field("triple", &self.triple())
240 .field("flags", &format!("{}", self.flags()))
241 .finish()
242 }
243}
244
245pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
247 IsaBuilder {
248 triple,
249 setup: x64_settings::builder(),
250 constructor: isa_constructor,
251 }
252}
253
254fn isa_constructor(
255 triple: Triple,
256 shared_flags: Flags,
257 builder: &shared_settings::Builder,
258) -> CodegenResult<OwnedTargetIsa> {
259 let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
260 let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags);
261 Ok(backend.wrapped())
262}