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