1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
15 pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
19 // NB: This ordering MUST match the AbiDatas array below.
20 // (This is ensured by the test indices_are_correct().)
22 // Single platform ABIs come first (`for_arch()` relies on this)
29 // Multiplatform ABIs second
36 #[allow(non_camel_case_types)]
38 pub enum Architecture {
39 // NB. You cannot change the ordering of these
40 // constants without adjusting IntelBits below.
41 // (This is ensured by the test indices_are_correct().)
48 static IntelBits: u32 = (1 << (X86 as uint)) | (1 << (X86_64 as uint));
49 static ArmBits: u32 = (1 << (Arm as uint));
54 // Name of this ABI as we like it called.
57 // Is it specific to a platform? If so, which one? Also, what is
58 // the name that LLVM gives it (in case we disagree)
59 abi_arch: AbiArchitecture
62 pub enum AbiArchitecture {
63 RustArch, // Not a real ABI (e.g., intrinsic)
64 AllArch, // An ABI that specifies cross-platform defaults (e.g., "C")
65 Archs(u32) // Multiple architectures (bitset)
68 #[deriving(Clone, Eq, Encodable, Decodable, Hash)]
70 priv bits: u32 // each bit represents one of the abis below
73 static AbiDatas: &'static [AbiData] = &[
74 // Platform-specific ABIs
75 AbiData {abi: Cdecl, name: "cdecl", abi_arch: Archs(IntelBits)},
76 AbiData {abi: Stdcall, name: "stdcall", abi_arch: Archs(IntelBits)},
77 AbiData {abi: Fastcall, name:"fastcall", abi_arch: Archs(IntelBits)},
78 AbiData {abi: Aapcs, name: "aapcs", abi_arch: Archs(ArmBits)},
79 AbiData {abi: Win64, name: "win64",
80 abi_arch: Archs(1 << (X86_64 as uint))},
82 // Cross-platform ABIs
84 // NB: Do not adjust this ordering without
85 // adjusting the indices below.
86 AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
87 AbiData {abi: C, name: "C", abi_arch: AllArch},
88 AbiData {abi: System, name: "system", abi_arch: AllArch},
89 AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
92 fn each_abi(op: |abi: Abi| -> bool) -> bool {
95 * Iterates through each of the defined ABIs.
98 AbiDatas.iter().advance(|abi_data| op(abi_data.abi))
101 pub fn lookup(name: &str) -> Option<Abi> {
104 * Returns the ABI with the given name (if any).
110 if name == abi.data().name {
120 pub fn all_names() -> Vec<&'static str> {
121 AbiDatas.iter().map(|d| d.name).collect()
126 pub fn index(&self) -> uint {
131 pub fn data(&self) -> &'static AbiData {
132 &AbiDatas[self.index()]
135 pub fn name(&self) -> &'static str {
139 pub fn for_target(&self, os: Os, arch: Architecture) -> Abi {
140 match (*self, os, arch) {
141 (System, OsWin32, X86) => Stdcall,
149 fn bit(&self) -> u32 {
155 pub fn from(abi: Abi) -> AbiSet {
156 AbiSet { bits: (1 << abi.index()) }
160 pub fn Rust() -> AbiSet {
165 pub fn C() -> AbiSet {
170 pub fn Intrinsic() -> AbiSet {
171 AbiSet::from(RustIntrinsic)
174 pub fn default() -> AbiSet {
178 pub fn empty() -> AbiSet {
183 pub fn is_rust(&self) -> bool {
184 self.bits == 1 << Rust.index()
188 pub fn is_c(&self) -> bool {
189 self.bits == 1 << C.index()
193 pub fn is_intrinsic(&self) -> bool {
194 self.bits == 1 << RustIntrinsic.index()
197 pub fn contains(&self, abi: Abi) -> bool {
198 (self.bits & (1 << abi.index())) != 0
201 pub fn subset_of(&self, other_abi_set: AbiSet) -> bool {
202 (self.bits & other_abi_set.bits) == self.bits
205 pub fn add(&mut self, abi: Abi) {
206 self.bits |= 1 << abi.index();
209 pub fn each(&self, op: |abi: Abi| -> bool) -> bool {
210 each_abi(|abi| !self.contains(abi) || op(abi))
213 pub fn is_empty(&self) -> bool {
217 pub fn for_target(&self, os: Os, arch: Architecture) -> Option<Abi> {
218 // NB---Single platform ABIs come first
223 let data = abi.data();
224 match data.abi_arch {
225 Archs(a) if (a & arch.bit()) != 0 => { res = Some(abi); false }
227 RustArch | AllArch => { res = Some(abi); false }
231 res.map(|r| r.for_target(os, arch))
234 pub fn check_valid(&self) -> Option<(Abi, Abi)> {
235 let mut abis = Vec::new();
236 self.each(|abi| { abis.push(abi); true });
238 for (i, abi) in abis.iter().enumerate() {
239 let data = abi.data();
240 for other_abi in abis.slice(0, i).iter() {
241 let other_data = other_abi.data();
242 debug!("abis=({:?},{:?}) datas=({:?},{:?})",
244 other_abi, other_data.abi_arch);
245 match (&data.abi_arch, &other_data.abi_arch) {
246 (&AllArch, &AllArch) => {
247 // Two cross-architecture ABIs
248 return Some((*abi, *other_abi));
252 // Cannot combine Rust or Rust-Intrinsic with
254 return Some((*abi, *other_abi));
256 (&Archs(is), &Archs(js)) if (is & js) != 0 => {
257 // Two ABIs for same architecture
258 return Some((*abi, *other_abi));
269 impl fmt::Show for Abi {
270 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
271 self.data().name.fmt(f)
275 impl fmt::Show for AbiSet {
276 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277 try!(write!(f.buf, "\""));
278 let mut first = true;
280 if first { first = false; }
281 else { let _ = write!(f.buf, " "); }
282 let _ = write!(f.buf, "{}", abi.data().name);
291 let abi = lookup("Rust");
292 assert!(abi.is_some() && abi.unwrap().data().name == "Rust");
297 let abi = lookup("cdecl");
298 assert!(abi.is_some() && abi.unwrap().data().name == "cdecl");
303 let abi = lookup("baz");
304 assert!(abi.is_none());
308 fn cannot_combine(n: Abi, m: Abi) {
309 let mut set = AbiSet::empty();
312 match set.check_valid() {
314 assert!((n == a && m == b) ||
318 fail!("invalid match not detected");
324 fn can_combine(n: Abi, m: Abi) {
325 let mut set = AbiSet::empty();
328 match set.check_valid() {
330 fail!("valid match declared invalid");
337 fn cannot_combine_cdecl_and_stdcall() {
338 cannot_combine(Cdecl, Stdcall);
342 fn cannot_combine_c_and_rust() {
343 cannot_combine(C, Rust);
347 fn cannot_combine_rust_and_cdecl() {
348 cannot_combine(Rust, Cdecl);
352 fn cannot_combine_rust_intrinsic_and_cdecl() {
353 cannot_combine(RustIntrinsic, Cdecl);
357 fn can_combine_system_and_cdecl() {
358 can_combine(System, Cdecl);
362 fn can_combine_c_and_stdcall() {
363 can_combine(C, Stdcall);
367 fn can_combine_aapcs_and_stdcall() {
368 can_combine(Aapcs, Stdcall);
372 fn abi_to_str_stdcall_aaps() {
373 let mut set = AbiSet::empty();
376 assert!(set.to_str() == ~"\"stdcall aapcs\"");
380 fn abi_to_str_c_aaps() {
381 let mut set = AbiSet::empty();
384 debug!("set = {}", set.to_str());
385 assert!(set.to_str() == ~"\"aapcs C\"");
389 fn abi_to_str_rust() {
390 let mut set = AbiSet::empty();
392 debug!("set = {}", set.to_str());
393 assert!(set.to_str() == ~"\"Rust\"");
397 fn indices_are_correct() {
398 for (i, abi_data) in AbiDatas.iter().enumerate() {
399 assert_eq!(i, abi_data.abi.index());
402 let bits = 1 << (X86 as u32);
403 let bits = bits | 1 << (X86_64 as u32);
404 assert_eq!(IntelBits, bits);
406 let bits = 1 << (Arm as u32);
407 assert_eq!(ArmBits, bits);
411 fn get_arch(abis: &[Abi], os: Os, arch: Architecture) -> Option<Abi> {
412 let mut set = AbiSet::empty();
413 for &abi in abis.iter() {
416 set.for_target(os, arch)
420 fn pick_multiplatform() {
421 assert_eq!(get_arch([C, Cdecl], OsLinux, X86), Some(Cdecl));
422 assert_eq!(get_arch([C, Cdecl], OsLinux, X86_64), Some(Cdecl));
423 assert_eq!(get_arch([C, Cdecl], OsLinux, Arm), Some(C));
427 fn pick_uniplatform() {
428 assert_eq!(get_arch([Stdcall], OsLinux, X86), Some(Stdcall));
429 assert_eq!(get_arch([Stdcall], OsLinux, Arm), None);
430 assert_eq!(get_arch([System], OsLinux, X86), Some(C));
431 assert_eq!(get_arch([System], OsWin32, X86), Some(Stdcall));
432 assert_eq!(get_arch([System], OsWin32, X86_64), Some(C));
433 assert_eq!(get_arch([System], OsWin32, Arm), Some(C));
434 assert_eq!(get_arch([Stdcall], OsWin32, X86), Some(Stdcall));
435 assert_eq!(get_arch([Stdcall], OsWin32, X86_64), Some(Stdcall));