rustc: Make rust-intrinsics take an explicit return pointer

This commit is contained in:
Patrick Walton 2011-07-09 21:13:25 -07:00
parent e823ca4965
commit f42c94740a
5 changed files with 133 additions and 48 deletions

View file

@ -8878,31 +8878,44 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
// wide. This is obviously wildly unsafe. We should have a better FFI
// that allows types of different sizes to be returned.
auto rty_is_nil =
ty::type_is_nil(ccx.tcx, ty::ty_fn_ret(ccx.tcx, fn_type));
auto rty = ty::ty_fn_ret(ccx.tcx, fn_type);
auto rty_is_nil = ty::type_is_nil(ccx.tcx, rty);
auto pass_task;
auto uses_retptr;
auto cast_to_i32;
alt (abi) {
case (ast::native_abi_rust) { pass_task = true; cast_to_i32 = true; }
case (ast::native_abi_rust_intrinsic) {
pass_task = true;
cast_to_i32 = false;
}
case (ast::native_abi_cdecl) {
pass_task = false;
cast_to_i32 = true;
}
case (ast::native_abi_llvm) {
pass_task = false;
cast_to_i32 = false;
}
case (ast::native_abi_rust) {
pass_task = true;
uses_retptr = false;
cast_to_i32 = true;
}
case (ast::native_abi_rust_intrinsic) {
pass_task = true;
uses_retptr = true;
cast_to_i32 = false;
}
case (ast::native_abi_cdecl) {
pass_task = false;
uses_retptr = false;
cast_to_i32 = true;
}
case (ast::native_abi_llvm) {
pass_task = false;
uses_retptr = false;
cast_to_i32 = false;
}
}
auto lltaskptr;
if (cast_to_i32) {
lltaskptr = vp2i(bcx, fcx.lltaskptr);
} else { lltaskptr = fcx.lltaskptr; }
let ValueRef[] call_args = ~[];
if (pass_task) { call_args += ~[lltaskptr]; }
if (uses_retptr) { call_args += ~[bcx.fcx.llretptr]; }
auto arg_n = 3u;
for each (uint i in uint::range(0u, num_ty_param)) {
auto llarg = llvm::LLVMGetParam(fcx.llfn, arg_n);
@ -8931,16 +8944,25 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
}
ret vp2i(cx, v);
}
fn trans_simple_native_abi(&@block_ctxt bcx, str name,
&mutable ValueRef[] call_args,
ty::t fn_type, uint first_arg_n) ->
ty::t fn_type, uint first_arg_n,
bool uses_retptr) ->
tup(ValueRef, ValueRef) {
let TypeRef[] call_arg_tys = ~[];
for (ValueRef arg in call_args) { call_arg_tys += ~[val_ty(arg)]; }
auto llnativefnty =
T_fn(call_arg_tys,
type_of(bcx.fcx.lcx.ccx, bcx.sp,
ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
auto llnativefnty;
if (uses_retptr) {
llnativefnty = T_fn(call_arg_tys, T_void());
} else {
llnativefnty =
T_fn(call_arg_tys,
type_of(bcx.fcx.lcx.ccx, bcx.sp,
ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
}
auto llnativefn =
get_extern_fn(bcx.fcx.lcx.ccx.externs, bcx.fcx.lcx.ccx.llmod,
name, lib::llvm::LLVMCCallConv, llnativefnty);
@ -8948,6 +8970,7 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
auto rptr = bcx.fcx.llretptr;
ret tup(r, rptr);
}
auto args = ty::ty_fn_args(ccx.tcx, fn_type);
// Build up the list of arguments.
@ -8970,7 +8993,8 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
alt (abi) {
case (ast::native_abi_llvm) {
auto result =
trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n);
trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n,
uses_retptr);
r = result._0;
rptr = result._1;
}
@ -8978,7 +9002,7 @@ 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);
fn_type, arg_n, uses_retptr);
r = result._0;
rptr = result._1;
}
@ -8994,7 +9018,8 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
// pointer. This is the only concession made to non-i32 return values. See
// the FIXME above.
if (!rty_is_nil) { bcx.build.Store(r, rptr); }
if (!rty_is_nil && !uses_retptr) { bcx.build.Store(r, rptr); }
for (tup(ValueRef, ty::t) d in drop_args) {
bcx = drop_ty(bcx, d._0, d._1).bcx;
}

