about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-07-18 13:14:33 -0700
committerBrian Anderson <banderson@mozilla.com>2011-07-18 13:56:15 -0700
commitc40d6265ce2ae093b3bb9e15177f60b375a158fa (patch)
tree6e189545311d1b6e2c46a3aa0cd4b623327dfd44
parent682875929efe558b42318d6ae8b2ef8dc625e94a (diff)
downloadrust-c40d6265ce2ae093b3bb9e15177f60b375a158fa.tar.gz
rust-c40d6265ce2ae093b3bb9e15177f60b375a158fa.zip
Support x86 stdcall convention
This allows rust to call the Win32 API
-rw-r--r--src/comp/lib/llvm.rs9
-rw-r--r--src/comp/metadata/tydecode.rs1
-rw-r--r--src/comp/metadata/tyencode.rs1
-rw-r--r--src/comp/middle/trans.rs32
-rw-r--r--src/comp/syntax/ast.rs1
-rw-r--r--src/comp/syntax/parse/parser.rs2
-rw-r--r--src/test/run-pass/x86stdcall.rs21
7 files changed, 61 insertions, 6 deletions
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index 2f0abed3d27..bb7dd4f2621 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -1314,6 +1314,15 @@ obj builder(BuilderRef B, @mutable bool terminated) {
         ret v;
     }
 
+    fn CallWithConv(ValueRef Fn, &ValueRef[] Args,
+                    uint Conv) -> ValueRef {
+        assert !(*terminated);
+        auto v = llvm::LLVMBuildCall(B, Fn, ivec::to_ptr(Args),
+                                     ivec::len(Args), str::buf(""));
+        llvm::LLVMSetInstructionCallConv(v, Conv);
+        ret v;
+    }
+
     fn Select(ValueRef If, ValueRef Then, ValueRef Else) -> ValueRef {
         assert (!*terminated);
         ret llvm::LLVMBuildSelect(B, If, Then, Else, str::buf(""));
diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs
index b4d96d17a3e..2804c530240 100644
--- a/src/comp/metadata/tydecode.rs
+++ b/src/comp/metadata/tydecode.rs
@@ -221,6 +221,7 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
                 case ('i') { abi = ast::native_abi_rust_intrinsic; }
                 case ('c') { abi = ast::native_abi_cdecl; }
                 case ('l') { abi = ast::native_abi_llvm; }
+                case ('s') { abi = ast::native_abi_x86stdcall; }
             }
             auto func = parse_ty_fn(st, sd);
             ret ty::mk_native_fn(st.tcx, abi, func._0, func._1);
diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs
index 4d7e1b8ac18..3b3ce6b3866 100644
--- a/src/comp/metadata/tyencode.rs
+++ b/src/comp/metadata/tyencode.rs
@@ -155,6 +155,7 @@ fn enc_sty(&ioivec::writer w, &@ctxt cx, &ty::sty st) {
                 }
                 case (native_abi_cdecl) { w.write_char('c'); }
                 case (native_abi_llvm) { w.write_char('l'); }
+                case (native_abi_x86stdcall) { w.write_char('s'); }
             }
             enc_ty_fn(w, cx, args, out, return, ~[]);
         }
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 2493569567d..68a5823a761 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -751,7 +751,8 @@ fn trans_native_call(&builder b, @glue_fns glues, ValueRef lltaskptr,
                      ModuleRef llmod, &str name, bool pass_task,
                      &ValueRef[] args) -> ValueRef {
     let int n = std::ivec::len[ValueRef](args) as int;
-    let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
+    let ValueRef llnative = get_simple_extern_fn(externs, llmod,
+                                                 name, n);
     let ValueRef[] call_args = ~[];
     for (ValueRef a in args) { call_args += ~[b.ZExtOrBitCast(a, T_int())]; }
     ret b.Call(llnative, call_args);
@@ -8142,6 +8143,11 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
         uses_retptr = false;
         cast_to_i32 = false;
       }
