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