]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/abi.rs
Imported Upstream version 0.6
[rustc.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 core::prelude::*;
12 use core::to_bytes;
13 use core::to_str::ToStr;
14
15 #[deriving(Eq)]
16 pub enum Abi {
17 // NB: This ordering MUST match the AbiDatas array below.
18 // (This is ensured by the test indices_are_correct().)
19
20 // Single platform ABIs come first (`for_arch()` relies on this)
21 Cdecl,
22 Stdcall,
23 Fastcall,
24 Aapcs,
25
26 // Multiplatform ABIs second
27 Rust,
28 C,
29 RustIntrinsic,
30 }
31
32 #[deriving(Eq)]
33 pub enum Architecture {
34 // NB. You cannot change the ordering of these
35 // constants without adjusting IntelBits below.
36 // (This is ensured by the test indices_are_correct().)
37 X86,
38 X86_64,
39 Arm,
40 Mips
41 }
42
43 static IntelBits: u32 = (1 << (X86 as uint)) | (1 << (X86_64 as uint));
44 static ArmBits: u32 = (1 << (Arm as uint));
45
46 struct AbiData {
47 abi: Abi,
48
49 // Name of this ABI as we like it called.
50 name: &'static str,
51
52 // Is it specific to a platform? If so, which one? Also, what is
53 // the name that LLVM gives it (in case we disagree)
54 abi_arch: AbiArchitecture
55 }
56
57 enum AbiArchitecture {
58 RustArch, // Not a real ABI (e.g., intrinsic)
59 AllArch, // An ABI that specifies cross-platform defaults (e.g., "C")
60 Archs(u32) // Multiple architectures (bitset)
61 }
62
63 #[auto_encode]
64 #[auto_decode]
65 #[deriving(Eq)]
66 pub struct AbiSet {
67 priv bits: u32 // each bit represents one of the abis below
68 }
69
70 static AbiDatas: &'static [AbiData] = &[
71 // Platform-specific ABIs
72 AbiData {abi: Cdecl, name: "cdecl", abi_arch: Archs(IntelBits)},
73 AbiData {abi: Stdcall, name: "stdcall", abi_arch: Archs(IntelBits)},
74 AbiData {abi: Fastcall, name:"fastcall", abi_arch: Archs(IntelBits)},
75 AbiData {abi: Aapcs, name: "aapcs", abi_arch: Archs(ArmBits)},
76
77 // Cross-platform ABIs
78 //
79 // NB: Do not adjust this ordering without
80 // adjusting the indices below.
81 AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
82 AbiData {abi: C, name: "C", abi_arch: AllArch},
83 AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
84 ];
85
86 fn each_abi(op: &fn(abi: Abi) -> bool) {
87 /*!
88 *
89 * Iterates through each of the defined ABIs.
90 */
91
92 for AbiDatas.each |abi_data| {
93 if !op(abi_data.abi) {
94 return;
95 }
96 }
97 }
98
99 pub fn lookup(name: &str) -> Option<Abi> {
100 /*!
101 *
102 * Returns the ABI with the given name (if any).
103 */
104
105 for each_abi |abi| {
106 if name == abi.data().name {
107 return Some(abi);
108 }
109 }
110 return None;
111 }
112
113 pub fn all_names() -> ~[&'static str] {
114 AbiDatas.map(|d| d.name)
115 }
116
117 pub impl Abi {
118 #[inline]
119 fn index(&self) -> uint {
120 *self as uint
121 }
122
123 #[inline]
124 fn data(&self) -> &'static AbiData {
125 &AbiDatas[self.index()]
126 }
127
128 fn name(&self) -> &'static str {
129 self.data().name
130 }
131 }
132
133 impl Architecture {
134 fn bit(&self) -> u32 {
135 1 << (*self as u32)
136 }
137 }
138
139 pub impl AbiSet {
140 fn from(abi: Abi) -> AbiSet {
141 AbiSet { bits: (1 << abi.index()) }
142 }
143
144 #[inline]
145 fn Rust() -> AbiSet {
146 AbiSet::from(Rust)
147 }
148
149 #[inline]
150 fn C() -> AbiSet {
151 AbiSet::from(C)
152 }
153
154 #[inline]
155 fn Intrinsic() -> AbiSet {
156 AbiSet::from(RustIntrinsic)
157 }
158
159 fn default() -> AbiSet {
160 AbiSet::C()
161 }
162
163 fn empty() -> AbiSet {
164 AbiSet { bits: 0 }
165 }
166
167 #[inline]
168 fn is_rust(&self) -> bool {
169 self.bits == 1 << Rust.index()
170 }
171
172 #[inline]
173 fn is_c(&self) -> bool {
174 self.bits == 1 << C.index()
175 }
176
177 #[inline]
178 fn is_intrinsic(&self) -> bool {
179 self.bits == 1 << RustIntrinsic.index()
180 }
181
182 fn contains(&self, abi: Abi) -> bool {
183 (self.bits & (1 << abi.index())) != 0
184 }
185
186 fn subset_of(&self, other_abi_set: AbiSet) -> bool {
187 (self.bits & other_abi_set.bits) == self.bits
188 }
189
190 fn add(&mut self, abi: Abi) {
191 self.bits |= (1 << abi.index());
192 }
193
194 fn each(&self, op: &fn(abi: Abi) -> bool) {
195 for each_abi |abi| {
196 if self.contains(abi) {
197 if !op(abi) {
198 return;
199 }
200 }
201 }
202 }
203
204 fn is_empty(&self) -> bool {
205 self.bits == 0
206 }
207
208 fn for_arch(&self, arch: Architecture) -> Option<Abi> {
209 // NB---Single platform ABIs come first
210 for self.each |abi| {
211 let data = abi.data();
212 match data.abi_arch {
213 Archs(a) if (a & arch.bit()) != 0 => { return Some(abi); }
214 Archs(_) => { }
215 RustArch | AllArch => { return Some(abi); }
216 }
217 }
218
219 None
220 }
221
222 fn check_valid(&self) -> Option<(Abi, Abi)> {
223 let mut abis = ~[];
224 for self.each |abi| { abis.push(abi); }
225
226 for abis.eachi |i, abi| {
227 let data = abi.data();
228 for abis.slice(0, i).each |other_abi| {
229 let other_data = other_abi.data();
230 debug!("abis=(%?,%?) datas=(%?,%?)",
231 abi, data.abi_arch,
232 other_abi, other_data.abi_arch);
233 match (&data.abi_arch, &other_data.abi_arch) {
234 (&AllArch, &AllArch) => {
235 // Two cross-architecture ABIs
236 return Some((*abi, *other_abi));
237 }
238 (_, &RustArch) |
239 (&RustArch, _) => {
240 // Cannot combine Rust or Rust-Intrinsic with
241 // anything else.
242 return Some((*abi, *other_abi));
243 }
244 (&Archs(is), &Archs(js)) if (is & js) != 0 => {
245 // Two ABIs for same architecture
246 return Some((*abi, *other_abi));
247 }
248 _ => {}
249 }
250 }
251 }
252
253 return None;
254 }
255 }
256
257 impl to_bytes::IterBytes for Abi {
258 fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
259 self.index().iter_bytes(lsb0, f)
260 }
261 }
262
263 impl to_bytes::IterBytes for AbiSet {
264 fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
265 self.bits.iter_bytes(lsb0, f)
266 }
267 }
268
269 impl ToStr for Abi {
270 fn to_str(&self) -> ~str {
271 self.data().name.to_str()
272 }
273 }
274
275 impl ToStr for AbiSet {
276 fn to_str(&self) -> ~str {
277 unsafe { // so we can push to strs.
278 let mut strs = ~[];
279 for self.each |abi| {
280 strs.push(abi.data().name);
281 }
282 fmt!("\"%s\"", str::connect_slices(strs, " "))
283 }
284 }
285 }
286
287 #[test]
288 fn lookup_Rust() {
289 let abi = lookup("Rust");
290 assert!(abi.is_some() && abi.get().data().name == "Rust");
291 }
292
293 #[test]
294 fn lookup_cdecl() {
295 let abi = lookup("cdecl");
296 assert!(abi.is_some() && abi.get().data().name == "cdecl");
297 }
298
299 #[test]
300 fn lookup_baz() {
301 let abi = lookup("baz");
302 assert!(abi.is_none());
303 }
304
305 #[cfg(test)]
306 fn cannot_combine(n: Abi, m: Abi) {
307 let mut set = AbiSet::empty();
308 set.add(n);
309 set.add(m);
310 match set.check_valid() {
311 Some((a, b)) => {
312 assert!((n == a && m == b) ||
313 (m == a && n == b));
314 }
315 None => {
316 fail!(~"Invalid match not detected");
317 }
318 }
319 }
320
321 #[cfg(test)]
322 fn can_combine(n: Abi, m: Abi) {
323 let mut set = AbiSet::empty();
324 set.add(n);
325 set.add(m);
326 match set.check_valid() {
327 Some((_, _)) => {
328 fail!(~"Valid match declared invalid");
329 }
330 None => {}
331 }
332 }
333
334 #[test]
335 fn cannot_combine_cdecl_and_stdcall() {
336 cannot_combine(Cdecl, Stdcall);
337 }
338
339 #[test]
340 fn cannot_combine_c_and_rust() {
341 cannot_combine(C, Rust);
342 }
343
344 #[test]
345 fn cannot_combine_rust_and_cdecl() {
346 cannot_combine(Rust, Cdecl);
347 }
348
349 #[test]
350 fn cannot_combine_rust_intrinsic_and_cdecl() {
351 cannot_combine(RustIntrinsic, Cdecl);
352 }
353
354 #[test]
355 fn can_combine_c_and_stdcall() {
356 can_combine(C, Stdcall);
357 }
358
359 #[test]
360 fn can_combine_aapcs_and_stdcall() {
361 can_combine(Aapcs, Stdcall);
362 }
363
364 #[test]
365 fn abi_to_str_stdcall_aaps() {
366 let mut set = AbiSet::empty();
367 set.add(Aapcs);
368 set.add(Stdcall);
369 assert!(set.to_str() == ~"\"stdcall aapcs\"");
370 }
371
372 #[test]
373 fn abi_to_str_c_aaps() {
374 let mut set = AbiSet::empty();
375 set.add(Aapcs);
376 set.add(C);
377 debug!("set = %s", set.to_str());
378 assert!(set.to_str() == ~"\"aapcs C\"");
379 }
380
381 #[test]
382 fn abi_to_str_rust() {
383 let mut set = AbiSet::empty();
384 set.add(Rust);
385 debug!("set = %s", set.to_str());
386 assert!(set.to_str() == ~"\"Rust\"");
387 }
388
389 #[test]
390 fn indices_are_correct() {
391 for AbiDatas.eachi |i, abi_data| {
392 assert!(i == abi_data.abi.index());
393 }
394
395 let bits = 1 << (X86 as u32);
396 let bits = bits | 1 << (X86_64 as u32);
397 assert!(IntelBits == bits);
398
399 let bits = 1 << (Arm as u32);
400 assert!(ArmBits == bits);
401 }
402
403 #[cfg(test)]
404 fn check_arch(abis: &[Abi], arch: Architecture, expect: Option<Abi>) {
405 let mut set = AbiSet::empty();
406 for abis.each |&abi| {
407 set.add(abi);
408 }
409 let r = set.for_arch(arch);
410 assert!(r == expect);
411 }
412
413 #[test]
414 fn pick_multiplatform() {
415 check_arch([C, Cdecl], X86, Some(Cdecl));
416 check_arch([C, Cdecl], X86_64, Some(Cdecl));
417 check_arch([C, Cdecl], Arm, Some(C));
418 }
419
420 #[test]
421 fn pick_uniplatform() {
422 check_arch([Stdcall], X86, Some(Stdcall));
423 check_arch([Stdcall], Arm, None);
424 }