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