cranelift_codegen/isa/x64/
mod.rs1pub use self::inst::{args, CallInfo, EmitInfo, EmitState, Inst};
4
5use super::{OwnedTargetIsa, TargetIsa};
6use crate::dominator_tree::DominatorTree;
7use crate::ir::{condcodes::IntCC, Function, Type};
8#[cfg(feature = "unwind")]
9use crate::isa::unwind::systemv;
10use crate::isa::x64::{inst::regs::create_reg_env_systemv, settings as x64_settings};
11use crate::isa::Builder as IsaBuilder;
12use crate::machinst::{
13 compile, CompiledCode, CompiledCodeStencil, MachTextSectionBuilder, Reg, SigSet,
14 TextSectionBuilder, VCode,
15};
16use crate::result::{CodegenError, CodegenResult};
17use crate::settings::{self as shared_settings, Flags};
18use alloc::{boxed::Box, vec::Vec};
19use core::fmt;
20use regalloc2::MachineEnv;
21use target_lexicon::Triple;
22
23mod abi;
24pub mod encoding;
25mod inst;
26mod lower;
27pub mod settings;
28
29pub(crate) struct X64Backend {
31 triple: Triple,
32 flags: Flags,
33 x64_flags: x64_settings::Flags,
34 reg_env: MachineEnv,
35}
36
37impl X64Backend {
38 fn new_with_flags(triple: Triple, flags: Flags, x64_flags: x64_settings::Flags) -> Self {
40 let reg_env = create_reg_env_systemv(&flags);
41 Self {
42 triple,
43 flags,
44 x64_flags,
45 reg_env,
46 }
47 }
48
49 fn compile_vcode(
50 &self,
51 func: &Function,
52 domtree: &DominatorTree,
53 ) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
54 let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone());
57 let sigs = SigSet::new::<abi::X64ABIMachineSpec>(func, &self.flags)?;
58 let abi = abi::X64Callee::new(func, self, &self.x64_flags, &sigs)?;
59 compile::compile::<Self>(func, domtree, self, abi, emit_info, sigs)
60 }
61}
62
63impl TargetIsa for X64Backend {
64 fn compile_function(
65 &self,
66 func: &Function,
67 domtree: &DominatorTree,
68 want_disasm: bool,
69 ) -> CodegenResult<CompiledCodeStencil> {
70 let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?;
71
72 let emit_result = vcode.emit(
73 ®alloc_result,
74 want_disasm,
75 self.flags.machine_code_cfg_info(),
76 );
77 let frame_size = emit_result.frame_size;
78 let value_labels_ranges = emit_result.value_labels_ranges;
79 let buffer = emit_result.buffer.finish();
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 log::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 alignment: emit_result.alignment,
97 })
98 }
99
100 fn flags(&self) -> &Flags {
101 &self.flags
102 }
103
104 fn machine_env(&self) -> &MachineEnv {
105 &self.reg_env
106 }
107
108 fn isa_flags(&self) -> Vec<shared_settings::Value> {
109 self.x64_flags.iter().collect()
110 }
111
112 fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {
113 16
114 }
115
116 fn name(&self) -> &'static str {
117 "x64"
118 }
119
120 fn triple(&self) -> &Triple {
121 &self.triple
122 }
123
124 fn unsigned_add_overflow_condition(&self) -> IntCC {
125 IntCC::UnsignedLessThan
128 }
129
130 #[cfg(feature = "unwind")]
131 fn emit_unwind_info(
132 &self,
133 result: &CompiledCode,
134 kind: crate::machinst::UnwindInfoKind,
135 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
136 use crate::isa::unwind::UnwindInfo;
137 use crate::machinst::UnwindInfoKind;
138 Ok(match kind {
139 UnwindInfoKind::SystemV => {
140 let mapper = self::inst::unwind::systemv::RegisterMapper;
141 Some(UnwindInfo::SystemV(
142 crate::isa::unwind::systemv::create_unwind_info_from_insts(
143 &result.buffer.unwind_info[..],
144 result.buffer.data().len(),
145 &mapper,
146 )?,
147 ))
148 }
149 UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
150 crate::isa::unwind::winx64::create_unwind_info_from_insts::<
151 self::inst::unwind::winx64::RegisterMapper,
152 >(&result.buffer.unwind_info[..])?,
153 )),
154 _ => None,
155 })
156 }
157
158 #[cfg(feature = "unwind")]
159 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
160 Some(inst::unwind::systemv::create_cie())
161 }
162
163 #[cfg(feature = "unwind")]
164 fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {
165 inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
166 }
167
168 fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
169 Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))
170 }
171
172 fn function_alignment(&self) -> u32 {
175 16
176 }
177
178 #[cfg(feature = "disas")]
179 fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
180 use capstone::prelude::*;
181 Capstone::new()
182 .x86()
183 .mode(arch::x86::ArchMode::Mode64)
184 .syntax(arch::x86::ArchSyntax::Att)
185 .build()
186 }
187
188 fn has_native_fma(&self) -> bool {
189 self.x64_flags.use_fma()
190 }
191}
192
193impl fmt::Display for X64Backend {
194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195 f.debug_struct("MachBackend")
196 .field("name", &self.name())
197 .field("triple", &self.triple())
198 .field("flags", &format!("{}", self.flags()))
199 .finish()
200 }
201}
202
203pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
205 IsaBuilder {
206 triple,
207 setup: x64_settings::builder(),
208 constructor: isa_constructor,
209 }
210}
211
212fn isa_constructor(
213 triple: Triple,
214 shared_flags: Flags,
215 builder: &shared_settings::Builder,
216) -> CodegenResult<OwnedTargetIsa> {
217 let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
218
219 if shared_flags.enable_simd() {
222 if !isa_flags.has_sse3()
223 || !isa_flags.has_ssse3()
224 || !isa_flags.has_sse41()
225 || !isa_flags.has_sse42()
226 {
227 return Err(CodegenError::Unsupported(
228 "SIMD support requires SSE3, SSSE3, SSE4.1, and SSE4.2 on x86_64.".into(),
229 ));
230 }
231 }
232
233 let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags);
234 Ok(backend.wrapped())
235}
236
237#[cfg(test)]
238mod test {
239 use super::*;
240 use crate::settings;
241 use crate::settings::Configurable;
242
243 #[test]
245 fn simd_required_features() {
246 let mut shared_flags_builder = settings::builder();
247 shared_flags_builder.set("enable_simd", "true").unwrap();
248 let shared_flags = settings::Flags::new(shared_flags_builder);
249 let mut isa_builder = crate::isa::lookup_by_name("x86_64").unwrap();
250 isa_builder.set("has_sse3", "false").unwrap();
251 isa_builder.set("has_ssse3", "false").unwrap();
252 isa_builder.set("has_sse41", "false").unwrap();
253 isa_builder.set("has_sse42", "false").unwrap();
254 assert!(matches!(
255 isa_builder.finish(shared_flags),
256 Err(CodegenError::Unsupported(_)),
257 ));
258 }
259}