| 1 | // This file defines the `Triple` type and support code shared by all targets. |
| 2 | |
| 3 | use crate::data_model::CDataModel; |
| 4 | use crate::parse_error::ParseError; |
| 5 | use crate::targets::{ |
| 6 | default_binary_format, Architecture, ArmArchitecture, BinaryFormat, Environment, |
| 7 | OperatingSystem, Riscv32Architecture, Vendor, |
| 8 | }; |
| 9 | #[cfg (not(feature = "std" ))] |
| 10 | use alloc::borrow::ToOwned; |
| 11 | use core::fmt; |
| 12 | use core::str::FromStr; |
| 13 | |
| 14 | /// The target memory endianness. |
| 15 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Hash)] |
| 16 | #[allow (missing_docs)] |
| 17 | pub enum Endianness { |
| 18 | Little, |
| 19 | Big, |
| 20 | } |
| 21 | |
| 22 | /// The width of a pointer (in the default address space). |
| 23 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Hash)] |
| 24 | #[allow (missing_docs)] |
| 25 | pub enum PointerWidth { |
| 26 | U16, |
| 27 | U32, |
| 28 | U64, |
| 29 | } |
| 30 | |
| 31 | impl PointerWidth { |
| 32 | /// Return the number of bits in a pointer. |
| 33 | pub fn bits(self) -> u8 { |
| 34 | match self { |
| 35 | PointerWidth::U16 => 16, |
| 36 | PointerWidth::U32 => 32, |
| 37 | PointerWidth::U64 => 64, |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | /// Return the number of bytes in a pointer. |
| 42 | /// |
| 43 | /// For these purposes, there are 8 bits in a byte. |
| 44 | pub fn bytes(self) -> u8 { |
| 45 | match self { |
| 46 | PointerWidth::U16 => 2, |
| 47 | PointerWidth::U32 => 4, |
| 48 | PointerWidth::U64 => 8, |
| 49 | } |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | /// The calling convention, which specifies things like which registers are |
| 54 | /// used for passing arguments, which registers are callee-saved, and so on. |
| 55 | #[cfg_attr (feature = "rust_1_40" , non_exhaustive)] |
| 56 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Hash)] |
| 57 | pub enum CallingConvention { |
| 58 | /// "System V", which is used on most Unix-like platfoms. Note that the |
| 59 | /// specific conventions vary between hardware architectures; for example, |
| 60 | /// x86-32's "System V" is entirely different from x86-64's "System V". |
| 61 | SystemV, |
| 62 | |
| 63 | /// The WebAssembly C ABI. |
| 64 | /// https://github.com/WebAssembly/tool-conventions/blob/master/BasicCABI.md |
| 65 | WasmBasicCAbi, |
| 66 | |
| 67 | /// "Windows Fastcall", which is used on Windows. Note that like "System V", |
| 68 | /// this varies between hardware architectures. On x86-32 it describes what |
| 69 | /// Windows documentation calls "fastcall", and on x86-64 it describes what |
| 70 | /// Windows documentation often just calls the Windows x64 calling convention |
| 71 | /// (though the compiler still recognizes "fastcall" as an alias for it). |
| 72 | WindowsFastcall, |
| 73 | |
| 74 | /// Apple Aarch64 platforms use their own variant of the common Aarch64 |
| 75 | /// calling convention. |
| 76 | /// |
| 77 | /// <https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms> |
| 78 | AppleAarch64, |
| 79 | } |
| 80 | |
| 81 | /// An LLVM target "triple". Historically such things had three fields, though |
| 82 | /// they've added additional fields over time. |
| 83 | /// |
| 84 | /// Note that `Triple` doesn't implement `Default` itself. If you want a type |
| 85 | /// which defaults to the host triple, or defaults to unknown-unknown-unknown, |
| 86 | /// use `DefaultToHost` or `DefaultToUnknown`, respectively. |
| 87 | #[derive (Clone, Debug, PartialEq, Eq, Hash)] |
| 88 | pub struct Triple { |
| 89 | /// The "architecture" (and sometimes the subarchitecture). |
| 90 | pub architecture: Architecture, |
| 91 | /// The "vendor" (whatever that means). |
| 92 | pub vendor: Vendor, |
| 93 | /// The "operating system" (sometimes also the environment). |
| 94 | pub operating_system: OperatingSystem, |
| 95 | /// The "environment" on top of the operating system (often omitted for |
| 96 | /// operating systems with a single predominant environment). |
| 97 | pub environment: Environment, |
| 98 | /// The "binary format" (rarely used). |
| 99 | pub binary_format: BinaryFormat, |
| 100 | } |
| 101 | |
| 102 | impl Triple { |
| 103 | /// Return the endianness of this target's architecture. |
| 104 | pub fn endianness(&self) -> Result<Endianness, ()> { |
| 105 | self.architecture.endianness() |
| 106 | } |
| 107 | |
| 108 | /// Return the pointer width of this target's architecture. |
| 109 | /// |
| 110 | /// This function is aware of x32 and ilp32 ABIs on 64-bit architectures. |
| 111 | pub fn pointer_width(&self) -> Result<PointerWidth, ()> { |
| 112 | // Some ABIs have a different pointer width than the CPU architecture. |
| 113 | match self.environment { |
| 114 | Environment::Gnux32 | Environment::GnuIlp32 => return Ok(PointerWidth::U32), |
| 115 | _ => {} |
| 116 | } |
| 117 | |
| 118 | self.architecture.pointer_width() |
| 119 | } |
| 120 | |
| 121 | /// Return the default calling convention for the given target triple. |
| 122 | pub fn default_calling_convention(&self) -> Result<CallingConvention, ()> { |
| 123 | Ok(match self.operating_system { |
| 124 | os if os.is_like_darwin() => match self.architecture { |
| 125 | Architecture::Aarch64(_) => CallingConvention::AppleAarch64, |
| 126 | _ => CallingConvention::SystemV, |
| 127 | }, |
| 128 | OperatingSystem::Aix |
| 129 | | OperatingSystem::Bitrig |
| 130 | | OperatingSystem::Cloudabi |
| 131 | | OperatingSystem::Dragonfly |
| 132 | | OperatingSystem::Freebsd |
| 133 | | OperatingSystem::Fuchsia |
| 134 | | OperatingSystem::Haiku |
| 135 | | OperatingSystem::Hermit |
| 136 | | OperatingSystem::Hurd |
| 137 | | OperatingSystem::L4re |
| 138 | | OperatingSystem::Linux |
| 139 | | OperatingSystem::Netbsd |
| 140 | | OperatingSystem::Openbsd |
| 141 | | OperatingSystem::Redox |
| 142 | | OperatingSystem::Solaris => CallingConvention::SystemV, |
| 143 | OperatingSystem::Windows => CallingConvention::WindowsFastcall, |
| 144 | OperatingSystem::Nebulet |
| 145 | | OperatingSystem::Emscripten |
| 146 | | OperatingSystem::Wasi |
| 147 | | OperatingSystem::Unknown => match self.architecture { |
| 148 | Architecture::Wasm32 => CallingConvention::WasmBasicCAbi, |
| 149 | _ => return Err(()), |
| 150 | }, |
| 151 | _ => return Err(()), |
| 152 | }) |
| 153 | } |
| 154 | |
| 155 | /// The C data model for a given target. If the model is not known, returns `Err(())`. |
| 156 | pub fn data_model(&self) -> Result<CDataModel, ()> { |
| 157 | match self.pointer_width()? { |
| 158 | PointerWidth::U64 => { |
| 159 | if self.operating_system == OperatingSystem::Windows { |
| 160 | Ok(CDataModel::LLP64) |
| 161 | } else if self.default_calling_convention() == Ok(CallingConvention::SystemV) |
| 162 | || self.architecture == Architecture::Wasm64 |
| 163 | || self.default_calling_convention() == Ok(CallingConvention::AppleAarch64) |
| 164 | { |
| 165 | Ok(CDataModel::LP64) |
| 166 | } else { |
| 167 | Err(()) |
| 168 | } |
| 169 | } |
| 170 | PointerWidth::U32 => { |
| 171 | if self.operating_system == OperatingSystem::Windows |
| 172 | || self.default_calling_convention() == Ok(CallingConvention::SystemV) |
| 173 | || self.architecture == Architecture::Wasm32 |
| 174 | { |
| 175 | Ok(CDataModel::ILP32) |
| 176 | } else { |
| 177 | Err(()) |
| 178 | } |
| 179 | } |
| 180 | // TODO: on 16-bit machines there is usually a distinction |
| 181 | // between near-pointers and far-pointers. |
| 182 | // Additionally, code pointers sometimes have a different size than data pointers. |
| 183 | // We don't handle this case. |
| 184 | PointerWidth::U16 => Err(()), |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | /// Return a `Triple` with all unknown fields. |
| 189 | pub fn unknown() -> Self { |
| 190 | Self { |
| 191 | architecture: Architecture::Unknown, |
| 192 | vendor: Vendor::Unknown, |
| 193 | operating_system: OperatingSystem::Unknown, |
| 194 | environment: Environment::Unknown, |
| 195 | binary_format: BinaryFormat::Unknown, |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | impl fmt::Display for Triple { |
| 201 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 202 | if let Some(res) = self.special_case_display(f) { |
| 203 | return res; |
| 204 | } |
| 205 | |
| 206 | let implied_binary_format = default_binary_format(&self); |
| 207 | |
| 208 | write!(f, " {}" , self.architecture)?; |
| 209 | if self.vendor == Vendor::Unknown |
| 210 | && (self.environment != Environment::HermitKernel |
| 211 | && self.environment != Environment::LinuxKernel) |
| 212 | && ((self.operating_system == OperatingSystem::Linux |
| 213 | && (self.environment == Environment::Android |
| 214 | || self.environment == Environment::Androideabi |
| 215 | || self.environment == Environment::Kernel)) |
| 216 | || self.operating_system == OperatingSystem::Wasi |
| 217 | || self.operating_system == OperatingSystem::WasiP1 |
| 218 | || self.operating_system == OperatingSystem::WasiP2 |
| 219 | || (self.operating_system == OperatingSystem::None_ |
| 220 | && (self.architecture == Architecture::Arm(ArmArchitecture::Armv4t) |
| 221 | || self.architecture == Architecture::Arm(ArmArchitecture::Armv5te) |
| 222 | || self.architecture == Architecture::Arm(ArmArchitecture::Armebv7r) |
| 223 | || self.architecture == Architecture::Arm(ArmArchitecture::Armv7a) |
| 224 | || self.architecture == Architecture::Arm(ArmArchitecture::Armv7r) |
| 225 | || self.architecture == Architecture::Arm(ArmArchitecture::Armv8r) |
| 226 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv4t) |
| 227 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv5te) |
| 228 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv6m) |
| 229 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7em) |
| 230 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7m) |
| 231 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mBase) |
| 232 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mMain) |
| 233 | || self.architecture == Architecture::Msp430))) |
| 234 | { |
| 235 | // As a special case, omit the vendor for Android, Wasi, and sometimes |
| 236 | // None_, depending on the hardware architecture. This logic is entirely |
| 237 | // ad-hoc, and is just sufficient to handle the current set of recognized |
| 238 | // triples. |
| 239 | write!(f, "- {}" , self.operating_system)?; |
| 240 | } else if self.architecture.is_clever() && self.operating_system == OperatingSystem::Unknown |
| 241 | { |
| 242 | write!(f, "- {}" , self.vendor)?; |
| 243 | } else { |
| 244 | write!(f, "- {}- {}" , self.vendor, self.operating_system)?; |
| 245 | } |
| 246 | |
| 247 | match (&self.vendor, self.operating_system, self.environment) { |
| 248 | (Vendor::Nintendo, OperatingSystem::Horizon, Environment::Newlib) |
| 249 | | (Vendor::Espressif, OperatingSystem::Espidf, Environment::Newlib) => { |
| 250 | // The triple representations of these platforms don't have an environment field. |
| 251 | } |
| 252 | (_, _, Environment::Unknown) => { |
| 253 | // Don't print out the environment if it is unknown. |
| 254 | } |
| 255 | _ => { |
| 256 | write!(f, "- {}" , self.environment)?; |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | if self.binary_format != implied_binary_format || show_binary_format_with_no_os(self) { |
| 261 | // As a special case, omit a non-default binary format for some |
| 262 | // targets which happen to exclude it. |
| 263 | write!(f, "- {}" , self.binary_format)?; |
| 264 | } |
| 265 | Ok(()) |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | fn show_binary_format_with_no_os(triple: &Triple) -> bool { |
| 270 | if triple.binary_format == BinaryFormat::Unknown { |
| 271 | return false; |
| 272 | } |
| 273 | |
| 274 | #[cfg (feature = "arch_zkasm" )] |
| 275 | { |
| 276 | if triple.architecture == Architecture::ZkAsm { |
| 277 | return false; |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | triple.environment != Environment::Eabi |
| 282 | && triple.environment != Environment::Eabihf |
| 283 | && triple.environment != Environment::Sgx |
| 284 | && triple.architecture != Architecture::Avr |
| 285 | && triple.architecture != Architecture::Wasm32 |
| 286 | && triple.architecture != Architecture::Wasm64 |
| 287 | && (triple.operating_system == OperatingSystem::None_ |
| 288 | || triple.operating_system == OperatingSystem::Unknown) |
| 289 | } |
| 290 | |
| 291 | impl FromStr for Triple { |
| 292 | type Err = ParseError; |
| 293 | |
| 294 | /// Parse a triple from an LLVM target triple. |
| 295 | /// |
| 296 | /// This may also be able to parse `rustc` target triples, though support |
| 297 | /// for that is secondary. |
| 298 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 299 | if let Some(triple) = Triple::special_case_from_str(s) { |
| 300 | return Ok(triple); |
| 301 | } |
| 302 | |
| 303 | let mut parts = s.split('-' ); |
| 304 | let mut result = Self::unknown(); |
| 305 | let mut current_part; |
| 306 | |
| 307 | current_part = parts.next(); |
| 308 | if let Some(s) = current_part { |
| 309 | if let Ok(architecture) = Architecture::from_str(s) { |
| 310 | result.architecture = architecture; |
| 311 | current_part = parts.next(); |
| 312 | } else { |
| 313 | // Insist that the triple start with a valid architecture. |
| 314 | return Err(ParseError::UnrecognizedArchitecture(s.to_owned())); |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | let mut has_vendor = false; |
| 319 | let mut has_operating_system = false; |
| 320 | if let Some(s) = current_part { |
| 321 | if let Ok(vendor) = Vendor::from_str(s) { |
| 322 | has_vendor = true; |
| 323 | result.vendor = vendor; |
| 324 | current_part = parts.next(); |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | if !has_operating_system { |
| 329 | if let Some(s) = current_part { |
| 330 | if let Ok(operating_system) = OperatingSystem::from_str(s) { |
| 331 | has_operating_system = true; |
| 332 | result.operating_system = operating_system; |
| 333 | current_part = parts.next(); |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | let mut has_environment = false; |
| 339 | |
| 340 | if !has_environment { |
| 341 | if let Some(s) = current_part { |
| 342 | if let Ok(environment) = Environment::from_str(s) { |
| 343 | has_environment = true; |
| 344 | result.environment = environment; |
| 345 | current_part = parts.next(); |
| 346 | } |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | let mut has_binary_format = false; |
| 351 | if let Some(s) = current_part { |
| 352 | if let Ok(binary_format) = BinaryFormat::from_str(s) { |
| 353 | has_binary_format = true; |
| 354 | result.binary_format = binary_format; |
| 355 | current_part = parts.next(); |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | // The binary format is frequently omitted; if that's the case here, |
| 360 | // infer it from the other fields. |
| 361 | if !has_binary_format { |
| 362 | result.binary_format = default_binary_format(&result); |
| 363 | } |
| 364 | |
| 365 | if let Some(s) = current_part { |
| 366 | Err( |
| 367 | if !has_vendor && !has_operating_system && !has_environment && !has_binary_format { |
| 368 | ParseError::UnrecognizedVendor(s.to_owned()) |
| 369 | } else if !has_operating_system && !has_environment && !has_binary_format { |
| 370 | ParseError::UnrecognizedOperatingSystem(s.to_owned()) |
| 371 | } else if !has_environment && !has_binary_format { |
| 372 | ParseError::UnrecognizedEnvironment(s.to_owned()) |
| 373 | } else if !has_binary_format { |
| 374 | ParseError::UnrecognizedBinaryFormat(s.to_owned()) |
| 375 | } else { |
| 376 | ParseError::UnrecognizedField(s.to_owned()) |
| 377 | }, |
| 378 | ) |
| 379 | } else { |
| 380 | Ok(result) |
| 381 | } |
| 382 | } |
| 383 | } |
| 384 | |
| 385 | impl Triple { |
| 386 | /// Handle special cases in the `Display` implementation. |
| 387 | fn special_case_display(&self, f: &mut fmt::Formatter) -> Option<fmt::Result> { |
| 388 | let res = match self { |
| 389 | Triple { |
| 390 | architecture: Architecture::Arm(ArmArchitecture::Armv6k), |
| 391 | vendor: Vendor::Nintendo, |
| 392 | operating_system: OperatingSystem::Horizon, |
| 393 | .. |
| 394 | } => write!(f, " {}- {}-3ds" , self.architecture, self.vendor), |
| 395 | Triple { |
| 396 | architecture: Architecture::Riscv32(Riscv32Architecture::Riscv32imc), |
| 397 | vendor: Vendor::Espressif, |
| 398 | operating_system: OperatingSystem::Espidf, |
| 399 | .. |
| 400 | } => write!(f, " {}-esp- {}" , self.architecture, self.operating_system), |
| 401 | _ => return None, |
| 402 | }; |
| 403 | Some(res) |
| 404 | } |
| 405 | |
| 406 | /// Handle special cases in the `FromStr` implementation. |
| 407 | fn special_case_from_str(s: &str) -> Option<Self> { |
| 408 | let mut triple = Triple::unknown(); |
| 409 | |
| 410 | match s { |
| 411 | "armv6k-nintendo-3ds" => { |
| 412 | triple.architecture = Architecture::Arm(ArmArchitecture::Armv6k); |
| 413 | triple.vendor = Vendor::Nintendo; |
| 414 | triple.operating_system = OperatingSystem::Horizon; |
| 415 | triple.environment = Environment::Newlib; |
| 416 | triple.binary_format = default_binary_format(&triple); |
| 417 | } |
| 418 | "riscv32imc-esp-espidf" => { |
| 419 | triple.architecture = Architecture::Riscv32(Riscv32Architecture::Riscv32imc); |
| 420 | triple.vendor = Vendor::Espressif; |
| 421 | triple.operating_system = OperatingSystem::Espidf; |
| 422 | triple.environment = Environment::Newlib; |
| 423 | triple.binary_format = default_binary_format(&triple); |
| 424 | } |
| 425 | _ => return None, |
| 426 | } |
| 427 | |
| 428 | Some(triple) |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | /// A convenient syntax for triple literals. |
| 433 | /// |
| 434 | /// This currently expands to code that just calls `Triple::from_str` and does |
| 435 | /// an `expect`, though in the future it would be cool to use procedural macros |
| 436 | /// or so to report errors at compile time instead. |
| 437 | #[macro_export ] |
| 438 | macro_rules! triple { |
| 439 | ($str:tt) => { |
| 440 | <$crate::Triple as core::str::FromStr>::from_str($str).expect("invalid triple literal" ) |
| 441 | }; |
| 442 | } |
| 443 | |
| 444 | #[cfg (test)] |
| 445 | mod tests { |
| 446 | use super::*; |
| 447 | |
| 448 | #[test ] |
| 449 | fn parse_errors() { |
| 450 | assert_eq!( |
| 451 | Triple::from_str("" ), |
| 452 | Err(ParseError::UnrecognizedArchitecture("" .to_owned())) |
| 453 | ); |
| 454 | assert_eq!( |
| 455 | Triple::from_str("foo" ), |
| 456 | Err(ParseError::UnrecognizedArchitecture("foo" .to_owned())) |
| 457 | ); |
| 458 | assert_eq!( |
| 459 | Triple::from_str("unknown-unknown-foo" ), |
| 460 | Err(ParseError::UnrecognizedOperatingSystem("foo" .to_owned())) |
| 461 | ); |
| 462 | assert_eq!( |
| 463 | Triple::from_str("unknown-unknown-unknown-foo" ), |
| 464 | Err(ParseError::UnrecognizedEnvironment("foo" .to_owned())) |
| 465 | ); |
| 466 | assert_eq!( |
| 467 | Triple::from_str("unknown-unknown-unknown-unknown-foo" ), |
| 468 | Err(ParseError::UnrecognizedBinaryFormat("foo" .to_owned())) |
| 469 | ); |
| 470 | assert_eq!( |
| 471 | Triple::from_str("unknown-unknown-unknown-unknown-unknown-foo" ), |
| 472 | Err(ParseError::UnrecognizedField("foo" .to_owned())) |
| 473 | ); |
| 474 | } |
| 475 | |
| 476 | #[test ] |
| 477 | fn defaults() { |
| 478 | assert_eq!( |
| 479 | Triple::from_str("unknown-unknown-unknown" ), |
| 480 | Ok(Triple::unknown()) |
| 481 | ); |
| 482 | assert_eq!( |
| 483 | Triple::from_str("unknown-unknown-unknown-unknown" ), |
| 484 | Ok(Triple::unknown()) |
| 485 | ); |
| 486 | assert_eq!( |
| 487 | Triple::from_str("unknown-unknown-unknown-unknown-unknown" ), |
| 488 | Ok(Triple::unknown()) |
| 489 | ); |
| 490 | } |
| 491 | |
| 492 | #[test ] |
| 493 | fn unknown_properties() { |
| 494 | assert_eq!(Triple::unknown().endianness(), Err(())); |
| 495 | assert_eq!(Triple::unknown().pointer_width(), Err(())); |
| 496 | assert_eq!(Triple::unknown().default_calling_convention(), Err(())); |
| 497 | } |
| 498 | |
| 499 | #[test ] |
| 500 | fn apple_calling_convention() { |
| 501 | for triple in &[ |
| 502 | "aarch64-apple-darwin" , |
| 503 | "aarch64-apple-ios" , |
| 504 | "aarch64-apple-ios-macabi" , |
| 505 | "aarch64-apple-tvos" , |
| 506 | "aarch64-apple-watchos" , |
| 507 | ] { |
| 508 | let triple = Triple::from_str(triple).unwrap(); |
| 509 | assert_eq!( |
| 510 | triple.default_calling_convention().unwrap(), |
| 511 | CallingConvention::AppleAarch64 |
| 512 | ); |
| 513 | assert_eq!(triple.data_model().unwrap(), CDataModel::LP64); |
| 514 | } |
| 515 | |
| 516 | for triple in &["aarch64-linux-android" , "x86_64-apple-ios" ] { |
| 517 | assert_eq!( |
| 518 | Triple::from_str(triple) |
| 519 | .unwrap() |
| 520 | .default_calling_convention() |
| 521 | .unwrap(), |
| 522 | CallingConvention::SystemV |
| 523 | ); |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | #[test ] |
| 528 | fn p32_abi() { |
| 529 | // Test that special 32-bit pointer ABIs on 64-bit architectures are |
| 530 | // reported as having 32-bit pointers. |
| 531 | for triple in &[ |
| 532 | "x86_64-unknown-linux-gnux32" , |
| 533 | "aarch64_be-unknown-linux-gnu_ilp32" , |
| 534 | "aarch64-unknown-linux-gnu_ilp32" , |
| 535 | ] { |
| 536 | assert_eq!( |
| 537 | Triple::from_str(triple).unwrap().pointer_width().unwrap(), |
| 538 | PointerWidth::U32 |
| 539 | ); |
| 540 | } |
| 541 | |
| 542 | // Test that the corresponding ABIs have 64-bit pointers. |
| 543 | for triple in &[ |
| 544 | "x86_64-unknown-linux-gnu" , |
| 545 | "aarch64_be-unknown-linux-gnu" , |
| 546 | "aarch64-unknown-linux-gnu" , |
| 547 | ] { |
| 548 | assert_eq!( |
| 549 | Triple::from_str(triple).unwrap().pointer_width().unwrap(), |
| 550 | PointerWidth::U64 |
| 551 | ); |
| 552 | } |
| 553 | } |
| 554 | } |
| 555 | |