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