+      case (ast::native_abi_x86stdcall) {
+        pass_task = false;
+        uses_retptr = false;
+        cast_to_i32 = true;
+      }
     }
 
     auto lltaskptr;
@@ -8185,7 +8191,7 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
     fn trans_simple_native_abi(&@block_ctxt bcx, str name,
                                &mutable ValueRef[] call_args,
                                ty::t fn_type, uint first_arg_n,
-                               bool uses_retptr) ->
+                               bool uses_retptr, uint cc) ->
        tup(ValueRef, ValueRef) {
         let TypeRef[] call_arg_tys = ~[];
         for (ValueRef arg in call_args) { call_arg_tys += ~[val_ty(arg)]; }
@@ -8202,8 +8208,12 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
 
         auto llnativefn =
             get_extern_fn(bcx.fcx.lcx.ccx.externs, bcx.fcx.lcx.ccx.llmod,
-                          name, lib::llvm::LLVMCCallConv, llnativefnty);
-        auto r = bcx.build.Call(llnativefn, call_args);
+                          name, cc, llnativefnty);
+        auto r = if (cc == lib::llvm::LLVMCCallConv) {
+            bcx.build.Call(llnativefn, call_args)
+        } else {
+            bcx.build.CallWithConv(llnativefn, call_args, cc)
+        };
         auto rptr = bcx.fcx.llretptr;
         ret tup(r, rptr);
     }
@@ -8231,7 +8241,8 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
         case (ast::native_abi_llvm) {
             auto result =
                 trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n,
-                                        uses_retptr);
+                                        uses_retptr,
+                                        lib::llvm::LLVMCCallConv);
             r = result._0;
             rptr = result._1;
         }
@@ -8239,7 +8250,16 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
             auto external_name = "rust_intrinsic_" + name;
             auto result =
                 trans_simple_native_abi(bcx, external_name, call_args,
-                                        fn_type, arg_n, uses_retptr);
+                                        fn_type, arg_n, uses_retptr,
+                                        lib::llvm::LLVMCCallConv);
+            r = result._0;
+            rptr = result._1;
+        }
+        case (ast::native_abi_x86stdcall) {
+            auto result =
+                trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n,
+                                        uses_retptr,
+                                        lib::llvm::LLVMX86StdcallCallConv);
             r = result._0;
             rptr = result._1;
         }
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index fd5a308cbb8..745aa4e1fcd 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -526,6 +526,7 @@ tag native_abi {
     native_abi_cdecl;
     native_abi_llvm;
     native_abi_rust_intrinsic;
+    native_abi_x86stdcall;
 }
 
 type native_mod =
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 183c9ce0c47..59dbf72f7c5 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -2004,6 +2004,8 @@ fn parse_item_native_mod(&parser p, &ast::attribute[] attrs) -> @ast::item {
             abi = ast::native_abi_llvm;
         } else if (str::eq(t, "rust-intrinsic")) {
             abi = ast::native_abi_rust_intrinsic;
+        } else if (str::eq(t, "x86stdcall")) {
+            abi = ast::native_abi_x86stdcall;
         } else { p.fatal("unsupported abi: " + t); fail; }
     }
     expect_word(p, "mod");
diff --git a/src/test/run-pass/x86stdcall.rs b/src/test/run-pass/x86stdcall.rs
new file mode 100644
index 00000000000..0b61ddaff28
--- /dev/null
+++ b/src/test/run-pass/x86stdcall.rs
@@ -0,0 +1,21 @@
+// xfail-stage0
+
+#[cfg(target_os = "win32")]
+mod m {
+    native "x86stdcall" mod kernel32 {
+        fn SetLastError(uint err);
+        fn GetLastError() -> uint;
+    }
+
+    fn main() {
+        auto expected = 10u;
+        kernel32::SetLastError(expected);
+        auto actual = kernel32::GetLastError();
+        assert expected == actual;
+    }
+}
+
+#[cfg(target_os = "macos")]
+#[cfg(target_os = "linux")]
+fn main() {
+}
\ No newline at end of file