#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Endianness {
Little,
Big,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ArchConfig {
pub name: &'static str,
pub pointer_size: usize,
pub cache_line_size: usize,
pub max_align: usize,
pub endianness: Endianness,
}
pub const X86_64_SYSV: ArchConfig = ArchConfig {
name: "x86_64",
pointer_size: 8,
cache_line_size: 64,
max_align: 16,
endianness: Endianness::Little,
};
pub const AARCH64: ArchConfig = ArchConfig {
name: "aarch64",
pointer_size: 8,
cache_line_size: 64,
max_align: 16,
endianness: Endianness::Little,
};
pub const AARCH64_APPLE: ArchConfig = ArchConfig {
name: "aarch64-apple",
pointer_size: 8,
cache_line_size: 128,
max_align: 16,
endianness: Endianness::Little,
};
pub const WASM32: ArchConfig = ArchConfig {
name: "wasm32",
pointer_size: 4,
cache_line_size: 64,
max_align: 8,
endianness: Endianness::Little,
};
pub const RISCV64: ArchConfig = ArchConfig {
name: "riscv64",
pointer_size: 8,
cache_line_size: 64,
max_align: 16,
endianness: Endianness::Little,
};
pub const CORTEX_M: ArchConfig = ArchConfig {
name: "cortex_m",
pointer_size: 4,
cache_line_size: 0,
max_align: 8,
endianness: Endianness::Little,
};
pub const CORTEX_M4: ArchConfig = ArchConfig {
name: "cortex_m4",
pointer_size: 4,
cache_line_size: 32,
max_align: 8,
endianness: Endianness::Little,
};
pub const AVR: ArchConfig = ArchConfig {
name: "avr",
pointer_size: 2,
cache_line_size: 0,
max_align: 1,
endianness: Endianness::Little,
};
pub fn with_overrides(
base: &ArchConfig,
cache_line_size: Option<usize>,
word_size: Option<usize>,
) -> &'static ArchConfig {
let ptr = word_size.unwrap_or(base.pointer_size);
let max_align = if word_size.is_some() {
if ptr <= 4 { 8 } else { base.max_align }
} else {
base.max_align
};
Box::leak(Box::new(ArchConfig {
name: "custom",
pointer_size: ptr,
cache_line_size: cache_line_size.unwrap_or(base.cache_line_size),
max_align,
endianness: base.endianness,
}))
}
pub fn arch_by_name(name: &str) -> Option<&'static ArchConfig> {
match name {
"x86_64" => Some(&X86_64_SYSV),
"aarch64" => Some(&AARCH64),
"aarch64_apple" => Some(&AARCH64_APPLE),
"wasm32" => Some(&WASM32),
"riscv64" => Some(&RISCV64),
"cortex_m" => Some(&CORTEX_M),
"cortex_m4" => Some(&CORTEX_M4),
"avr" => Some(&AVR),
_ => arch_by_triple(name),
}
}
pub fn arch_by_triple(triple: &str) -> Option<&'static ArchConfig> {
if triple.starts_with("x86_64-") {
Some(&X86_64_SYSV)
} else if triple.starts_with("aarch64-apple-") {
Some(&AARCH64_APPLE)
} else if triple.starts_with("aarch64-") {
Some(&AARCH64)
} else if triple.starts_with("wasm32-") {
Some(&WASM32)
} else if triple.starts_with("riscv64") {
Some(&RISCV64)
} else if triple.starts_with("thumbv6m-")
|| triple.starts_with("thumbv7m-")
|| triple.starts_with("thumbv8m.base-")
{
Some(&CORTEX_M)
} else if triple.starts_with("thumbv7em-") || triple.starts_with("thumbv8m.main-") {
Some(&CORTEX_M4)
} else if triple.starts_with("avr-") {
Some(&AVR)
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn short_names_resolve() {
assert_eq!(arch_by_name("x86_64"), Some(&X86_64_SYSV));
assert_eq!(arch_by_name("aarch64"), Some(&AARCH64));
assert_eq!(arch_by_name("aarch64_apple"), Some(&AARCH64_APPLE));
assert_eq!(arch_by_name("wasm32"), Some(&WASM32));
assert_eq!(arch_by_name("riscv64"), Some(&RISCV64));
}
#[test]
fn target_triples_resolve() {
assert_eq!(arch_by_name("x86_64-unknown-linux-gnu"), Some(&X86_64_SYSV));
assert_eq!(arch_by_name("x86_64-pc-windows-msvc"), Some(&X86_64_SYSV));
assert_eq!(arch_by_name("aarch64-unknown-linux-gnu"), Some(&AARCH64));
assert_eq!(arch_by_name("aarch64-linux-android"), Some(&AARCH64));
assert_eq!(arch_by_name("aarch64-apple-darwin"), Some(&AARCH64_APPLE));
assert_eq!(arch_by_name("aarch64-apple-ios"), Some(&AARCH64_APPLE));
assert_eq!(arch_by_name("wasm32-unknown-unknown"), Some(&WASM32));
assert_eq!(arch_by_name("riscv64gc-unknown-linux-gnu"), Some(&RISCV64));
}
#[test]
fn unknown_triple_returns_none() {
assert_eq!(arch_by_name("mips-unknown-linux-gnu"), None);
assert_eq!(arch_by_name("totally-bogus"), None);
}
#[test]
fn apple_aarch64_has_128_byte_cache_line() {
let cfg = arch_by_name("aarch64-apple-darwin").unwrap();
assert_eq!(cfg.cache_line_size, 128);
}
#[test]
fn cortex_m_short_names() {
assert_eq!(arch_by_name("cortex_m"), Some(&CORTEX_M));
assert_eq!(arch_by_name("cortex_m4"), Some(&CORTEX_M4));
assert_eq!(arch_by_name("avr"), Some(&AVR));
}
#[test]
fn cortex_m_no_cache_variants() {
assert_eq!(arch_by_name("thumbv6m-none-eabi"), Some(&CORTEX_M));
assert_eq!(
arch_by_name("thumbv6m-none-eabi").unwrap().cache_line_size,
0
);
assert_eq!(arch_by_name("thumbv7m-none-eabi"), Some(&CORTEX_M));
assert_eq!(arch_by_name("thumbv8m.base-none-eabi"), Some(&CORTEX_M));
}
#[test]
fn cortex_m4_cached_variants() {
assert_eq!(arch_by_name("thumbv7em-none-eabi"), Some(&CORTEX_M4));
assert_eq!(arch_by_name("thumbv7em-none-eabihf"), Some(&CORTEX_M4));
assert_eq!(
arch_by_name("thumbv7em-none-eabi").unwrap().cache_line_size,
32
);
assert_eq!(arch_by_name("thumbv8m.main-none-eabi"), Some(&CORTEX_M4));
assert_eq!(arch_by_name("thumbv8m.main-none-eabihf"), Some(&CORTEX_M4));
}
#[test]
fn avr_triple() {
assert_eq!(arch_by_name("avr-unknown-gnu-atmega328p"), Some(&AVR));
assert_eq!(arch_by_name("avr").unwrap().pointer_size, 2);
assert_eq!(arch_by_name("avr").unwrap().cache_line_size, 0);
}
#[test]
fn cortex_m_has_4_byte_pointers() {
assert_eq!(CORTEX_M.pointer_size, 4);
assert_eq!(CORTEX_M4.pointer_size, 4);
}
}