1 //! Instruction Set Architectures. 2 //! 3 //! The `isa` module provides a `TargetIsa` trait which provides the behavior specialization needed 4 //! by the ISA-independent code generator. The sub-modules of this module provide definitions for 5 //! the instruction sets that Cranelift can target. Each sub-module has it's own implementation of 6 //! `TargetIsa`. 7 //! 8 //! # Constructing a `TargetIsa` instance 9 //! 10 //! The target ISA is built from the following information: 11 //! 12 //! - The name of the target ISA as a string. Cranelift is a cross-compiler, so the ISA to target 13 //! can be selected dynamically. Individual ISAs can be left out when Cranelift is compiled, so a 14 //! string is used to identify the proper sub-module. 15 //! - Values for settings that apply to all ISAs. This is represented by a `settings::Flags` 16 //! instance. 17 //! - Values for ISA-specific settings. 18 //! 19 //! The `isa::lookup()` function is the main entry point which returns an `isa::Builder` 20 //! appropriate for the requested ISA: 21 //! 22 //! ``` 23 //! # #[macro_use] extern crate target_lexicon; 24 //! use cranelift_codegen::isa; 25 //! use cranelift_codegen::settings::{self, Configurable}; 26 //! use std::str::FromStr; 27 //! use target_lexicon::Triple; 28 //! 29 //! let shared_builder = settings::builder(); 30 //! let shared_flags = settings::Flags::new(shared_builder); 31 //! 32 //! match isa::lookup(triple!("x86_64")) { 33 //! Err(_) => { 34 //! // The x86_64 target ISA is not available. 35 //! } 36 //! Ok(mut isa_builder) => { 37 //! isa_builder.set("use_popcnt", "on"); 38 //! let isa = isa_builder.finish(shared_flags); 39 //! } 40 //! } 41 //! ``` 42 //! 43 //! The configured target ISA trait object is a `Box<TargetIsa>` which can be used for multiple 44 //! concurrent function compilations. 45 46 pub use crate::isa::call_conv::CallConv; 47 pub use crate::isa::constraints::{ 48 BranchRange, ConstraintKind, OperandConstraint, RecipeConstraints, 49 }; 50 pub use crate::isa::enc_tables::Encodings; 51 pub use crate::isa::encoding::{base_size, EncInfo, Encoding}; 52 pub use crate::isa::registers::{regs_overlap, RegClass, RegClassIndex, RegInfo, RegUnit}; 53 pub use crate::isa::stack::{StackBase, StackBaseMask, StackRef}; 54 55 use crate::binemit; 56 use crate::flowgraph; 57 use crate::ir; 58 #[cfg(feature = "unwind")] 59 use crate::isa::unwind::systemv::RegisterMappingError; 60 use crate::machinst::{MachBackend, UnwindInfoKind}; 61 use crate::regalloc; 62 use crate::result::CodegenResult; 63 use crate::settings; 64 use crate::settings::SetResult; 65 use crate::timing; 66 use alloc::{borrow::Cow, boxed::Box, vec::Vec}; 67 use core::any::Any; 68 use core::fmt; 69 use core::fmt::{Debug, Formatter}; 70 use core::hash::Hasher; 71 use target_lexicon::{triple, Architecture, OperatingSystem, PointerWidth, Triple}; 72 use thiserror::Error; 73 74 #[cfg(feature = "riscv")] 75 mod riscv; 76 77 // N.B.: the old x86-64 backend (`x86`) and the new one (`x64`) are both 78 // included whenever building with x86 support. The new backend is the default, 79 // but the old can be requested with `BackendVariant::Legacy`. However, if this 80 // crate is built with the `old-x86-backend` feature, then the old backend is 81 // default instead. 82 #[cfg(feature = "x86")] 83 mod x86; 84 85 #[cfg(feature = "x86")] 86 mod x64; 87 88 #[cfg(feature = "arm32")] 89 mod arm32; 90 91 #[cfg(feature = "arm64")] 92 pub(crate) mod aarch64; 93 94 pub mod unwind; 95 96 mod call_conv; 97 mod constraints; 98 mod enc_tables; 99 mod encoding; 100 pub mod registers; 101 mod stack; 102 103 #[cfg(test)] 104 mod test_utils; 105 106 /// Returns a builder that can create a corresponding `TargetIsa` 107 /// or `Err(LookupError::SupportDisabled)` if not enabled. 108 macro_rules! isa_builder { 109 ($name: ident, $cfg_terms: tt, $triple: ident) => {{ 110 #[cfg $cfg_terms] 111 { 112 Ok($name::isa_builder($triple)) 113 } 114 #[cfg(not $cfg_terms)] 115 { 116 Err(LookupError::SupportDisabled) 117 } 118 }}; 119 } 120 121 /// The "variant" for a given target. On one platform (x86-64), we have two 122 /// backends, the "old" and "new" one; the new one is the default if included 123 /// in the build configuration and not otherwise specified. 124 #[derive(Clone, Copy, Debug)] 125 pub enum BackendVariant { 126 /// Any backend available. 127 Any, 128 /// A "legacy" backend: one that operates using legalizations and encodings. 129 Legacy, 130 /// A backend built on `MachInst`s and the `VCode` framework. 131 MachInst, 132 } 133 134 impl Default for BackendVariant { 135 fn default() -> Self { 136 BackendVariant::Any 137 } 138 } 139 140 /// Look for an ISA for the given `triple`, selecting the backend variant given 141 /// by `variant` if available. 142 pub fn lookup_variant(triple: Triple, variant: BackendVariant) -> Result<Builder, LookupError> { 143 match (triple.architecture, variant) { 144 (Architecture::Riscv32 { .. }, _) | (Architecture::Riscv64 { .. }, _) => { 145 isa_builder!(riscv, (feature = "riscv"), triple) 146 } 147 (Architecture::X86_64, BackendVariant::Legacy) => { 148 isa_builder!(x86, (feature = "x86"), triple) 149 } 150 (Architecture::X86_64, BackendVariant::MachInst) => { 151 isa_builder!(x64, (feature = "x86"), triple) 152 } 153 #[cfg(not(feature = "old-x86-backend"))] 154 (Architecture::X86_64, BackendVariant::Any) => { 155 isa_builder!(x64, (feature = "x86"), triple) 156 } 157 #[cfg(feature = "old-x86-backend")] 158 (Architecture::X86_64, BackendVariant::Any) => { 159 isa_builder!(x86, (feature = "x86"), triple) 160 } 161 (Architecture::Arm { .. }, _) => isa_builder!(arm32, (feature = "arm32"), triple), 162 (Architecture::Aarch64 { .. }, _) => isa_builder!(aarch64, (feature = "arm64"), triple), 163 _ => Err(LookupError::Unsupported), 164 } 165 } 166 167 /// Look for an ISA for the given `triple`. 168 /// Return a builder that can create a corresponding `TargetIsa`. 169 pub fn lookup(triple: Triple) -> Result<Builder, LookupError> { 170 lookup_variant(triple, BackendVariant::Any) 171 } 172 173 /// Look for a supported ISA with the given `name`. 174 /// Return a builder that can create a corresponding `TargetIsa`. 175 pub fn lookup_by_name(name: &str) -> Result<Builder, LookupError> { 176 use alloc::str::FromStr; 177 lookup(triple!(name)) 178 } 179 180 /// Describes reason for target lookup failure 181 #[derive(Error, PartialEq, Eq, Copy, Clone, Debug)] 182 pub enum LookupError { 183 /// Support for this target was disabled in the current build. 184 #[error("Support for this target is disabled")] 185 SupportDisabled, 186 187 /// Support for this target has not yet been implemented. 188 #[error("Support for this target has not been implemented yet")] 189 Unsupported, 190 } 191 192 /// Builder for a `TargetIsa`. 193 /// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`. 194 #[derive(Clone)] 195 pub struct Builder { 196 triple: Triple, 197 setup: settings::Builder, 198 constructor: fn(Triple, settings::Flags, settings::Builder) -> Box<dyn TargetIsa>, 199 } 200 201 impl Builder { 202 /// Gets the triple for the builder. 203 pub fn triple(&self) -> &Triple { 204 &self.triple 205 } 206 207 /// Iterates the available settings in the builder. 208 pub fn iter(&self) -> impl Iterator<Item = settings::Setting> { 209 self.setup.iter() 210 } 211 212 /// Combine the ISA-specific settings with the provided ISA-independent settings and allocate a 213 /// fully configured `TargetIsa` trait object. 214 pub fn finish(self, shared_flags: settings::Flags) -> Box<dyn TargetIsa> { 215 (self.constructor)(self.triple, shared_flags, self.setup) 216 } 217 } 218 219 impl settings::Configurable for Builder { 220 fn set(&mut self, name: &str, value: &str) -> SetResult<()> { 221 self.setup.set(name, value) 222 } 223 224 fn enable(&mut self, name: &str) -> SetResult<()> { 225 self.setup.enable(name) 226 } 227 } 228 229 /// After determining that an instruction doesn't have an encoding, how should we proceed to 230 /// legalize it? 231 /// 232 /// The `Encodings` iterator returns a legalization function to call. 233 pub type Legalize = 234 fn(ir::Inst, &mut ir::Function, &mut flowgraph::ControlFlowGraph, &dyn TargetIsa) -> bool; 235 236 /// This struct provides information that a frontend may need to know about a target to 237 /// produce Cranelift IR for the target. 238 #[derive(Clone, Copy, Hash)] 239 pub struct TargetFrontendConfig { 240 /// The default calling convention of the target. 241 pub default_call_conv: CallConv, 242 243 /// The pointer width of the target. 244 pub pointer_width: PointerWidth, 245 } 246 247 impl TargetFrontendConfig { 248 /// Get the pointer type of this target. 249 pub fn pointer_type(self) -> ir::Type { 250 ir::Type::int(u16::from(self.pointer_bits())).unwrap() 251 } 252 253 /// Get the width of pointers on this target, in units of bits. 254 pub fn pointer_bits(self) -> u8 { 255 self.pointer_width.bits() 256 } 257 258 /// Get the width of pointers on this target, in units of bytes. 259 pub fn pointer_bytes(self) -> u8 { 260 self.pointer_width.bytes() 261 } 262 } 263 264 /// Methods that are specialized to a target ISA. Implies a Display trait that shows the 265 /// shared flags, as well as any isa-specific flags. 266 pub trait TargetIsa: fmt::Display + Send + Sync { 267 /// Get the name of this ISA. 268 fn name(&self) -> &'static str; 269 270 /// Get the target triple that was used to make this trait object. 271 fn triple(&self) -> &Triple; 272 273 /// Get the ISA-independent flags that were used to make this trait object. 274 fn flags(&self) -> &settings::Flags; 275 276 /// Get the ISA-dependent flag values that were used to make this trait object. 277 fn isa_flags(&self) -> Vec<settings::Value>; 278 279 /// Get the variant of this ISA (Legacy or MachInst). 280 fn variant(&self) -> BackendVariant { 281 BackendVariant::Legacy 282 } 283 284 /// Hashes all flags, both ISA-independent and ISA-specific, into the 285 /// specified hasher. 286 fn hash_all_flags(&self, hasher: &mut dyn Hasher); 287 288 /// Get the default calling convention of this target. 289 fn default_call_conv(&self) -> CallConv { 290 CallConv::triple_default(self.triple()) 291 } 292 293 /// Get the endianness of this ISA. 294 fn endianness(&self) -> ir::Endianness { 295 match self.triple().endianness().unwrap() { 296 target_lexicon::Endianness::Little => ir::Endianness::Little, 297 target_lexicon::Endianness::Big => ir::Endianness::Big, 298 } 299 } 300 301 /// Get the pointer type of this ISA. 302 fn pointer_type(&self) -> ir::Type { 303 ir::Type::int(u16::from(self.pointer_bits())).unwrap() 304 } 305 306 /// Get the width of pointers on this ISA. 307 fn pointer_width(&self) -> PointerWidth { 308 self.triple().pointer_width().unwrap() 309 } 310 311 /// Get the width of pointers on this ISA, in units of bits. 312 fn pointer_bits(&self) -> u8 { 313 self.pointer_width().bits() 314 } 315 316 /// Get the width of pointers on this ISA, in units of bytes. 317 fn pointer_bytes(&self) -> u8 { 318 self.pointer_width().bytes() 319 } 320 321 /// Get the information needed by frontends producing Cranelift IR. 322 fn frontend_config(&self) -> TargetFrontendConfig { 323 TargetFrontendConfig { 324 default_call_conv: self.default_call_conv(), 325 pointer_width: self.pointer_width(), 326 } 327 } 328 329 /// Does the CPU implement scalar comparisons using a CPU flags register? 330 fn uses_cpu_flags(&self) -> bool { 331 false 332 } 333 334 /// Does the CPU implement multi-register addressing? 335 fn uses_complex_addresses(&self) -> bool { 336 false 337 } 338 339 /// Get a data structure describing the registers in this ISA. 340 fn register_info(&self) -> RegInfo; 341 342 #[cfg(feature = "unwind")] 343 /// Map a Cranelift register to its corresponding DWARF register. 344 fn map_dwarf_register(&self, _: RegUnit) -> Result<u16, RegisterMappingError> { 345 Err(RegisterMappingError::UnsupportedArchitecture) 346 } 347 348 #[cfg(feature = "unwind")] 349 /// Map a regalloc::Reg to its corresponding DWARF register. 350 fn map_regalloc_reg_to_dwarf(&self, _: ::regalloc::Reg) -> Result<u16, RegisterMappingError> { 351 Err(RegisterMappingError::UnsupportedArchitecture) 352 } 353 354 /// Returns an iterator over legal encodings for the instruction. 355 fn legal_encodings<'a>( 356 &'a self, 357 func: &'a ir::Function, 358 inst: &'a ir::InstructionData, 359 ctrl_typevar: ir::Type, 360 ) -> Encodings<'a>; 361 362 /// Encode an instruction after determining it is legal. 363 /// 364 /// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object. 365 /// Otherwise, return `Legalize` action. 366 /// 367 /// This is also the main entry point for determining if an instruction is legal. 368 fn encode( 369 &self, 370 func: &ir::Function, 371 inst: &ir::InstructionData, 372 ctrl_typevar: ir::Type, 373 ) -> Result<Encoding, Legalize> { 374 let mut iter = self.legal_encodings(func, inst, ctrl_typevar); 375 iter.next().ok_or_else(|| iter.legalize()) 376 } 377 378 /// Get a data structure describing the instruction encodings in this ISA. 379 fn encoding_info(&self) -> EncInfo; 380 381 /// Legalize a function signature. 382 /// 383 /// This is used to legalize both the signature of the function being compiled and any called 384 /// functions. The signature should be modified by adding `ArgumentLoc` annotations to all 385 /// arguments and return values. 386 /// 387 /// Arguments with types that are not supported by the ABI can be expanded into multiple 388 /// arguments: 389 /// 390 /// - Integer types that are too large to fit in a register can be broken into multiple 391 /// arguments of a smaller integer type. 392 /// - Floating point types can be bit-cast to an integer type of the same size, and possible 393 /// broken into smaller integer types. 394 /// - Vector types can be bit-cast and broken down into smaller vectors or scalars. 395 /// 396 /// The legalizer will adapt argument and return values as necessary at all ABI boundaries. 397 /// 398 /// When this function is called to legalize the signature of the function currently being 399 /// compiled, `current` is true. The legalized signature can then also contain special purpose 400 /// arguments and return values such as: 401 /// 402 /// - A `link` argument representing the link registers on RISC architectures that don't push 403 /// the return address on the stack. 404 /// - A `link` return value which will receive the value that was passed to the `link` 405 /// argument. 406 /// - An `sret` argument can be added if one wasn't present already. This is necessary if the 407 /// signature returns more values than registers are available for returning values. 408 /// - An `sret` return value can be added if the ABI requires a function to return its `sret` 409 /// argument in a register. 410 /// 411 /// Arguments and return values for the caller's frame pointer and other callee-saved registers 412 /// should not be added by this function. These arguments are not added until after register 413 /// allocation. 414 fn legalize_signature(&self, sig: &mut Cow<ir::Signature>, current: bool); 415 416 /// Get the register class that should be used to represent an ABI argument or return value of 417 /// type `ty`. This should be the top-level register class that contains the argument 418 /// registers. 419 /// 420 /// This function can assume that it will only be asked to provide register classes for types 421 /// that `legalize_signature()` produces in `ArgumentLoc::Reg` entries. 422 fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass; 423 424 /// Get the set of allocatable registers that can be used when compiling `func`. 425 /// 426 /// This set excludes reserved registers like the stack pointer and other special-purpose 427 /// registers. 428 fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet; 429 430 /// Compute the stack layout and insert prologue and epilogue code into `func`. 431 /// 432 /// Return an error if the stack frame is too large. 433 fn prologue_epilogue(&self, func: &mut ir::Function) -> CodegenResult<()> { 434 let _tt = timing::prologue_epilogue(); 435 // This default implementation is unlikely to be good enough. 436 use crate::ir::stackslot::{StackOffset, StackSize}; 437 use crate::stack_layout::layout_stack; 438 439 let word_size = StackSize::from(self.pointer_bytes()); 440 441 // Account for the SpiderMonkey standard prologue pushes. 442 if func.signature.call_conv.extends_baldrdash() { 443 let bytes = StackSize::from(self.flags().baldrdash_prologue_words()) * word_size; 444 let mut ss = ir::StackSlotData::new(ir::StackSlotKind::IncomingArg, bytes); 445 ss.offset = Some(-(bytes as StackOffset)); 446 func.stack_slots.push(ss); 447 } 448 449 let is_leaf = func.is_leaf(); 450 layout_stack(&mut func.stack_slots, is_leaf, word_size)?; 451 Ok(()) 452 } 453 454 /// Emit binary machine code for a single instruction into the `sink` trait object. 455 /// 456 /// Note that this will call `put*` methods on the `sink` trait object via its vtable which 457 /// is not the fastest way of emitting code. 458 /// 459 /// This function is under the "testing_hooks" feature, and is only suitable for use by 460 /// test harnesses. It increases code size, and is inefficient. 461 #[cfg(feature = "testing_hooks")] 462 fn emit_inst( 463 &self, 464 func: &ir::Function, 465 inst: ir::Inst, 466 divert: &mut regalloc::RegDiversions, 467 sink: &mut dyn binemit::CodeSink, 468 ); 469 470 /// Emit a whole function into memory. 471 fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink); 472 473 /// IntCC condition for Unsigned Addition Overflow (Carry). 474 fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC; 475 476 /// IntCC condition for Unsigned Subtraction Overflow (Borrow/Carry). 477 fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC; 478 479 /// Returns the flavor of unwind information emitted for this target. 480 fn unwind_info_kind(&self) -> UnwindInfoKind { 481 match self.triple().operating_system { 482 #[cfg(feature = "unwind")] 483 OperatingSystem::Windows => UnwindInfoKind::Windows, 484 #[cfg(feature = "unwind")] 485 _ => UnwindInfoKind::SystemV, 486 #[cfg(not(feature = "unwind"))] 487 _ => UnwindInfoKind::None, 488 } 489 } 490 491 /// Creates unwind information for the function. 492 /// 493 /// Returns `None` if there is no unwind information for the function. 494 #[cfg(feature = "unwind")] 495 fn create_unwind_info( 496 &self, 497 _func: &ir::Function, 498 ) -> CodegenResult<Option<unwind::UnwindInfo>> { 499 // By default, an ISA has no unwind information 500 Ok(None) 501 } 502 503 /// Creates a new System V Common Information Entry for the ISA. 504 /// 505 /// Returns `None` if the ISA does not support System V unwind information. 506 #[cfg(feature = "unwind")] 507 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> { 508 // By default, an ISA cannot create a System V CIE 509 None 510 } 511 512 /// Get the new-style MachBackend, if this is an adapter around one. 513 fn get_mach_backend(&self) -> Option<&dyn MachBackend> { 514 None 515 } 516 517 /// Return an [Any] reference for downcasting to the ISA-specific implementation of this trait 518 /// with `isa.as_any().downcast_ref::<isa::foo::Isa>()`. 519 fn as_any(&self) -> &dyn Any; 520 } 521 522 impl Debug for &dyn TargetIsa { 523 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 524 write!( 525 f, 526 "TargetIsa {{ triple: {:?}, pointer_width: {:?}}}", 527 self.triple(), 528 self.pointer_width() 529 ) 530 } 531 } 532