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