cranelift_codegen/isa/
mod.rs

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
46use crate::dominator_tree::DominatorTree;
47pub use crate::isa::call_conv::CallConv;
48
49use crate::flowgraph;
50use crate::ir::{self, Function};
51#[cfg(feature = "unwind")]
52use crate::isa::unwind::systemv::RegisterMappingError;
53use crate::machinst::{CompiledCode, CompiledCodeStencil, TextSectionBuilder, UnwindInfoKind};
54use crate::settings;
55use crate::settings::SetResult;
56use crate::CodegenResult;
57use alloc::{boxed::Box, sync::Arc, vec::Vec};
58use core::fmt;
59use core::fmt::{Debug, Formatter};
60use target_lexicon::{triple, Architecture, PointerWidth, Triple};
61
62// This module is made public here for benchmarking purposes. No guarantees are
63// made regarding API stability.
64#[cfg(feature = "x86")]
65pub mod x64;
66
67#[cfg(feature = "arm64")]
68pub mod aarch64;
69
70#[cfg(feature = "riscv64")]
71pub mod riscv64;
72
73#[cfg(feature = "s390x")]
74mod s390x;
75
76pub mod unwind;
77
78mod call_conv;
79
80/// Returns a builder that can create a corresponding `TargetIsa`
81/// or `Err(LookupError::SupportDisabled)` if not enabled.
82macro_rules! isa_builder {
83    ($name: ident, $cfg_terms: tt, $triple: ident) => {{
84        #[cfg $cfg_terms]
85        {
86            Ok($name::isa_builder($triple))
87        }
88        #[cfg(not $cfg_terms)]
89        {
90            Err(LookupError::SupportDisabled)
91        }
92    }};
93}
94
95/// Look for an ISA for the given `triple`.
96/// Return a builder that can create a corresponding `TargetIsa`.
97pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
98    match triple.architecture {
99        Architecture::X86_64 => {
100            isa_builder!(x64, (feature = "x86"), triple)
101        }
102        Architecture::Aarch64 { .. } => isa_builder!(aarch64, (feature = "arm64"), triple),
103        Architecture::S390x { .. } => isa_builder!(s390x, (feature = "s390x"), triple),
104        Architecture::Riscv64 { .. } => isa_builder!(riscv64, (feature = "riscv64"), triple),
105        _ => Err(LookupError::Unsupported),
106    }
107}
108
109/// The string names of all the supported, but possibly not enabled, architectures. The elements of
110/// this slice are suitable to be passed to the [lookup_by_name] function to obtain the default
111/// configuration for that architecture.
112pub const ALL_ARCHITECTURES: &[&str] = &["x86_64", "aarch64", "s390x", "riscv64"];
113
114/// Look for a supported ISA with the given `name`.
115/// Return a builder that can create a corresponding `TargetIsa`.
116pub fn lookup_by_name(name: &str) -> Result<Builder, LookupError> {
117    use alloc::str::FromStr;
118    lookup(triple!(name))
119}
120
121/// Describes reason for target lookup failure
122#[derive(PartialEq, Eq, Copy, Clone, Debug)]
123pub enum LookupError {
124    /// Support for this target was disabled in the current build.
125    SupportDisabled,
126
127    /// Support for this target has not yet been implemented.
128    Unsupported,
129}
130
131// This is manually implementing Error and Display instead of using thiserror to reduce the amount
132// of dependencies used by Cranelift.
133impl std::error::Error for LookupError {}
134
135impl fmt::Display for LookupError {
136    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
137        match self {
138            LookupError::SupportDisabled => write!(f, "Support for this target is disabled"),
139            LookupError::Unsupported => {
140                write!(f, "Support for this target has not been implemented yet")
141            }
142        }
143    }
144}
145
146/// The type of a polymorphic TargetISA object which is 'static.
147pub type OwnedTargetIsa = Arc<dyn TargetIsa>;
148
149/// Type alias of `IsaBuilder` used for building Cranelift's ISAs.
150pub type Builder = IsaBuilder<CodegenResult<OwnedTargetIsa>>;
151
152/// Builder for a `TargetIsa`.
153/// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`.
154#[derive(Clone)]
155pub struct IsaBuilder<T> {
156    triple: Triple,
157    setup: settings::Builder,
158    constructor: fn(Triple, settings::Flags, &settings::Builder) -> T,
159}
160
161impl<T> IsaBuilder<T> {
162    /// Creates a new ISA-builder from its components, namely the `triple` for
163    /// the ISA, the ISA-specific settings builder, and a final constructor
164    /// function to generate the ISA from its components.
165    pub fn new(
166        triple: Triple,
167        setup: settings::Builder,
168        constructor: fn(Triple, settings::Flags, &settings::Builder) -> T,
169    ) -> Self {
170        IsaBuilder {
171            triple,
172            setup,
173            constructor,
174        }
175    }
176
177    /// Gets the triple for the builder.
178    pub fn triple(&self) -> &Triple {
179        &self.triple
180    }
181
182    /// Iterates the available settings in the builder.
183    pub fn iter(&self) -> impl Iterator<Item = settings::Setting> {
184        self.setup.iter()
185    }
186
187    /// Combine the ISA-specific settings with the provided
188    /// ISA-independent settings and allocate a fully configured
189    /// `TargetIsa` trait object. May return an error if some of the
190    /// flags are inconsistent or incompatible: for example, some
191    /// platform-independent features, like general SIMD support, may
192    /// need certain ISA extensions to be enabled.
193    pub fn finish(&self, shared_flags: settings::Flags) -> T {
194        (self.constructor)(self.triple.clone(), shared_flags, &self.setup)
195    }
196}
197
198impl<T> settings::Configurable for IsaBuilder<T> {
199    fn set(&mut self, name: &str, value: &str) -> SetResult<()> {
200        self.setup.set(name, value)
201    }
202
203    fn enable(&mut self, name: &str) -> SetResult<()> {
204        self.setup.enable(name)
205    }
206}
207
208/// After determining that an instruction doesn't have an encoding, how should we proceed to
209/// legalize it?
210///
211/// The `Encodings` iterator returns a legalization function to call.
212pub type Legalize =
213    fn(ir::Inst, &mut ir::Function, &mut flowgraph::ControlFlowGraph, &dyn TargetIsa) -> bool;
214
215/// This struct provides information that a frontend may need to know about a target to
216/// produce Cranelift IR for the target.
217#[derive(Clone, Copy, Hash)]
218pub struct TargetFrontendConfig {
219    /// The default calling convention of the target.
220    pub default_call_conv: CallConv,
221
222    /// The pointer width of the target.
223    pub pointer_width: PointerWidth,
224}
225
226impl TargetFrontendConfig {
227    /// Get the pointer type of this target.
228    pub fn pointer_type(self) -> ir::Type {
229        ir::Type::int(self.pointer_bits() as u16).unwrap()
230    }
231
232    /// Get the width of pointers on this target, in units of bits.
233    pub fn pointer_bits(self) -> u8 {
234        self.pointer_width.bits()
235    }
236
237    /// Get the width of pointers on this target, in units of bytes.
238    pub fn pointer_bytes(self) -> u8 {
239        self.pointer_width.bytes()
240    }
241}
242
243/// Methods that are specialized to a target ISA.
244///
245/// Implies a Display trait that shows the shared flags, as well as any ISA-specific flags.
246pub trait TargetIsa: fmt::Display + Send + Sync {
247    /// Get the name of this ISA.
248    fn name(&self) -> &'static str;
249
250    /// Get the target triple that was used to make this trait object.
251    fn triple(&self) -> &Triple;
252
253    /// Get the ISA-independent flags that were used to make this trait object.
254    fn flags(&self) -> &settings::Flags;
255
256    /// Get the ISA-dependent MachineEnv for managing register allocation.
257    fn machine_env(&self) -> &regalloc2::MachineEnv;
258
259    /// Get the ISA-dependent flag values that were used to make this trait object.
260    fn isa_flags(&self) -> Vec<settings::Value>;
261
262    /// Get a flag indicating whether branch protection is enabled.
263    fn is_branch_protection_enabled(&self) -> bool {
264        false
265    }
266
267    /// Get the ISA-dependent maximum vector register size, in bytes.
268    fn dynamic_vector_bytes(&self, dynamic_ty: ir::Type) -> u32;
269
270    /// Compile the given function.
271    fn compile_function(
272        &self,
273        func: &Function,
274        domtree: &DominatorTree,
275        want_disasm: bool,
276    ) -> CodegenResult<CompiledCodeStencil>;
277
278    #[cfg(feature = "unwind")]
279    /// Map a regalloc::Reg to its corresponding DWARF register.
280    fn map_regalloc_reg_to_dwarf(
281        &self,
282        _: crate::machinst::Reg,
283    ) -> Result<u16, RegisterMappingError> {
284        Err(RegisterMappingError::UnsupportedArchitecture)
285    }
286
287    /// IntCC condition for Unsigned Addition Overflow (Carry).
288    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC;
289
290    /// Creates unwind information for the function.
291    ///
292    /// Returns `None` if there is no unwind information for the function.
293    #[cfg(feature = "unwind")]
294    fn emit_unwind_info(
295        &self,
296        result: &CompiledCode,
297        kind: UnwindInfoKind,
298    ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>>;
299
300    /// Creates a new System V Common Information Entry for the ISA.
301    ///
302    /// Returns `None` if the ISA does not support System V unwind information.
303    #[cfg(feature = "unwind")]
304    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
305        // By default, an ISA cannot create a System V CIE
306        None
307    }
308
309    /// Returns an object that can be used to build the text section of an
310    /// executable.
311    ///
312    /// This object will internally attempt to handle as many relocations as
313    /// possible using relative calls/jumps/etc between functions.
314    ///
315    /// The `num_labeled_funcs` argument here is the number of functions which
316    /// will be "labeled" or might have calls between them, typically the number
317    /// of defined functions in the object file.
318    fn text_section_builder(&self, num_labeled_funcs: usize) -> Box<dyn TextSectionBuilder>;
319
320    /// The function alignment required by this ISA.
321    fn function_alignment(&self) -> u32;
322
323    /// Create a polymorphic TargetIsa from this specific implementation.
324    fn wrapped(self) -> OwnedTargetIsa
325    where
326        Self: Sized + 'static,
327    {
328        Arc::new(self)
329    }
330
331    /// Generate a `Capstone` context for disassembling bytecode for this architecture.
332    #[cfg(feature = "disas")]
333    fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
334        Err(capstone::Error::UnsupportedArch)
335    }
336
337    /// Returns whether this ISA has a native fused-multiply-and-add instruction
338    /// for floats.
339    ///
340    /// Currently this only returns false on x86 when some native features are
341    /// not detected.
342    fn has_native_fma(&self) -> bool;
343}
344
345/// Methods implemented for free for target ISA!
346impl<'a> dyn TargetIsa + 'a {
347    /// Get the default calling convention of this target.
348    pub fn default_call_conv(&self) -> CallConv {
349        CallConv::triple_default(self.triple())
350    }
351
352    /// Get the endianness of this ISA.
353    pub fn endianness(&self) -> ir::Endianness {
354        match self.triple().endianness().unwrap() {
355            target_lexicon::Endianness::Little => ir::Endianness::Little,
356            target_lexicon::Endianness::Big => ir::Endianness::Big,
357        }
358    }
359
360    /// Returns the minimum symbol alignment for this ISA.
361    pub fn symbol_alignment(&self) -> u64 {
362        match self.triple().architecture {
363            // All symbols need to be aligned to at least 2 on s390x.
364            Architecture::S390x => 2,
365            _ => 1,
366        }
367    }
368
369    /// Get the pointer type of this ISA.
370    pub fn pointer_type(&self) -> ir::Type {
371        ir::Type::int(self.pointer_bits() as u16).unwrap()
372    }
373
374    /// Get the width of pointers on this ISA.
375    pub(crate) fn pointer_width(&self) -> PointerWidth {
376        self.triple().pointer_width().unwrap()
377    }
378
379    /// Get the width of pointers on this ISA, in units of bits.
380    pub fn pointer_bits(&self) -> u8 {
381        self.pointer_width().bits()
382    }
383
384    /// Get the width of pointers on this ISA, in units of bytes.
385    pub fn pointer_bytes(&self) -> u8 {
386        self.pointer_width().bytes()
387    }
388
389    /// Get the information needed by frontends producing Cranelift IR.
390    pub fn frontend_config(&self) -> TargetFrontendConfig {
391        TargetFrontendConfig {
392            default_call_conv: self.default_call_conv(),
393            pointer_width: self.pointer_width(),
394        }
395    }
396}
397
398impl Debug for &dyn TargetIsa {
399    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
400        write!(
401            f,
402            "TargetIsa {{ triple: {:?}, pointer_width: {:?}}}",
403            self.triple(),
404            self.pointer_width()
405        )
406    }
407}