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) -> ®alloc2::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}