1 //! X86_64-bit Instruction Set Architecture. 2 3 pub use self::inst::{AtomicRmwSeqOp, EmitInfo, EmitState, Inst, args, external}; 4 5 use super::{OwnedTargetIsa, TargetIsa}; 6 use crate::dominator_tree::DominatorTree; 7 use crate::ir::{self, Function, Type, types}; 8 #[cfg(feature = "unwind")] 9 use crate::isa::unwind::systemv; 10 use crate::isa::x64::settings as x64_settings; 11 use crate::isa::{Builder as IsaBuilder, FunctionAlignment, IsaFlagsHashKey}; 12 use crate::machinst::{ 13 CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet, TextSectionBuilder, VCode, 14 compile, 15 }; 16 use crate::result::{CodegenError, CodegenResult}; 17 use crate::settings::{self as shared_settings, Flags}; 18 use crate::{Final, MachBufferFinalized}; 19 use alloc::string::String; 20 use alloc::{borrow::ToOwned, boxed::Box, vec::Vec}; 21 use core::fmt; 22 use cranelift_control::ControlPlane; 23 use target_lexicon::Triple; 24 25 mod abi; 26 mod inst; 27 mod lower; 28 mod pcc; 29 pub mod settings; 30 31 #[cfg(feature = "unwind")] 32 pub use inst::unwind::systemv::create_cie; 33 34 /// An X64 backend. 35 pub(crate) struct X64Backend { 36 triple: Triple, 37 flags: Flags, 38 x64_flags: x64_settings::Flags, 39 } 40 41 impl X64Backend { 42 /// Create a new X64 backend with the given (shared) flags. 43 fn new_with_flags( 44 triple: Triple, 45 flags: Flags, 46 x64_flags: x64_settings::Flags, 47 ) -> CodegenResult<Self> { 48 if triple.pointer_width().unwrap() != target_lexicon::PointerWidth::U64 { 49 return Err(CodegenError::Unsupported( 50 "the x32 ABI is not supported".to_owned(), 51 )); 52 } 53 54 Ok(Self { 55 triple, 56 flags, 57 x64_flags, 58 }) 59 } 60 61 fn compile_vcode( 62 &self, 63 func: &Function, 64 domtree: &DominatorTree, 65 ctrl_plane: &mut ControlPlane, 66 ) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> { 67 // This performs lowering to VCode, register-allocates the code, computes 68 // block layout and finalizes branches. The result is ready for binary emission. 69 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>(func, domtree, self, abi, emit_info, sigs, ctrl_plane) 73 } 74 } 75 76 impl TargetIsa for X64Backend { 77 fn compile_function( 78 &self, 79 func: &Function, 80 domtree: &DominatorTree, 81 want_disasm: bool, 82 ctrl_plane: &mut ControlPlane, 83 ) -> CodegenResult<CompiledCodeStencil> { 84 let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?; 85 86 let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane); 87 let value_labels_ranges = emit_result.value_labels_ranges; 88 let buffer = emit_result.buffer; 89 90 if let Some(disasm) = emit_result.disasm.as_ref() { 91 crate::trace!("disassembly:\n{}", disasm); 92 } 93 94 Ok(CompiledCodeStencil { 95 buffer, 96 vcode: emit_result.disasm, 97 value_labels_ranges, 98 bb_starts: emit_result.bb_offsets, 99 bb_edges: emit_result.bb_edges, 100 }) 101 } 102 103 fn flags(&self) -> &Flags { 104 &self.flags 105 } 106 107 fn isa_flags(&self) -> Vec<shared_settings::Value> { 108 self.x64_flags.iter().collect() 109 } 110 111 fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> { 112 IsaFlagsHashKey(self.x64_flags.hash_key()) 113 } 114 115 fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 { 116 16 117 } 118 119 fn name(&self) -> &'static str { 120 "x64" 121 } 122 123 fn triple(&self) -> &Triple { 124 &self.triple 125 } 126 127 #[cfg(feature = "unwind")] 128 fn emit_unwind_info( 129 &self, 130 result: &crate::machinst::CompiledCode, 131 kind: crate::isa::unwind::UnwindInfoKind, 132 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> { 133 emit_unwind_info(&result.buffer, kind) 134 } 135 136 #[cfg(feature = "unwind")] 137 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> { 138 Some(inst::unwind::systemv::create_cie()) 139 } 140 141 #[cfg(feature = "unwind")] 142 fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> { 143 inst::unwind::systemv::map_reg(reg).map(|reg| reg.0) 144 } 145 146 fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> { 147 Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs)) 148 } 149 150 fn function_alignment(&self) -> FunctionAlignment { 151 Inst::function_alignment() 152 } 153 154 fn page_size_align_log2(&self) -> u8 { 155 debug_assert_eq!(1 << 12, 0x1000); 156 12 157 } 158 159 #[cfg(feature = "disas")] 160 fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> { 161 use capstone::prelude::*; 162 Capstone::new() 163 .x86() 164 .mode(arch::x86::ArchMode::Mode64) 165 .syntax(arch::x86::ArchSyntax::Att) 166 .detail(true) 167 .build() 168 } 169 170 fn pretty_print_reg(&self, reg: Reg, size: u8) -> String { 171 inst::regs::pretty_print_reg(reg, size) 172 } 173 174 fn has_native_fma(&self) -> bool { 175 self.x64_flags.has_avx() && self.x64_flags.has_fma() 176 } 177 178 fn has_round(&self) -> bool { 179 self.x64_flags.has_sse41() 180 } 181 182 fn has_blendv_lowering(&self, ty: Type) -> bool { 183 // The `blendvpd`, `blendvps`, and `pblendvb` instructions are all only 184 // available from SSE 4.1 and onwards. Otherwise the i16x8 type has no 185 // equivalent instruction which only looks at the top bit for a select 186 // operation, so that always returns `false` 187 self.x64_flags.has_sse41() && ty != types::I16X8 188 } 189 190 fn has_x86_pshufb_lowering(&self) -> bool { 191 self.x64_flags.has_ssse3() 192 } 193 194 fn has_x86_pmulhrsw_lowering(&self) -> bool { 195 self.x64_flags.has_ssse3() 196 } 197 198 fn has_x86_pmaddubsw_lowering(&self) -> bool { 199 self.x64_flags.has_ssse3() 200 } 201 202 fn default_argument_extension(&self) -> ir::ArgumentExtension { 203 // This is copied/carried over from a historical piece of code in 204 // Wasmtime: 205 // 206 // https://github.com/bytecodealliance/wasmtime/blob/a018a5a9addb77d5998021a0150192aa955c71bf/crates/cranelift/src/lib.rs#L366-L374 207 // 208 // Whether or not it is still applicable here is unsure, but it's left 209 // the same as-is for now to reduce the likelihood of problems arising. 210 ir::ArgumentExtension::Uext 211 } 212 } 213 214 /// Emit unwind info for an x86 target. 215 pub fn emit_unwind_info( 216 buffer: &MachBufferFinalized<Final>, 217 kind: crate::isa::unwind::UnwindInfoKind, 218 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> { 219 #[cfg(feature = "unwind")] 220 use crate::isa::unwind::{UnwindInfo, UnwindInfoKind}; 221 #[cfg(not(feature = "unwind"))] 222 let _ = buffer; 223 Ok(match kind { 224 #[cfg(feature = "unwind")] 225 UnwindInfoKind::SystemV => { 226 let mapper = self::inst::unwind::systemv::RegisterMapper; 227 Some(UnwindInfo::SystemV( 228 crate::isa::unwind::systemv::create_unwind_info_from_insts( 229 &buffer.unwind_info[..], 230 buffer.data().len(), 231 &mapper, 232 )?, 233 )) 234 } 235 #[cfg(feature = "unwind")] 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 245 impl 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 255 /// Create a new `isa::Builder`. 256 pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder { 257 IsaBuilder { 258 triple, 259 setup: x64_settings::builder(), 260 constructor: isa_constructor, 261 } 262 } 263 264 fn 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 } 273