]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/abi.rs
b159920d929cf3bb3e670a34ea0d8bba55958ae3
[rust.git] / src / libsyntax / abi.rs
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.
4 //
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.
10
11 use std::fmt;
12 use std::fmt::Show;
13
14 #[deriving(Eq)]
15 pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
16
17 #[deriving(Eq, Hash)]
18 pub enum Abi {
19     // NB: This ordering MUST match the AbiDatas array below.
20     // (This is ensured by the test indices_are_correct().)
21
22     // Single platform ABIs come first (`for_arch()` relies on this)
23     Cdecl,
24     Stdcall,
25     Fastcall,
26     Aapcs,
27     Win64,
28
29     // Multiplatform ABIs second
30     Rust,
31     C,
32     System,
33     RustIntrinsic,
34 }
35
36 #[allow(non_camel_case_types)]
37 #[deriving(Eq)]
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().)
42     X86,
43     X86_64,
44     Arm,
45     Mips
46 }
47
48 static IntelBits: u32 = (1 << (X86 as uint)) | (1 << (X86_64 as uint));
49 static ArmBits: u32 = (1 << (Arm as uint));
50
51 pub struct AbiData {
52     abi: Abi,
53
54     // Name of this ABI as we like it called.
55     name: &'static str,
56
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
60 }
61
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)
66 }
67
68 #[deriving(Clone, Eq, Encodable, Decodable, Hash)]
69 pub struct AbiSet {
70     priv bits: u32   // each bit represents one of the abis below
71 }
72
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))},
81
82     // Cross-platform ABIs
83     //
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},
90 ];
91
92 fn each_abi(op: |abi: Abi| -> bool) -> bool {
93     /*!
94      *
95      * Iterates through each of the defined ABIs.
96      */
97
98     AbiDatas.iter().advance(|abi_data| op(abi_data.abi))
99 }
100
101 pub fn lookup(name: &str) -> Option<Abi> {
102     /*!
103      *
104      * Returns the ABI with the given name (if any).
105      */
106
107     let mut res = None;
108
109     each_abi(|abi| {
110         if name == abi.data().name {
111             res = Some(abi);
112             false
113         } else {
114             true
115         }
116     });
117     res
118 }
119
120 pub fn all_names() -> Vec<&'static str> {
121     AbiDatas.iter().map(|d| d.name).collect()
122 }
123
124 impl Abi {
125     #[inline]
126     pub fn index(&self) -> uint {
127         *self as uint
128     }
129
130     #[inline]
131     pub fn data(&self) -> &'static AbiData {
132         &AbiDatas[self.index()]
133     }
134
135     pub fn name(&self) -> &'static str {
136         self.data().name
137     }
138
139     pub fn for_target(&self, os: Os, arch: Architecture) -> Abi {
140         match (*self, os, arch) {
141             (System, OsWin32, X86) => Stdcall,
142             (System, _, _) => C,
143             (me, _, _) => me,
144         }
145     }
146 }
147
148 impl Architecture {
149     fn bit(&self) -> u32 {
150         1 << (*self as u32)
151     }
152 }
153
154 impl AbiSet {
155     pub fn from(abi: Abi) -> AbiSet {
156         AbiSet { bits: (1 << abi.index()) }
157     }
158
159     #[inline]
160     pub fn Rust() -> AbiSet {
161         AbiSet::from(Rust)
162     }
163
164     #[inline]
165     pub fn C() -> AbiSet {
166         AbiSet::from(C)
167     }
168
169     #[inline]
170     pub fn Intrinsic() -> AbiSet {
171         AbiSet::from(RustIntrinsic)
172     }
173
174     pub fn default() -> AbiSet {
175         AbiSet::C()
176     }
177
178     pub fn empty() -> AbiSet {
179         AbiSet { bits: 0 }
180     }
181
182     #[inline]
183     pub fn is_rust(&self) -> bool {
184         self.bits == 1 << Rust.index()
185     }
186
187     #[inline]
188     pub fn is_c(&self) -> bool {
189         self.bits == 1 << C.index()
190     }
191
192     #[inline]
193     pub fn is_intrinsic(&self) -> bool {
194         self.bits == 1 << RustIntrinsic.index()
195     }
196
197     pub fn contains(&self, abi: Abi) -> bool {
198         (self.bits & (1 << abi.index())) != 0
199     }
200
201     pub fn subset_of(&self, other_abi_set: AbiSet) -> bool {
202         (self.bits & other_abi_set.bits) == self.bits
203     }
204
205     pub fn add(&mut self, abi: Abi) {
206         self.bits |= 1 << abi.index();
207     }
208
209     pub fn each(&self, op: |abi: Abi| -> bool) -> bool {
210         each_abi(|abi| !self.contains(abi) || op(abi))
211     }
212
213     pub fn is_empty(&self) -> bool {
214         self.bits == 0
215     }
216
217     pub fn for_target(&self, os: Os, arch: Architecture) -> Option<Abi> {
218         // NB---Single platform ABIs come first
219
220         let mut res = None;
221
222         self.each(|abi| {
223             let data = abi.data();
224             match data.abi_arch {
225                 Archs(a) if (a & arch.bit()) != 0 => { res = Some(abi); false }
226                 Archs(_) => { true }
227                 RustArch | AllArch => { res = Some(abi); false }
228             }
229         });
230
231         res.map(|r| r.for_target(os, arch))
232     }
233
234     pub fn check_valid(&self) -> Option<(Abi, Abi)> {
235         let mut abis = Vec::new();
236         self.each(|abi| { abis.push(abi); true });
237
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=({:?},{:?})",
243                        abi, data.abi_arch,
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));
249                     }
250                     (_, &RustArch) |
251                     (&RustArch, _) => {
252                         // Cannot combine Rust or Rust-Intrinsic with
253                         // anything else.
254                         return Some((*abi, *other_abi));
255                     }
256                     (&Archs(is), &Archs(js)) if (is & js) != 0 => {
257                         // Two ABIs for same architecture
258                         return Some((*abi, *other_abi));
259                     }
260                     _ => {}
261                 }
262             }
263         }
264
265         return None;
266     }
267 }
268
269 impl fmt::Show for Abi {
270     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
271         self.data().name.fmt(f)
272     }
273 }
274
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;
279         self.each(|abi| {
280             if first { first = false; }
281             else { let _ = write!(f.buf, " "); }
282             let _ = write!(f.buf, "{}", abi.data().name);
283             true
284         });
285         write!(f.buf, "\"")
286     }
287 }
288
289 #[test]
290 fn lookup_Rust() {
291     let abi = lookup("Rust");
292     assert!(abi.is_some() && abi.unwrap().data().name == "Rust");
293 }
294
295 #[test]
296 fn lookup_cdecl() {
297     let abi = lookup("cdecl");
298     assert!(abi.is_some() && abi.unwrap().data().name == "cdecl");
299 }
300
301 #[test]
302 fn lookup_baz() {
303     let abi = lookup("baz");
304     assert!(abi.is_none());
305 }
306
307 #[cfg(test)]
308 fn cannot_combine(n: Abi, m: Abi) {
309     let mut set = AbiSet::empty();
310     set.add(n);
311     set.add(m);
312     match set.check_valid() {
313         Some((a, b)) => {
314             assert!((n == a && m == b) ||
315                          (m == a && n == b));
316         }
317         None => {
318             fail!("invalid match not detected");
319         }
320     }
321 }
322
323 #[cfg(test)]
324 fn can_combine(n: Abi, m: Abi) {
325     let mut set = AbiSet::empty();
326     set.add(n);
327     set.add(m);
328     match set.check_valid() {
329         Some((_, _)) => {
330             fail!("valid match declared invalid");
331         }
332         None => {}
333     }
334 }
335
336 #[test]
337 fn cannot_combine_cdecl_and_stdcall() {
338     cannot_combine(Cdecl, Stdcall);
339 }
340
341 #[test]
342 fn cannot_combine_c_and_rust() {
343     cannot_combine(C, Rust);
344 }
345
346 #[test]
347 fn cannot_combine_rust_and_cdecl() {
348     cannot_combine(Rust, Cdecl);
349 }
350
351 #[test]
352 fn cannot_combine_rust_intrinsic_and_cdecl() {
353     cannot_combine(RustIntrinsic, Cdecl);
354 }
355
356 #[test]
357 fn can_combine_system_and_cdecl() {
358     can_combine(System, Cdecl);
359 }
360
361 #[test]
362 fn can_combine_c_and_stdcall() {
363     can_combine(C, Stdcall);
364 }
365
366 #[test]
367 fn can_combine_aapcs_and_stdcall() {
368     can_combine(Aapcs, Stdcall);
369 }
370
371 #[test]
372 fn abi_to_str_stdcall_aaps() {
373     let mut set = AbiSet::empty();
374     set.add(Aapcs);
375     set.add(Stdcall);
376     assert!(set.to_str() == ~"\"stdcall aapcs\"");
377 }
378
379 #[test]
380 fn abi_to_str_c_aaps() {
381     let mut set = AbiSet::empty();
382     set.add(Aapcs);
383     set.add(C);
384     debug!("set = {}", set.to_str());
385     assert!(set.to_str() == ~"\"aapcs C\"");
386 }
387
388 #[test]
389 fn abi_to_str_rust() {
390     let mut set = AbiSet::empty();
391     set.add(Rust);
392     debug!("set = {}", set.to_str());
393     assert!(set.to_str() == ~"\"Rust\"");
394 }
395
396 #[test]
397 fn indices_are_correct() {
398     for (i, abi_data) in AbiDatas.iter().enumerate() {
399         assert_eq!(i, abi_data.abi.index());
400     }
401
402     let bits = 1 << (X86 as u32);
403     let bits = bits | 1 << (X86_64 as u32);
404     assert_eq!(IntelBits, bits);
405
406     let bits = 1 << (Arm as u32);
407     assert_eq!(ArmBits, bits);
408 }
409
410 #[cfg(test)]
411 fn get_arch(abis: &[Abi], os: Os, arch: Architecture) -> Option<Abi> {
412     let mut set = AbiSet::empty();
413     for &abi in abis.iter() {
414         set.add(abi);
415     }
416     set.for_target(os, arch)
417 }
418
419 #[test]
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));
424 }
425
426 #[test]
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));
436 }