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