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.
13 use core
::to_str
::ToStr
;
17 // NB: This ordering MUST match the AbiDatas array below.
18 // (This is ensured by the test indices_are_correct().)
20 // Single platform ABIs come first (`for_arch()` relies on this)
26 // Multiplatform ABIs second
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().)
43 static IntelBits
: u32 = (1 << (X86
as uint
)) | (1 << (X86_64
as uint
));
44 static ArmBits
: u32 = (1 << (Arm
as uint
));
49 // Name of this ABI as we like it called.
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
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)
67 priv bits
: u32 // each bit represents one of the abis below
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)}
,
77 // Cross-platform ABIs
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}
,
86 fn each_abi(op
: &fn(abi
: Abi
) -> bool
) {
89 * Iterates through each of the defined ABIs.
92 for AbiDatas
.each
|abi_data
| {
93 if !op(abi_data
.abi
) {
99 pub fn lookup(name
: &str) -> Option
<Abi
> {
102 * Returns the ABI with the given name (if any).
106 if name
== abi
.data().name
{
113 pub fn all_names() -> ~[&'
static str] {
114 AbiDatas
.map(|d
| d
.name
)
119 fn index(&self) -> uint
{
124 fn data(&self) -> &'
static AbiData
{
125 &AbiDatas
[self.index()]
128 fn name(&self) -> &'
static str {
134 fn bit(&self) -> u32 {
140 fn from(abi
: Abi
) -> AbiSet
{
141 AbiSet { bits: (1 << abi.index()) }
145 fn Rust() -> AbiSet
{
155 fn Intrinsic() -> AbiSet
{
156 AbiSet
::from(RustIntrinsic
)
159 fn default() -> AbiSet
{
163 fn empty() -> AbiSet
{
168 fn is_rust(&self) -> bool
{
169 self.bits
== 1 << Rust
.index()
173 fn is_c(&self) -> bool
{
174 self.bits
== 1 << C
.index()
178 fn is_intrinsic(&self) -> bool
{
179 self.bits
== 1 << RustIntrinsic
.index()
182 fn contains(&self, abi
: Abi
) -> bool
{
183 (self.bits
& (1 << abi
.index())) != 0
186 fn subset_of(&self, other_abi_set
: AbiSet
) -> bool
{
187 (self.bits
& other_abi_set
.bits
) == self.bits
190 fn add(&mut self, abi
: Abi
) {
191 self.bits
|= (1 << abi
.index());
194 fn each(&self, op
: &fn(abi
: Abi
) -> bool
) {
196 if self.contains(abi
) {
204 fn is_empty(&self) -> bool
{
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); }
215 RustArch
| AllArch
=> { return Some(abi); }
222 fn check_valid(&self) -> Option
<(Abi
, Abi
)> {
224 for self.each
|abi
| { abis.push(abi); }
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=(%?,%?)",
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
));
240 // Cannot combine Rust or Rust-Intrinsic with
242 return Some((*abi
, *other_abi
));
244 (&Archs(is
), &Archs(js
)) if (is
& js
) != 0 => {
245 // Two ABIs for same architecture
246 return Some((*abi
, *other_abi
));
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
)
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
)
270 fn to_str(&self) -> ~str {
271 self.data().name
.to_str()
275 impl ToStr
for AbiSet
{
276 fn to_str(&self) -> ~str {
277 unsafe { // so we can push to strs.
279 for self.each
|abi
| {
280 strs
.push(abi
.data().name
);
282 fmt
!("\"%s\"", str::connect_slices(strs
, " "))
289 let abi
= lookup("Rust");
290 assert
!(abi
.is_some() && abi
.get().data().name
== "Rust");
295 let abi
= lookup("cdecl");
296 assert
!(abi
.is_some() && abi
.get().data().name
== "cdecl");
301 let abi
= lookup("baz");
302 assert
!(abi
.is_none());
306 fn cannot_combine(n
: Abi
, m
: Abi
) {
307 let mut set
= AbiSet
::empty();
310 match set
.check_valid() {
312 assert
!((n
== a
&& m
== b
) ||
316 fail
!(~"Invalid match not detected");
322 fn can_combine(n
: Abi
, m
: Abi
) {
323 let mut set
= AbiSet
::empty();
326 match set
.check_valid() {
328 fail
!(~"Valid match declared invalid");
335 fn cannot_combine_cdecl_and_stdcall() {
336 cannot_combine(Cdecl
, Stdcall
);
340 fn cannot_combine_c_and_rust() {
341 cannot_combine(C
, Rust
);
345 fn cannot_combine_rust_and_cdecl() {
346 cannot_combine(Rust
, Cdecl
);
350 fn cannot_combine_rust_intrinsic_and_cdecl() {
351 cannot_combine(RustIntrinsic
, Cdecl
);
355 fn can_combine_c_and_stdcall() {
356 can_combine(C
, Stdcall
);
360 fn can_combine_aapcs_and_stdcall() {
361 can_combine(Aapcs
, Stdcall
);
365 fn abi_to_str_stdcall_aaps() {
366 let mut set
= AbiSet
::empty();
369 assert
!(set
.to_str() == ~"\"stdcall aapcs\"");
373 fn abi_to_str_c_aaps() {
374 let mut set
= AbiSet
::empty();
377 debug
!("set = %s", set
.to_str());
378 assert
!(set
.to_str() == ~"\"aapcs C\"");
382 fn abi_to_str_rust() {
383 let mut set
= AbiSet
::empty();
385 debug
!("set = %s", set
.to_str());
386 assert
!(set
.to_str() == ~"\"Rust\"");
390 fn indices_are_correct() {
391 for AbiDatas
.eachi
|i
, abi_data
| {
392 assert
!(i
== abi_data
.abi
.index());
395 let bits
= 1 << (X86
as u32);
396 let bits
= bits
| 1 << (X86_64
as u32);
397 assert
!(IntelBits
== bits
);
399 let bits
= 1 << (Arm
as u32);
400 assert
!(ArmBits
== bits
);
404 fn check_arch(abis
: &[Abi
], arch
: Architecture
, expect
: Option
<Abi
>) {
405 let mut set
= AbiSet
::empty();
406 for abis
.each
|&abi
| {
409 let r
= set
.for_arch(arch
);
410 assert
!(r
== expect
);
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
));
421 fn pick_uniplatform() {
422 check_arch([Stdcall
], X86
, Some(Stdcall
));
423 check_arch([Stdcall
], Arm
, None
);