Support x86 stdcall convention
This allows rust to call the Win32 API
This commit is contained in:
parent
682875929e
commit
c40d6265ce
@ -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(""));
|
||||
|
@ -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);
|
||||
|
@ -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, ~[]);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -526,6 +526,7 @@ tag native_abi {
|
||||
native_abi_cdecl;
|
||||
native_abi_llvm;
|
||||
native_abi_rust_intrinsic;
|
||||
native_abi_x86stdcall;
|
||||
}
|
||||
|
||||
type native_mod =
|
||||
|
@ -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");
|
||||
|
21
src/test/run-pass/x86stdcall.rs
Normal file
21
src/test/run-pass/x86stdcall.rs
Normal file
@ -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() {
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user