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 {
default() -> Self139 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.
lookup_variant(triple: Triple, variant: BackendVariant) -> Result<Builder, LookupError>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`.
lookup(triple: Triple) -> Result<Builder, LookupError>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`.
lookup_by_name(name: &str) -> Result<Builder, LookupError>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 {
fmt(&self, f: &mut Formatter) -> fmt::Result200 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.
triple(&self) -> &Triple221 pub fn triple(&self) -> &Triple {
222 &self.triple
223 }
224
225 /// Iterates the available settings in the builder.
iter(&self) -> impl Iterator<Item = settings::Setting>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.
finish(self, shared_flags: settings::Flags) -> Box<dyn TargetIsa>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 {
set(&mut self, name: &str, value: &str) -> SetResult<()>238 fn set(&mut self, name: &str, value: &str) -> SetResult<()> {
239 self.setup.set(name, value)
240 }
241
enable(&mut self, name: &str) -> SetResult<()>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.
pointer_type(self) -> ir::Type267 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.
pointer_bits(self) -> u8272 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.
pointer_bytes(self) -> u8277 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.
name(&self) -> &'static str286 fn name(&self) -> &'static str;
287
288 /// Get the target triple that was used to make this trait object.
triple(&self) -> &Triple289 fn triple(&self) -> &Triple;
290
291 /// Get the ISA-independent flags that were used to make this trait object.
flags(&self) -> &settings::Flags292 fn flags(&self) -> &settings::Flags;
293
294 /// Get the ISA-dependent flag values that were used to make this trait object.
isa_flags(&self) -> Vec<settings::Value>295 fn isa_flags(&self) -> Vec<settings::Value>;
296
297 /// Get the variant of this ISA (Legacy or MachInst).
variant(&self) -> BackendVariant298 fn variant(&self) -> BackendVariant {
299 BackendVariant::Legacy
300 }
301
302 /// Hashes all flags, both ISA-independent and ISA-specific, into the
303 /// specified hasher.
hash_all_flags(&self, hasher: &mut dyn Hasher)304 fn hash_all_flags(&self, hasher: &mut dyn Hasher);
305
306 /// Get the default calling convention of this target.
default_call_conv(&self) -> CallConv307 fn default_call_conv(&self) -> CallConv {
308 CallConv::triple_default(self.triple())
309 }
310
311 /// Get the endianness of this ISA.
endianness(&self) -> ir::Endianness312 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.
pointer_type(&self) -> ir::Type320 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.
pointer_width(&self) -> PointerWidth325 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.
pointer_bits(&self) -> u8330 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.
pointer_bytes(&self) -> u8335 fn pointer_bytes(&self) -> u8 {
336 self.pointer_width().bytes()
337 }
338
339 /// Get the information needed by frontends producing Cranelift IR.
frontend_config(&self) -> TargetFrontendConfig340 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?
uses_cpu_flags(&self) -> bool348 fn uses_cpu_flags(&self) -> bool {
349 false
350 }
351
352 /// Does the CPU implement multi-register addressing?
uses_complex_addresses(&self) -> bool353 fn uses_complex_addresses(&self) -> bool {
354 false
355 }
356
357 /// Get a data structure describing the registers in this ISA.
register_info(&self) -> RegInfo358 fn register_info(&self) -> RegInfo;
359
360 #[cfg(feature = "unwind")]
361 /// Map a Cranelift register to its corresponding DWARF register.
map_dwarf_register(&self, _: RegUnit) -> Result<u16, RegisterMappingError>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.
map_regalloc_reg_to_dwarf(&self, _: ::regalloc::Reg) -> Result<u16, RegisterMappingError>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.
legal_encodings<'a>( &'a self, func: &'a ir::Function, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type, ) -> Encodings<'a>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.
encode( &self, func: &ir::Function, inst: &ir::InstructionData, ctrl_typevar: ir::Type, ) -> Result<Encoding, Legalize>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.
encoding_info(&self) -> EncInfo397 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.
legalize_signature(&self, sig: &mut Cow<ir::Signature>, current: bool)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.
regclass_for_abi_type(&self, ty: ir::Type) -> RegClass440 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.
allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet446 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.
prologue_epilogue(&self, func: &mut ir::Function) -> CodegenResult<()>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")]
emit_inst( &self, func: &ir::Function, inst: ir::Inst, divert: &mut regalloc::RegDiversions, sink: &mut dyn binemit::CodeSink, )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.
emit_function_to_memory(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink)489 fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);
490
491 /// IntCC condition for Unsigned Addition Overflow (Carry).
unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC492 fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC;
493
494 /// IntCC condition for Unsigned Subtraction Overflow (Borrow/Carry).
unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC495 fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC;
496
497 /// Returns the flavor of unwind information emitted for this target.
unwind_info_kind(&self) -> UnwindInfoKind498 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")]
create_unwind_info( &self, _func: &ir::Function, ) -> CodegenResult<Option<unwind::UnwindInfo>>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")]
create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry>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.
get_mach_backend(&self) -> Option<&dyn MachBackend>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>()`.
as_any(&self) -> &dyn Any537 fn as_any(&self) -> &dyn Any;
538 }
539
540 impl Debug for &dyn TargetIsa {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result541 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