From f42c94740a7aadcaaebc9e6fe8d798ce17fc24ee Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sat, 9 Jul 2011 21:13:25 -0700 Subject: [PATCH] rustc: Make rust-intrinsics take an explicit return pointer --- src/comp/middle/trans.rs | 71 ++++++++++++++++++++---------- src/lib/ivec.rs | 4 +- src/rt/intrinsics/intrinsics.cpp | 35 ++++++++++++--- src/rt/intrinsics/intrinsics.ll.in | 49 ++++++++++++++++++--- src/test/run-pass/interior-vec.rs | 22 ++++----- 5 files changed, 133 insertions(+), 48 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 3e882dac6b9..7170aac794a 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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; } diff --git a/src/lib/ivec.rs b/src/lib/ivec.rs index d34b54d68e4..54f0352b996 100644 --- a/src/lib/ivec.rs +++ b/src/lib/ivec.rs @@ -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; diff --git a/src/rt/intrinsics/intrinsics.cpp b/src/rt/intrinsics/intrinsics.cpp index a390abae370..5cd7ea99b02 100644 --- a/src/rt/intrinsics/intrinsics.cpp +++ b/src/rt/intrinsics/intrinsics.cpp @@ -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); } diff --git a/src/rt/intrinsics/intrinsics.ll.in b/src/rt/intrinsics/intrinsics.ll.in index a20ef07c218..7364cf670fd 100644 --- a/src/rt/intrinsics/intrinsics.ll.in +++ b/src/rt/intrinsics/intrinsics.ll.in @@ -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 diff --git a/src/test/run-pass/interior-vec.rs b/src/test/run-pass/interior-vec.rs index 7788b7aa6ed..a431e59dba1 100644 --- a/src/test/run-pass/interior-vec.rs +++ b/src/test/run-pass/interior-vec.rs @@ -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 }