about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-11-20 11:01:34 -0800
committerbors <bors@rust-lang.org>2013-11-20 11:01:34 -0800
commite12bc239b4e85d0dedc5ba6e9f7ffa0b91ade634 (patch)
tree3f5752af4483fea874d47504a3b0cffd52ef2989 /src
parent6a25ba374b2bfe32d4411cab3547d76d47769d6c (diff)
parent02e565a187adc0b5a7348852de664be26eb1701c (diff)
downloadrust-e12bc239b4e85d0dedc5ba6e9f7ffa0b91ade634.tar.gz
rust-e12bc239b4e85d0dedc5ba6e9f7ffa0b91ade634.zip
auto merge of #10527 : eholk/rust/win64, r=alexcrichton
This was needed to access UEFI boot services in my new Boot2Rust experiment.

I also realized that Rust functions declared as extern always use the C calling convention regardless of how they were declared, so this pull request fixes that as well.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/lib/llvm.rs1
-rw-r--r--src/librustc/middle/trans/foreign.rs13
-rw-r--r--src/libsyntax/abi.rs3
-rw-r--r--src/test/auxiliary/extern_calling_convention.rs37
-rw-r--r--src/test/run-pass/extern-calling-convention-test.rs20
5 files changed, 72 insertions, 2 deletions
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index 14af20f0cb9..160bc511168 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -33,6 +33,7 @@ pub enum CallConv {
     ColdCallConv = 9,
     X86StdcallCallConv = 64,
     X86FastcallCallConv = 65,
+    X86_64_Win64 = 79,
 }
 
 pub enum Visibility {
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 33036aab65b..d73345b8474 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -33,7 +33,7 @@ use syntax::{ast};
 use syntax::{attr, ast_map};
 use syntax::parse::token::special_idents;
 use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System,
-                  Cdecl, Aapcs, C, AbiSet};
+                  Cdecl, Aapcs, C, AbiSet, Win64};
 use util::ppaux::{Repr, UserString};
 use middle::trans::type_::Type;
 
@@ -96,6 +96,7 @@ pub fn llvm_calling_convention(ccx: &mut CrateContext,
             Stdcall => lib::llvm::X86StdcallCallConv,
             Fastcall => lib::llvm::X86FastcallCallConv,
             C => lib::llvm::CCallConv,
+            Win64 => lib::llvm::X86_64_Win64,
 
             // NOTE These API constants ought to be more specific
             Cdecl => lib::llvm::CCallConv,
@@ -398,11 +399,19 @@ pub fn register_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
 
     let tys = foreign_types_for_id(ccx, node_id);
     let llfn_ty = lltype_for_fn_from_foreign_types(&tys);
+    let t = ty::node_id_to_type(ccx.tcx, node_id);
+    let cconv = match ty::get(t).sty {
+        ty::ty_bare_fn(ref fn_ty) => {
+            let c = llvm_calling_convention(ccx, fn_ty.abis);
+            c.unwrap_or(lib::llvm::CCallConv)
+        }
+        _ => lib::llvm::CCallConv
+    };
     let llfn = base::register_fn_llvmty(ccx,
                                         sp,
                                         sym,
                                         node_id,
-                                        lib::llvm::CCallConv,
+                                        cconv,
                                         llfn_ty);
     add_argument_attributes(&tys, llfn);
     debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})",
diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs
index c2283bf1227..60d49b4c9ed 100644
--- a/src/libsyntax/abi.rs
+++ b/src/libsyntax/abi.rs
@@ -23,6 +23,7 @@ pub enum Abi {
     Stdcall,
     Fastcall,
     Aapcs,
+    Win64,
 
     // Multiplatform ABIs second
     Rust,
@@ -73,6 +74,8 @@ static AbiDatas: &'static [AbiData] = &[
     AbiData {abi: Stdcall, name: "stdcall", abi_arch: Archs(IntelBits)},
     AbiData {abi: Fastcall, name:"fastcall", abi_arch: Archs(IntelBits)},
     AbiData {abi: Aapcs, name: "aapcs", abi_arch: Archs(ArmBits)},
+    AbiData {abi: Win64, name: "win64",
+             abi_arch: Archs(1 << (X86_64 as uint))},
 
     // Cross-platform ABIs
     //
diff --git a/src/test/auxiliary/extern_calling_convention.rs b/src/test/auxiliary/extern_calling_convention.rs
new file mode 100644
index 00000000000..41c57831da6
--- /dev/null
+++ b/src/test/auxiliary/extern_calling_convention.rs
@@ -0,0 +1,37 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Make sure Rust generates the correct calling convention for extern
+// functions.
+
+#[inline(never)]
+#[cfg(target_arch = "x86_64")]
+pub extern "win64" fn foo(a: int, b: int, c: int, d: int) {
+    assert!(a == 1);
+    assert!(b == 2);
+    assert!(c == 3);
+    assert!(d == 4);
+
+    println!("a: {:?}, b: {:?}, c: {:?}, d: {:?}",
+             a, b, c, d)
+}
+
+#[inline(never)]
+#[cfg(target_arch = "x86")]
+#[cfg(target_arch = "arm")]
+pub extern fn foo(a: int, b: int, c: int, d: int) {
+    assert!(a == 1);
+    assert!(b == 2);
+    assert!(c == 3);
+    assert!(d == 4);
+
+    println!("a: {:?}, b: {:?}, c: {:?}, d: {:?}",
+             a, b, c, d)
+}
diff --git a/src/test/run-pass/extern-calling-convention-test.rs b/src/test/run-pass/extern-calling-convention-test.rs
new file mode 100644
index 00000000000..e8609a8b60b
--- /dev/null
+++ b/src/test/run-pass/extern-calling-convention-test.rs
@@ -0,0 +1,20 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast: aux-build not compatible with fast
+// aux-build:extern_calling_convention.rs
+
+extern mod extern_calling_convention;
+
+use extern_calling_convention::foo;
+
+fn main() {
+    foo(1, 2, 3, 4);
+}