View file

@ -7,7 +7,7 @@ import uint::next_power_of_two;
type operator2[T,U,V] = fn(&T, &U) -> V;
native "rust-intrinsic" mod rusti {
fn ivec_len[T](&T[] v) -> uint;
fn ivec_len_2[T](&T[] v) -> uint;
}
native "rust" mod rustrt {
@ -32,7 +32,7 @@ fn to_ptr[T](&T[] v) -> *T {
}
fn len[T](&T[mutable?] v) -> uint {
ret rusti::ivec_len(v);
ret rusti::ivec_len_2(v);
}
type init_op[T] = fn(uint) -> T;

View file

@ -27,16 +27,37 @@ rust_intrinsic_ivec_len(rust_task *task, type_desc *ty, rust_ivec *v)
return fill / ty->size;
}
extern "C" void *
rust_intrinsic_ptr_offset(rust_task *task, type_desc *ty, void *ptr,
uintptr_t count)
extern "C" void
rust_intrinsic_vec_len_2(rust_task *task, size_t *retptr, type_desc *ty,
rust_vec *v)
{
return &((uint8_t *)ptr)[ty->size * count];
*retptr = v->fill / ty->size;
}
extern "C" void
rust_intrinsic_cast(rust_task *task, type_desc *t1, type_desc *t2, void *dest,
void *src)
rust_intrinsic_ivec_len_2(rust_task *task, size_t *retptr, type_desc *ty,
rust_ivec *v)
{
size_t fill;
if (v->fill)
fill = v->fill;
else if (v->payload.ptr)
fill = v->payload.ptr->fill;
else
fill = 0;
*retptr = fill / ty->size;
}
extern "C" void
rust_intrinsic_ptr_offset(rust_task *task, void **retptr, type_desc *ty,
void *ptr, uintptr_t count)
{
*retptr = &((uint8_t *)ptr)[ty->size * count];
}
extern "C" void
rust_intrinsic_cast(rust_task *task, void *retptr, type_desc *t1,
type_desc *t2, void *src)
{
if (t1->size != t2->size) {
upcall_fail(task, "attempt to cast values of differing sizes",
@ -44,6 +65,6 @@ rust_intrinsic_cast(rust_task *task, type_desc *t1, type_desc *t2, void *dest,
return;
}
memmove(dest, src, t1->size);
memmove(retptr, src, t1->size);
}

View file

@ -100,16 +100,55 @@ if.end17: ; preds = %if.else, %entry, %i
ret i32 %div
}
define linkonce_odr i8* @rust_intrinsic_ptr_offset(%struct.rust_task* nocapture %task, %struct.type_desc* nocapture %ty, i8* %ptr, i32 %count) nounwind readonly {
define linkonce_odr void @rust_intrinsic_vec_len_2(%struct.rust_task* nocapture %task, i32* nocapture %retptr, %struct.type_desc* nocapture %ty, %struct.rust_vec* nocapture %v) nounwind {
entry:
%fill = getelementptr inbounds %struct.rust_vec* %v, i32 0, i32 2
%tmp1 = load i32* %fill, align 4, !tbaa !0
%size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
%tmp3 = load i32* %size, align 4, !tbaa !0
%div = udiv i32 %tmp1, %tmp3
store i32 %div, i32* %retptr, align 4, !tbaa !0
ret void
}
define linkonce_odr void @rust_intrinsic_ivec_len_2(%struct.rust_task* nocapture %task, i32* nocapture %retptr, %struct.type_desc* nocapture %ty, %struct.rust_ivec* nocapture %v) nounwind {
entry:
%fill1 = getelementptr inbounds %struct.rust_ivec* %v, i32 0, i32 0
%tmp2 = load i32* %fill1, align 4, !tbaa !0
%tobool = icmp eq i32 %tmp2, 0
br i1 %tobool, label %if.else, label %if.end17
if.else: ; preds = %entry
%ptr = getelementptr inbounds %struct.rust_ivec* %v, i32 0, i32 2, i32 0
%tmp7 = load %struct.rust_ivec_heap** %ptr, align 4, !tbaa !3
%tobool8 = icmp eq %struct.rust_ivec_heap* %tmp7, null
br i1 %tobool8, label %if.end17, label %if.then9
if.then9: ; preds = %if.else
%fill14 = getelementptr inbounds %struct.rust_ivec_heap* %tmp7, i32 0, i32 0
%tmp15 = load i32* %fill14, align 4, !tbaa !0
br label %if.end17
if.end17: ; preds = %if.else, %entry, %if.then9
%fill.0 = phi i32 [ %tmp15, %if.then9 ], [ %tmp2, %entry ], [ 0, %if.else ]
%size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
%tmp20 = load i32* %size, align 4, !tbaa !0
%div = udiv i32 %fill.0, %tmp20
store i32 %div, i32* %retptr, align 4, !tbaa !0
ret void
}
define linkonce_odr void @rust_intrinsic_ptr_offset(%struct.rust_task* nocapture %task, i8** nocapture %retptr, %struct.type_desc* nocapture %ty, i8* %ptr, i32 %count) nounwind {
entry:
%size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
%tmp1 = load i32* %size, align 4, !tbaa !0
%mul = mul i32 %tmp1, %count
%arrayidx = getelementptr inbounds i8* %ptr, i32 %mul
ret i8* %arrayidx
store i8* %arrayidx, i8** %retptr, align 4, !tbaa !3
ret void
}
define linkonce_odr void @rust_intrinsic_cast(%struct.rust_task* %task, %struct.type_desc* nocapture %t1, %struct.type_desc* nocapture %t2, i8* nocapture %dest, i8* nocapture %src) {
define linkonce_odr void @rust_intrinsic_cast(%struct.rust_task* %task, i8* nocapture %retptr, %struct.type_desc* nocapture %t1, %struct.type_desc* nocapture %t2, i8* nocapture %src) {
entry:
%size = getelementptr inbounds %struct.type_desc* %t1, i32 0, i32 1
%tmp1 = load i32* %size, align 4, !tbaa !0
@ -119,11 +158,11 @@ entry:
br i1 %cmp, label %if.end, label %if.then
if.then: ; preds = %entry
tail call void @upcall_fail(%struct.rust_task* %task, i8* getelementptr inbounds ([42 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8]* @.str1, i32 0, i32 0), i32 43)
tail call void @upcall_fail(%struct.rust_task* %task, i8* getelementptr inbounds ([42 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8]* @.str1, i32 0, i32 0), i32 64)
br label %return
if.end: ; preds = %entry
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %tmp1, i32 1, i1 false)
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %retptr, i8* %src, i32 %tmp1, i32 1, i1 false)
br label %return
return: ; preds = %if.end, %if.then

View file

@ -1,31 +1,31 @@
// xfail-stage0
import rusti::ivec_len;
import rusti::ivec_len_2;
native "rust-intrinsic" mod rusti {
fn ivec_len[T](&T[] v) -> uint;
fn ivec_len_2[T](&T[] v) -> uint;
}
fn main() {
let int[] v = ~[];
assert (ivec_len(v) == 0u); // zero-length
assert (ivec_len_2(v) == 0u); // zero-length
auto x = ~[ 1, 2 ];
assert (ivec_len(x) == 2u); // on stack
assert (ivec_len_2(x) == 2u); // on stack
auto y = ~[ 1, 2, 3, 4, 5 ];
assert (ivec_len(y) == 5u); // on heap
assert (ivec_len_2(y) == 5u); // on heap
v += ~[];
assert (ivec_len(v) == 0u); // zero-length append
assert (ivec_len_2(v) == 0u); // zero-length append
x += ~[ 3 ];
assert (ivec_len(x) == 3u); // on-stack append
assert (ivec_len_2(x) == 3u); // on-stack append
y += ~[ 6, 7, 8, 9 ];
assert (ivec_len(y) == 9u); // on-heap append
assert (ivec_len_2(y) == 9u); // on-heap append
auto vv = v + v;
assert (ivec_len(vv) == 0u); // zero-length add
assert (ivec_len_2(vv) == 0u); // zero-length add
auto xx = x + ~[ 4 ];
assert (ivec_len(xx) == 4u); // on-stack add
assert (ivec_len_2(xx) == 4u); // on-stack add
auto yy = y + ~[ 10, 11 ];
assert (ivec_len(yy) == 11u); // on-heap add
assert (ivec_len_2(yy) == 11u); // on-heap add
}