Skip to main content

lamina_platform/
arch_table.rs

1//! The architecture table: every property of every architecture, stated once.
2//!
3//! One block per architecture, generated by [`arch_table!`] into the
4//! [`TargetArchitecture`] enum, [`TargetArchitecture::spec`], [`TargetArchitecture::all`],
5//! the `Display` spelling and the `FromStr` spellings. Nothing about an architecture is
6//! stated anywhere else, so adding one is one block and adding a property is one field.
7//!
8//! The compiler enforces both halves of that. A block missing a field does not match the
9//! macro's entry rule, so an architecture cannot exist without every property; the
10//! generated `spec` match has no wildcard arm; and `all` and the target list are derived
11//! from the same table, so they cannot fall behind it.
12
13use crate::arch_variant::{
14    Aarch64Level, ArchVariant, Armv7Variant, PowerLevel, RiscvIsa, VariantAxis,
15};
16use crate::cpu_level::X86CpuLevel;
17use crate::environment::TargetEnvironment;
18
19/// Width of a data pointer. Pointer size and alignment derive from it.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub enum PointerWidth {
22    Bits32,
23    Bits64,
24    Bits128,
25}
26
27impl PointerWidth {
28    pub const fn bytes(self) -> usize {
29        match self {
30            Self::Bits32 => 4,
31            Self::Bits64 => 8,
32            Self::Bits128 => 16,
33        }
34    }
35}
36
37/// Byte order of multi-byte values in memory.
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
39pub enum Endianness {
40    Little,
41    Big,
42}
43
44/// What a finished compilation of this target is.
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub enum OutputArtifact {
47    /// Object files that a linker turns into an executable.
48    Executable,
49    /// A self-contained module, assembled but never linked.
50    Module,
51    /// Assembly text handed on as-is.
52    Text,
53}
54
55/// Size and alignment, in bytes, of the `va_list` an architecture's C ABI defines.
56///
57/// A `va_list` is a struct the ABI names field by field, so its size is a property of
58/// the architecture and not of the pointer width. The shapes stated in the table are:
59///
60/// - x86_64: System V AMD64 ABI §3.5.7, `struct { unsigned int gp_offset, fp_offset;
61///   void *overflow_arg_area, *reg_save_area; }` — 24 bytes.
62/// - aarch64: AAPCS64 (IHI 0055) appendix "Variable Argument Lists", `struct { void
63///   *__stack, *__gr_top, *__vr_top; int __gr_offs, __vr_offs; }` — 32 bytes.
64/// - s390x: zSeries ELF ABI supplement, `struct { long __gpr, __fpr; void
65///   *__overflow_arg_area, *__reg_save_area; }` — 32 bytes.
66/// - riscv, powerpc64 ELFv2, loongarch, mips n64, wasm: a plain `void *`, one pointer.
67/// - i686: Intel386 psABI §3.17, `char *` — 4 bytes.
68/// - 32-bit ARM: AAPCS (IHI 0042) §7.1, `struct __va_list { void *__ap; }` — 4 bytes.
69///
70/// [`VaListAbi::Undefined`] is a statement that no ABI defines one, not an omission.
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
72pub enum VaListAbi {
73    Defined { size: u64, alignment: u64 },
74    Undefined,
75}
76
77impl VaListAbi {
78    pub const fn of(size: u64, alignment: u64) -> Self {
79        Self::Defined { size, alignment }
80    }
81}
82
83/// The facts a target-independent lowering needs to turn IR into MIR.
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
85pub struct TargetDataLayout {
86    pub pointer_width: PointerWidth,
87    pub int_register_bits: u32,
88    pub endianness: Endianness,
89    pub va_list: VaListAbi,
90}
91
92impl TargetDataLayout {
93    pub const fn has_64bit_int_registers(self) -> bool {
94        self.int_register_bits >= 64
95    }
96}
97
98/// The ELF interpreter an architecture takes, one path per environment it supports.
99///
100/// `None` is a statement that the combination has no interpreter, not an omission.
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
102pub struct LinuxInterpreters {
103    /// glibc, with the architecture's own floating-point ABI.
104    pub gnu: Option<&'static str>,
105    /// glibc, with the soft-float ABI. Reached by `eabi` and by a RISC-V ISA without `d`.
106    pub gnu_soft_float: Option<&'static str>,
107    /// musl libc.
108    pub musl: Option<&'static str>,
109    /// Lamina's own C library. `None` on every architecture today: no Lamina libc has
110    /// been written, so there is no loader to name. A port fills this in here.
111    pub lamina: Option<&'static str>,
112}
113
114/// Cross-toolchain triples, by C library.
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
116pub struct ToolchainTriples {
117    pub gnu: Option<&'static str>,
118    pub musl: Option<&'static str>,
119    /// Lamina's own toolchain. `None` on every architecture today: nothing outside this
120    /// repository supplies a Lamina-libc cross compiler, and nothing should be guessed.
121    pub lamina: Option<&'static str>,
122}
123
124/// Everything an architecture states about itself.
125///
126/// Read it through [`crate::Target::spec`], which applies the variant's refinements;
127/// [`TargetArchitecture::spec`] is the unrefined form the table states.
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub struct ArchSpec {
130    /// Canonical spelling, the one `Display` writes.
131    pub token: &'static str,
132    /// Further spellings `FromStr` accepts for this architecture.
133    pub spellings: &'static [&'static str],
134    /// Target strings this architecture contributes to the supported-target list.
135    pub targets: &'static [&'static str],
136    pub pointer_width: PointerWidth,
137    /// Widest integer one register holds. Not the pointer width: wasm32 has 32-bit
138    /// pointers and 64-bit integer registers.
139    pub max_int_register_bits: u32,
140    pub endianness: Endianness,
141    /// Size and alignment of this architecture's C `va_list`.
142    pub va_list: VaListAbi,
143    /// Alignment the stack pointer holds at a call. `1` means there is no machine stack.
144    pub stack_alignment_at_call: usize,
145    /// Whether an argument with 16-byte alignment starts at its own alignment rather than
146    /// at the next word. AAPCS64 rounds the integer register counter up to even before
147    /// such an argument; the riscv psABI makes that rule variadic-only and ppc64 does not
148    /// round for named arguments either.
149    pub honors_argument_alignment: bool,
150    pub output_artifact: OutputArtifact,
151    /// Environment a hosted target of this architecture means when the target string
152    /// names none.
153    pub hosted_environment: TargetEnvironment,
154    /// Environments a target string may name for this architecture, beside
155    /// [`TargetEnvironment::Freestanding`], which every architecture accepts.
156    pub environments: &'static [TargetEnvironment],
157    pub interpreters: LinuxInterpreters,
158    pub toolchain: ToolchainTriples,
159    /// Directory name under the Windows SDK `Lib` tree. `None` means Windows has no
160    /// library layout for this architecture, and asking for one is an error rather than
161    /// a search of the x86_64 directories.
162    pub msvc_library_arch: Option<&'static str>,
163    /// The sub-architecture axis this architecture has, and its default.
164    pub variants: VariantAxis,
165}
166
167impl ArchSpec {
168    pub const fn data_layout(&self) -> TargetDataLayout {
169        TargetDataLayout {
170            pointer_width: self.pointer_width,
171            int_register_bits: self.max_int_register_bits,
172            endianness: self.endianness,
173            va_list: self.va_list,
174        }
175    }
176
177    pub const fn has_64bit_int_registers(&self) -> bool {
178        self.max_int_register_bits >= 64
179    }
180
181    /// The ELF interpreter for an environment, or `None` when there is none.
182    pub const fn interpreter(&self, environment: TargetEnvironment) -> Option<&'static str> {
183        match environment {
184            TargetEnvironment::Gnu | TargetEnvironment::Eabihf => self.interpreters.gnu,
185            TargetEnvironment::Eabi => self.interpreters.gnu_soft_float,
186            TargetEnvironment::Musl => self.interpreters.musl,
187            TargetEnvironment::Lamina => self.interpreters.lamina,
188            TargetEnvironment::Freestanding => None,
189        }
190    }
191
192    /// The cross-toolchain triple for an environment.
193    pub const fn toolchain_triple(&self, environment: TargetEnvironment) -> Option<&'static str> {
194        match environment {
195            TargetEnvironment::Gnu | TargetEnvironment::Eabi | TargetEnvironment::Eabihf => {
196                self.toolchain.gnu
197            }
198            TargetEnvironment::Musl => self.toolchain.musl,
199            TargetEnvironment::Lamina => self.toolchain.lamina,
200            TargetEnvironment::Freestanding => self.toolchain.gnu,
201        }
202    }
203
204    /// Whether a target string may name this environment for this architecture.
205    pub fn accepts_environment(&self, environment: TargetEnvironment) -> bool {
206        environment == TargetEnvironment::Freestanding || self.environments.contains(&environment)
207    }
208}
209
210macro_rules! arch_table {
211    ($(
212        $(#[doc = $doc:literal])*
213        $(#[cfg($cfg:meta)])?
214        $variant:ident {
215            token: $token:literal,
216            spellings: [$($spelling:literal),* $(,)?],
217            targets: [$($target:literal),* $(,)?],
218            pointer_width: $pointer_width:ident,
219            max_int_register_bits: $int_bits:literal,
220            endianness: $endianness:ident,
221            va_list: $va_list:expr,
222            stack_alignment_at_call: $stack_align:literal,
223            honors_argument_alignment: $honors:literal,
224            output_artifact: $artifact:ident,
225            hosted_environment: $hosted:ident,
226            environments: [$($environment:ident),* $(,)?],
227            interpreters: {
228                gnu: $i_gnu:expr,
229                gnu_soft_float: $i_soft:expr,
230                musl: $i_musl:expr,
231                lamina: $i_lamina:expr
232            },
233            toolchain: { gnu: $t_gnu:expr, musl: $t_musl:expr, lamina: $t_lamina:expr },
234            msvc_library_arch: $msvc:expr,
235            variants: $axis:expr,
236        }
237    )*) => {
238        /// An architecture lamina has a backend for, or has reserved a name for.
239        ///
240        /// Every property is stated in the table in [`crate::arch_table`]; there are no
241        /// per-property matches anywhere else.
242        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
243        pub enum TargetArchitecture {
244            $(
245                $(#[doc = $doc])*
246                $(#[cfg($cfg)])?
247                $variant,
248            )*
249        }
250
251        impl TargetArchitecture {
252            /// Everything this architecture states about itself.
253            pub const fn spec(self) -> ArchSpec {
254                match self {
255                    $(
256                        $(#[cfg($cfg)])?
257                        Self::$variant => ArchSpec {
258                            token: $token,
259                            spellings: &[$($spelling),*],
260                            targets: &[$($target),*],
261                            pointer_width: PointerWidth::$pointer_width,
262                            max_int_register_bits: $int_bits,
263                            endianness: Endianness::$endianness,
264                            va_list: $va_list,
265                            stack_alignment_at_call: $stack_align,
266                            honors_argument_alignment: $honors,
267                            output_artifact: OutputArtifact::$artifact,
268                            hosted_environment: TargetEnvironment::$hosted,
269                            environments: &[$(TargetEnvironment::$environment),*],
270                            interpreters: LinuxInterpreters {
271                                gnu: $i_gnu,
272                                gnu_soft_float: $i_soft,
273                                musl: $i_musl,
274                                lamina: $i_lamina,
275                            },
276                            toolchain: ToolchainTriples {
277                                gnu: $t_gnu,
278                                musl: $t_musl,
279                                lamina: $t_lamina,
280                            },
281                            msvc_library_arch: $msvc,
282                            variants: $axis,
283                        },
284                    )*
285                }
286            }
287
288            /// Every architecture in the table, in declaration order.
289            pub fn all() -> Vec<Self> {
290                let mut architectures = Vec::new();
291                $(
292                    $(#[cfg($cfg)])?
293                    architectures.push(Self::$variant);
294                )*
295                architectures
296            }
297
298            /// The architecture a bare spelling names, without consulting the refusals.
299            pub(crate) fn from_spelling(spelling: &str) -> Option<Self> {
300                $(
301                    $(#[cfg($cfg)])?
302                    if spelling == $token $(|| spelling == $spelling)* {
303                        return Some(Self::$variant);
304                    }
305                )*
306                None
307            }
308        }
309    };
310}
311
312arch_table! {
313    X86_64 {
314        token: "x86_64",
315        spellings: [],
316        targets: [
317            "x86_64_unknown", "x86_64_linux", "x86_64_windows", "x86_64_macos",
318            "x86_64_android", "x86_64_ios", "x86_64_tvos", "x86_64_watchos",
319            "x86_64_freebsd", "x86_64_orbis", "x86_64_prospero",
320        ],
321        pointer_width: Bits64,
322        max_int_register_bits: 64,
323        endianness: Little,
324        va_list: VaListAbi::of(24, 8),
325        stack_alignment_at_call: 16,
326        honors_argument_alignment: true,
327        output_artifact: Executable,
328        hosted_environment: Gnu,
329        environments: [Gnu, Musl, Lamina],
330        interpreters: {
331            gnu: Some("/lib64/ld-linux-x86-64.so.2"),
332            gnu_soft_float: None,
333            musl: Some("/lib/ld-musl-x86_64.so.1"),
334            lamina: None
335        },
336        toolchain: { gnu: Some("x86_64-linux-gnu"), musl: Some("x86_64-linux-musl"), lamina: None },
337        msvc_library_arch: Some("x64"),
338        variants: VariantAxis::X86(X86CpuLevel::V2),
339    }
340
341    Aarch64 {
342        token: "aarch64",
343        spellings: [],
344        targets: [
345            "aarch64_unknown", "aarch64_macos", "aarch64_linux", "aarch64_windows",
346            "aarch64_android", "aarch64_ios", "aarch64_tvos", "aarch64_watchos",
347            "aarch64_visionos", "aarch64_horizon",
348        ],
349        pointer_width: Bits64,
350        max_int_register_bits: 64,
351        endianness: Little,
352        va_list: VaListAbi::of(32, 8),
353        stack_alignment_at_call: 16,
354        honors_argument_alignment: true,
355        output_artifact: Executable,
356        hosted_environment: Gnu,
357        environments: [Gnu, Musl, Lamina],
358        interpreters: {
359            gnu: Some("/lib/ld-linux-aarch64.so.1"),
360            gnu_soft_float: None,
361            musl: Some("/lib/ld-musl-aarch64.so.1"),
362            lamina: None
363        },
364        toolchain: { gnu: Some("aarch64-linux-gnu"), musl: Some("aarch64-linux-musl"), lamina: None },
365        msvc_library_arch: Some("arm64"),
366        variants: VariantAxis::Aarch64(Aarch64Level::V8_0),
367    }
368
369    #[doc = "ARX64, an experimental architecture with no silicon."]
370    #[cfg(feature = "nightly")]
371    Arx64 {
372        token: "arx64",
373        spellings: [],
374        targets: ["arx64_unknown"],
375        pointer_width: Bits64,
376        max_int_register_bits: 64,
377        endianness: Little,
378        va_list: VaListAbi::Undefined,
379        stack_alignment_at_call: 16,
380        honors_argument_alignment: false,
381        output_artifact: Executable,
382        hosted_environment: Freestanding,
383        environments: [],
384        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
385        toolchain: { gnu: None, musl: None, lamina: None },
386        msvc_library_arch: None,
387        variants: VariantAxis::None,
388    }
389
390    #[doc = "32-bit ARM with no revision, float ABI or profile named. Reserved, and"]
391    #[doc = "refused by `FromStr` in favour of `armv7`, `thumbv6m` and `thumbv7m`."]
392    Arm32 {
393        token: "arm32",
394        spellings: [],
395        targets: [],
396        pointer_width: Bits32,
397        max_int_register_bits: 32,
398        endianness: Little,
399        va_list: VaListAbi::of(4, 4),
400        stack_alignment_at_call: 8,
401        honors_argument_alignment: false,
402        output_artifact: Executable,
403        hosted_environment: Eabi,
404        environments: [Eabi, Eabihf],
405        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
406        toolchain: { gnu: None, musl: None, lamina: None },
407        msvc_library_arch: Some("arm"),
408        variants: VariantAxis::None,
409    }
410
411    Armv7 {
412        token: "armv7",
413        spellings: ["armv7a", "armv7hf"],
414        targets: ["armv7_linux"],
415        pointer_width: Bits32,
416        max_int_register_bits: 32,
417        endianness: Little,
418        va_list: VaListAbi::of(4, 4),
419        stack_alignment_at_call: 16,
420        honors_argument_alignment: false,
421        output_artifact: Executable,
422        hosted_environment: Eabihf,
423        environments: [Eabi, Eabihf],
424        interpreters: {
425            gnu: Some("/lib/ld-linux-armhf.so.3"),
426            gnu_soft_float: Some("/lib/ld-linux.so.3"),
427            musl: None,
428            lamina: None
429        },
430        toolchain: { gnu: Some("arm-linux-gnueabihf"), musl: None, lamina: None },
431        msvc_library_arch: Some("arm"),
432        variants: VariantAxis::Armv7(Armv7Variant::cortex_a7()),
433    }
434
435    #[doc = "ARMv6-M, Thumb-1 only: Cortex-M0 and M0+."]
436    Thumbv6m {
437        token: "thumbv6m",
438        spellings: ["armv6m", "cortex-m0"],
439        targets: ["thumbv6m_unknown", "thumbv6m_linux"],
440        pointer_width: Bits32,
441        max_int_register_bits: 32,
442        endianness: Little,
443        va_list: VaListAbi::of(4, 4),
444        stack_alignment_at_call: 8,
445        honors_argument_alignment: false,
446        output_artifact: Executable,
447        hosted_environment: Eabi,
448        environments: [Eabi],
449        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
450        toolchain: { gnu: None, musl: None, lamina: None },
451        msvc_library_arch: Some("arm"),
452        variants: VariantAxis::None,
453    }
454
455    #[doc = "ARMv7-M, Thumb-2: Cortex-M3, M4 and M7."]
456    Thumbv7m {
457        token: "thumbv7m",
458        spellings: ["armv7m", "cortex-m3"],
459        targets: ["thumbv7m_unknown", "thumbv7m_linux"],
460        pointer_width: Bits32,
461        max_int_register_bits: 32,
462        endianness: Little,
463        va_list: VaListAbi::of(4, 4),
464        stack_alignment_at_call: 8,
465        honors_argument_alignment: false,
466        output_artifact: Executable,
467        hosted_environment: Eabi,
468        environments: [Eabi],
469        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
470        toolchain: { gnu: None, musl: None, lamina: None },
471        msvc_library_arch: Some("arm"),
472        variants: VariantAxis::Armv7(Armv7Variant::cortex_m3()),
473    }
474
475    I686 {
476        token: "i686",
477        spellings: ["i386", "x86"],
478        targets: ["i686_linux"],
479        pointer_width: Bits32,
480        max_int_register_bits: 32,
481        endianness: Little,
482        va_list: VaListAbi::of(4, 4),
483        stack_alignment_at_call: 16,
484        honors_argument_alignment: false,
485        output_artifact: Executable,
486        hosted_environment: Gnu,
487        environments: [Gnu, Musl],
488        interpreters: {
489            gnu: Some("/lib/ld-linux.so.2"),
490            gnu_soft_float: None,
491            musl: Some("/lib/ld-musl-i386.so.1"),
492            lamina: None
493        },
494        toolchain: { gnu: Some("i686-linux-gnu"), musl: Some("i686-linux-musl"), lamina: None },
495        msvc_library_arch: Some("x86"),
496        variants: VariantAxis::None,
497    }
498
499    Riscv32 {
500        token: "riscv32",
501        spellings: [],
502        targets: ["riscv32_unknown", "riscv32_linux"],
503        pointer_width: Bits32,
504        max_int_register_bits: 32,
505        endianness: Little,
506        va_list: VaListAbi::of(4, 4),
507        stack_alignment_at_call: 16,
508        honors_argument_alignment: false,
509        output_artifact: Executable,
510        hosted_environment: Gnu,
511        environments: [Gnu, Musl],
512        interpreters: {
513            gnu: Some("/lib/ld-linux-riscv32-ilp32d.so.1"),
514            gnu_soft_float: Some("/lib/ld-linux-riscv32-ilp32.so.1"),
515            musl: Some("/lib/ld-musl-riscv32.so.1"),
516            lamina: None
517        },
518        toolchain: { gnu: Some("riscv32-linux-gnu"), musl: Some("riscv32-linux-musl"), lamina: None },
519        msvc_library_arch: None,
520        variants: VariantAxis::Riscv(RiscvIsa::general(32)),
521    }
522
523    Riscv64 {
524        token: "riscv64",
525        spellings: ["riscv64gc"],
526        targets: ["riscv64_linux", "riscv64_unknown", "riscv64gc_linux"],
527        pointer_width: Bits64,
528        max_int_register_bits: 64,
529        endianness: Little,
530        va_list: VaListAbi::of(8, 8),
531        stack_alignment_at_call: 16,
532        honors_argument_alignment: false,
533        output_artifact: Executable,
534        hosted_environment: Gnu,
535        environments: [Gnu, Musl],
536        interpreters: {
537            gnu: Some("/lib/ld-linux-riscv64-lp64d.so.1"),
538            gnu_soft_float: Some("/lib/ld-linux-riscv64-lp64.so.1"),
539            musl: Some("/lib/ld-musl-riscv64.so.1"),
540            lamina: None
541        },
542        toolchain: { gnu: Some("riscv64-linux-gnu"), musl: Some("riscv64-linux-musl"), lamina: None },
543        msvc_library_arch: None,
544        variants: VariantAxis::Riscv(RiscvIsa::general(64)),
545    }
546
547    #[cfg(feature = "nightly")]
548    Riscv128 {
549        token: "riscv128",
550        spellings: [],
551        targets: ["riscv128_unknown"],
552        pointer_width: Bits128,
553        max_int_register_bits: 128,
554        endianness: Little,
555        va_list: VaListAbi::Undefined,
556        stack_alignment_at_call: 16,
557        honors_argument_alignment: false,
558        output_artifact: Executable,
559        hosted_environment: Gnu,
560        environments: [Gnu],
561        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
562        toolchain: { gnu: None, musl: None, lamina: None },
563        msvc_library_arch: None,
564        variants: VariantAxis::Riscv(RiscvIsa::general(128)),
565    }
566
567    Wasm32 {
568        token: "wasm32",
569        spellings: ["wasm"],
570        targets: ["wasm32_unknown", "wasm32_wasi"],
571        pointer_width: Bits32,
572        max_int_register_bits: 64,
573        endianness: Little,
574        va_list: VaListAbi::of(4, 4),
575        stack_alignment_at_call: 1,
576        honors_argument_alignment: false,
577        output_artifact: Module,
578        hosted_environment: Freestanding,
579        environments: [],
580        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
581        toolchain: { gnu: None, musl: None, lamina: None },
582        msvc_library_arch: None,
583        variants: VariantAxis::None,
584    }
585
586    Wasm64 {
587        token: "wasm64",
588        spellings: [],
589        targets: ["wasm64_unknown"],
590        pointer_width: Bits64,
591        max_int_register_bits: 64,
592        endianness: Little,
593        va_list: VaListAbi::of(8, 8),
594        stack_alignment_at_call: 1,
595        honors_argument_alignment: false,
596        output_artifact: Module,
597        hosted_environment: Freestanding,
598        environments: [],
599        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
600        toolchain: { gnu: None, musl: None, lamina: None },
601        msvc_library_arch: None,
602        variants: VariantAxis::None,
603    }
604
605    #[doc = "Little-endian 64-bit POWER, ELFv2."]
606    PowerPC64 {
607        token: "ppc64le",
608        spellings: [],
609        targets: ["ppc64le_linux", "ppc64le_unknown"],
610        pointer_width: Bits64,
611        max_int_register_bits: 64,
612        endianness: Little,
613        va_list: VaListAbi::of(8, 8),
614        stack_alignment_at_call: 16,
615        honors_argument_alignment: false,
616        output_artifact: Executable,
617        hosted_environment: Gnu,
618        environments: [Gnu, Musl],
619        interpreters: {
620            gnu: Some("/lib64/ld64.so.2"),
621            gnu_soft_float: None,
622            musl: Some("/lib/ld-musl-powerpc64le.so.1"),
623            lamina: None
624        },
625        toolchain: { gnu: Some("powerpc64le-linux-gnu"), musl: Some("powerpc64le-linux-musl"), lamina: None },
626        msvc_library_arch: None,
627        variants: VariantAxis::Power(PowerLevel::Power8),
628    }
629
630    #[doc = "Big-endian 64-bit POWER, ELFv2."]
631    PowerPC64Be {
632        token: "ppc64",
633        spellings: ["powerpc64"],
634        targets: ["ppc64_linux"],
635        pointer_width: Bits64,
636        max_int_register_bits: 64,
637        endianness: Big,
638        va_list: VaListAbi::of(8, 8),
639        stack_alignment_at_call: 16,
640        honors_argument_alignment: false,
641        output_artifact: Executable,
642        hosted_environment: Gnu,
643        environments: [Gnu, Musl],
644        interpreters: {
645            gnu: Some("/lib64/ld64.so.2"),
646            gnu_soft_float: None,
647            musl: Some("/lib/ld-musl-powerpc64.so.1"),
648            lamina: None
649        },
650        toolchain: { gnu: Some("powerpc64-linux-gnu"), musl: Some("powerpc64-linux-musl"), lamina: None },
651        msvc_library_arch: None,
652        variants: VariantAxis::Power(PowerLevel::Power8),
653    }
654
655    Mips64 {
656        token: "mips64",
657        spellings: [],
658        targets: ["mips64_linux"],
659        pointer_width: Bits64,
660        max_int_register_bits: 64,
661        endianness: Big,
662        va_list: VaListAbi::of(8, 8),
663        stack_alignment_at_call: 16,
664        honors_argument_alignment: false,
665        output_artifact: Executable,
666        hosted_environment: Gnu,
667        environments: [Gnu, Musl],
668        interpreters: {
669            gnu: Some("/lib64/ld.so.1"),
670            gnu_soft_float: None,
671            musl: Some("/lib/ld-musl-mips64.so.1"),
672            lamina: None
673        },
674        toolchain: { gnu: Some("mips64-linux-gnuabi64"), musl: Some("mips64-linux-musl"), lamina: None },
675        msvc_library_arch: None,
676        variants: VariantAxis::None,
677    }
678
679    Mips64El {
680        token: "mips64el",
681        spellings: ["mips64le"],
682        targets: ["mips64el_linux"],
683        pointer_width: Bits64,
684        max_int_register_bits: 64,
685        endianness: Little,
686        va_list: VaListAbi::of(8, 8),
687        stack_alignment_at_call: 16,
688        honors_argument_alignment: false,
689        output_artifact: Executable,
690        hosted_environment: Gnu,
691        environments: [Gnu, Musl],
692        interpreters: {
693            gnu: Some("/lib64/ld.so.1"),
694            gnu_soft_float: None,
695            musl: Some("/lib/ld-musl-mips64el.so.1"),
696            lamina: None
697        },
698        toolchain: { gnu: Some("mips64el-linux-gnuabi64"), musl: Some("mips64el-linux-musl"), lamina: None },
699        msvc_library_arch: None,
700        variants: VariantAxis::None,
701    }
702
703    LoongArch64 {
704        token: "loongarch64",
705        spellings: ["loong64"],
706        targets: ["loongarch64_linux"],
707        pointer_width: Bits64,
708        max_int_register_bits: 64,
709        endianness: Little,
710        va_list: VaListAbi::of(8, 8),
711        stack_alignment_at_call: 16,
712        honors_argument_alignment: false,
713        output_artifact: Executable,
714        hosted_environment: Gnu,
715        environments: [Gnu, Musl],
716        interpreters: {
717            gnu: Some("/lib64/ld-linux-loongarch-lp64d.so.1"),
718            gnu_soft_float: None,
719            musl: Some("/lib/ld-musl-loongarch64.so.1"),
720            lamina: None
721        },
722        toolchain: { gnu: Some("loongarch64-linux-gnu"), musl: Some("loongarch64-linux-musl"), lamina: None },
723        msvc_library_arch: None,
724        variants: VariantAxis::None,
725    }
726
727    S390x {
728        token: "s390x",
729        spellings: ["systemz"],
730        targets: ["s390x_linux"],
731        pointer_width: Bits64,
732        max_int_register_bits: 64,
733        endianness: Big,
734        va_list: VaListAbi::of(32, 8),
735        stack_alignment_at_call: 8,
736        honors_argument_alignment: false,
737        output_artifact: Executable,
738        hosted_environment: Gnu,
739        environments: [Gnu, Musl],
740        interpreters: {
741            gnu: Some("/lib/ld64.so.1"),
742            gnu_soft_float: None,
743            musl: Some("/lib/ld-musl-s390x.so.1"),
744            lamina: None
745        },
746        toolchain: { gnu: Some("s390x-linux-gnu"), musl: Some("s390x-linux-musl"), lamina: None },
747        msvc_library_arch: None,
748        variants: VariantAxis::None,
749    }
750
751    Nvptx64 {
752        token: "nvptx64",
753        spellings: [],
754        targets: ["nvptx64_cuda"],
755        pointer_width: Bits64,
756        max_int_register_bits: 64,
757        endianness: Little,
758        va_list: VaListAbi::Undefined,
759        stack_alignment_at_call: 1,
760        honors_argument_alignment: false,
761        output_artifact: Text,
762        hosted_environment: Freestanding,
763        environments: [],
764        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
765        toolchain: { gnu: None, musl: None, lamina: None },
766        msvc_library_arch: None,
767        variants: VariantAxis::None,
768    }
769
770    Amdgcn {
771        token: "amdgcn",
772        spellings: [],
773        targets: ["amdgcn_amdhsa"],
774        pointer_width: Bits64,
775        max_int_register_bits: 64,
776        endianness: Little,
777        va_list: VaListAbi::Undefined,
778        stack_alignment_at_call: 1,
779        honors_argument_alignment: false,
780        output_artifact: Text,
781        hosted_environment: Freestanding,
782        environments: [],
783        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
784        toolchain: { gnu: None, musl: None, lamina: None },
785        msvc_library_arch: None,
786        variants: VariantAxis::None,
787    }
788
789    #[cfg(feature = "nightly")]
790    Lisa {
791        token: "lisa",
792        spellings: [],
793        targets: [],
794        pointer_width: Bits64,
795        max_int_register_bits: 64,
796        endianness: Little,
797        va_list: VaListAbi::Undefined,
798        stack_alignment_at_call: 16,
799        honors_argument_alignment: false,
800        output_artifact: Executable,
801        hosted_environment: Freestanding,
802        environments: [],
803        interpreters: { gnu: None, gnu_soft_float: None, musl: None, lamina: None },
804        toolchain: { gnu: None, musl: None, lamina: None },
805        msvc_library_arch: None,
806        variants: VariantAxis::None,
807    }
808}
809
810/// Spellings that name a real machine lamina has decided not to implement, each with the
811/// reason and the spelling to use instead. Consulted before the architecture spellings,
812/// so a refused name never resolves to an architecture.
813pub(crate) const REFUSED_SPELLINGS: &[(&str, &str)] = &[
814    (
815        "arm32",
816        "Architecture 'arm32' is not implemented\n  Hint: 'arm32' names no ARM revision, floating-point ABI or profile, so there is no machine to generate code for. The implemented 32-bit ARM target is armv7, AAPCS with VFP hard float: write 'armv7' (e.g. armv7_linux), or 'thumbv6m'/'thumbv7m' for Cortex-M",
817    ),
818    (
819        "ppc64-elfv1",
820        "Architecture 'ppc64-elfv1' is not supported\n  Hint: big-endian POWER here is ELFv2. ELFv1 calls through .opd function descriptors and is a different ABI. Write 'ppc64' (e.g. ppc64_linux)",
821    ),
822    (
823        "powerpc64-elfv1",
824        "Architecture 'ppc64-elfv1' is not supported\n  Hint: big-endian POWER here is ELFv2. ELFv1 calls through .opd function descriptors and is a different ABI. Write 'ppc64' (e.g. ppc64_linux)",
825    ),
826    (
827        "mips",
828        "Architecture 'mips' is not supported\n  Hint: lamina implements the N64 ABI on 64-bit MIPS only, not O32. Write 'mips64' or 'mips64el' (e.g. mips64_linux)",
829    ),
830    (
831        "mipsel",
832        "Architecture 'mips' is not supported\n  Hint: lamina implements the N64 ABI on 64-bit MIPS only, not O32. Write 'mips64' or 'mips64el' (e.g. mips64_linux)",
833    ),
834    (
835        "mips32",
836        "Architecture 'mips' is not supported\n  Hint: lamina implements the N64 ABI on 64-bit MIPS only, not O32. Write 'mips64' or 'mips64el' (e.g. mips64_linux)",
837    ),
838    (
839        "mips32el",
840        "Architecture 'mips' is not supported\n  Hint: lamina implements the N64 ABI on 64-bit MIPS only, not O32. Write 'mips64' or 'mips64el' (e.g. mips64_linux)",
841    ),
842    (
843        "s390",
844        "Architecture 's390' was not added\n  Hint: lamina supports 64-bit z/Architecture only. Write 's390x' (e.g. s390x_linux)",
845    ),
846];
847
848/// Shorthands for the fields of [`TargetArchitecture::spec`].
849///
850/// Each one reads the table; none of them is a second place a property is decided. A
851/// target that carries a variant should read [`crate::Target::spec`] instead, which
852/// applies the variant's refinements.
853impl TargetArchitecture {
854    pub const fn pointer_width(self) -> PointerWidth {
855        self.spec().pointer_width
856    }
857
858    pub const fn max_int_register_bits(self) -> u32 {
859        self.spec().max_int_register_bits
860    }
861
862    pub const fn has_64bit_int_registers(self) -> bool {
863        self.spec().has_64bit_int_registers()
864    }
865
866    pub const fn endianness(self) -> Endianness {
867        self.spec().endianness
868    }
869
870    pub const fn va_list(self) -> VaListAbi {
871        self.spec().va_list
872    }
873
874    pub const fn stack_alignment_at_call(self) -> usize {
875        self.spec().stack_alignment_at_call
876    }
877
878    pub const fn honors_argument_alignment(self) -> bool {
879        self.spec().honors_argument_alignment
880    }
881
882    pub const fn output_artifact(self) -> OutputArtifact {
883        self.spec().output_artifact
884    }
885
886    pub const fn data_layout(self) -> TargetDataLayout {
887        self.spec().data_layout()
888    }
889
890    pub const fn default_variant(self) -> ArchVariant {
891        self.spec().variants.default_variant()
892    }
893}