cranelift_codegen/isa/x64/
mod.rs1pub use self::inst::{args, external, 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
34pub(crate) struct X64Backend {
36 triple: Triple,
37 flags: Flags,
38 x64_flags: x64_settings::Flags,
39}
40
41impl X64Backend {
42 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 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(®alloc_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_round(&self) -> bool {
171 self.x64_flags.use_sse41()
172 }
173
174 fn has_x86_blendv_lowering(&self, ty: Type) -> bool {
175 self.x64_flags.use_sse41() && ty != types::I16X8
180 }
181
182 fn has_x86_pshufb_lowering(&self) -> bool {
183 self.x64_flags.use_ssse3()
184 }
185
186 fn has_x86_pmulhrsw_lowering(&self) -> bool {
187 self.x64_flags.use_ssse3()
188 }
189
190 fn has_x86_pmaddubsw_lowering(&self) -> bool {
191 self.x64_flags.use_ssse3()
192 }
193
194 fn default_argument_extension(&self) -> ir::ArgumentExtension {
195 ir::ArgumentExtension::Uext
203 }
204}
205
206pub fn emit_unwind_info(
208 buffer: &MachBufferFinalized<Final>,
209 kind: crate::isa::unwind::UnwindInfoKind,
210) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
211 use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};
212 Ok(match kind {
213 UnwindInfoKind::SystemV => {
214 let mapper = self::inst::unwind::systemv::RegisterMapper;
215 Some(UnwindInfo::SystemV(
216 crate::isa::unwind::systemv::create_unwind_info_from_insts(
217 &buffer.unwind_info[..],
218 buffer.data().len(),
219 &mapper,
220 )?,
221 ))
222 }
223 UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
224 crate::isa::unwind::winx64::create_unwind_info_from_insts::<
225 self::inst::unwind::winx64::RegisterMapper,
226 >(&buffer.unwind_info[..])?,
227 )),
228 _ => None,
229 })
230}
231
232impl fmt::Display for X64Backend {
233 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234 f.debug_struct("MachBackend")
235 .field("name", &self.name())
236 .field("triple", &self.triple())
237 .field("flags", &format!("{}", self.flags()))
238 .finish()
239 }
240}
241
242pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
244 IsaBuilder {
245 triple,
246 setup: x64_settings::builder(),
247 constructor: isa_constructor,
248 }
249}
250
251fn isa_constructor(
252 triple: Triple,
253 shared_flags: Flags,
254 builder: &shared_settings::Builder,
255) -> CodegenResult<OwnedTargetIsa> {
256 let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
257 let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags);
258 Ok(backend.wrapped())
259}