Skip to content

Commit f42c947

Browse files
committed
rustc: Make rust-intrinsics take an explicit return pointer
1 parent e823ca4 commit f42c947

File tree

5 files changed

+133
-48
lines changed

5 files changed

+133
-48
lines changed

src/comp/middle/trans.rs

+48-23
Original file line numberDiff line numberDiff line change
@@ -8878,31 +8878,44 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
88788878
// wide. This is obviously wildly unsafe. We should have a better FFI
88798879
// that allows types of different sizes to be returned.
88808880

8881-
auto rty_is_nil =
8882-
ty::type_is_nil(ccx.tcx, ty::ty_fn_ret(ccx.tcx, fn_type));
8881+
auto rty = ty::ty_fn_ret(ccx.tcx, fn_type);
8882+
auto rty_is_nil = ty::type_is_nil(ccx.tcx, rty);
8883+
88838884
auto pass_task;
8885+
auto uses_retptr;
88848886
auto cast_to_i32;
88858887
alt (abi) {
8886-
case (ast::native_abi_rust) { pass_task = true; cast_to_i32 = true; }
8887-
case (ast::native_abi_rust_intrinsic) {
8888-
pass_task = true;
8889-
cast_to_i32 = false;
8890-
}
8891-
case (ast::native_abi_cdecl) {
8892-
pass_task = false;
8893-
cast_to_i32 = true;
8894-
}
8895-
case (ast::native_abi_llvm) {
8896-
pass_task = false;
8897-
cast_to_i32 = false;
8898-
}
8888+
case (ast::native_abi_rust) {
8889+
pass_task = true;
8890+
uses_retptr = false;
8891+
cast_to_i32 = true;
8892+
}
8893+
case (ast::native_abi_rust_intrinsic) {
8894+
pass_task = true;
8895+
uses_retptr = true;
8896+
cast_to_i32 = false;
8897+
}
8898+
case (ast::native_abi_cdecl) {
8899+
pass_task = false;
8900+
uses_retptr = false;
8901+
cast_to_i32 = true;
8902+
}
8903+
case (ast::native_abi_llvm) {
8904+
pass_task = false;
8905+
uses_retptr = false;
8906+
cast_to_i32 = false;
8907+
}
88998908
}
8909+
89008910
auto lltaskptr;
89018911
if (cast_to_i32) {
89028912
lltaskptr = vp2i(bcx, fcx.lltaskptr);
89038913
} else { lltaskptr = fcx.lltaskptr; }
8914+
89048915
let ValueRef[] call_args = ~[];
89058916
if (pass_task) { call_args += ~[lltaskptr]; }
8917+
if (uses_retptr) { call_args += ~[bcx.fcx.llretptr]; }
8918+
89068919
auto arg_n = 3u;
89078920
for each (uint i in uint::range(0u, num_ty_param)) {
89088921
auto llarg = llvm::LLVMGetParam(fcx.llfn, arg_n);
@@ -8931,23 +8944,33 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
89318944
}
89328945
ret vp2i(cx, v);
89338946
}
8947+
89348948
fn trans_simple_native_abi(&@block_ctxt bcx, str name,
89358949
&mutable ValueRef[] call_args,
8936-
ty::t fn_type, uint first_arg_n) ->
8950+
ty::t fn_type, uint first_arg_n,
8951+
bool uses_retptr) ->
89378952
tup(ValueRef, ValueRef) {
89388953
let TypeRef[] call_arg_tys = ~[];
89398954
for (ValueRef arg in call_args) { call_arg_tys += ~[val_ty(arg)]; }
8940-
auto llnativefnty =
8941-
T_fn(call_arg_tys,
8942-
type_of(bcx.fcx.lcx.ccx, bcx.sp,
8943-
ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
8955+
8956+
auto llnativefnty;
8957+
if (uses_retptr) {
8958+
llnativefnty = T_fn(call_arg_tys, T_void());
8959+
} else {
8960+
llnativefnty =
8961+
T_fn(call_arg_tys,
8962+
type_of(bcx.fcx.lcx.ccx, bcx.sp,
8963+
ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
8964+
}
8965+
89448966
auto llnativefn =
89458967
get_extern_fn(bcx.fcx.lcx.ccx.externs, bcx.fcx.lcx.ccx.llmod,
89468968
name, lib::llvm::LLVMCCallConv, llnativefnty);
89478969
auto r = bcx.build.Call(llnativefn, call_args);
89488970
auto rptr = bcx.fcx.llretptr;
89498971
ret tup(r, rptr);
89508972
}
8973+
89518974
auto args = ty::ty_fn_args(ccx.tcx, fn_type);
89528975
// Build up the list of arguments.
89538976

@@ -8970,15 +8993,16 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
89708993
alt (abi) {
89718994
case (ast::native_abi_llvm) {
89728995
auto result =
8973-
trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n);
8996+
trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n,
8997+
uses_retptr);
89748998
r = result._0;
89758999
rptr = result._1;
89769000
}
89779001
case (ast::native_abi_rust_intrinsic) {
89789002
auto external_name = "rust_intrinsic_" + name;
89799003
auto result =
89809004
trans_simple_native_abi(bcx, external_name, call_args,
8981-
fn_type, arg_n);
9005+
fn_type, arg_n, uses_retptr);
89829006
r = result._0;
89839007
rptr = result._1;
89849008
}
@@ -8994,7 +9018,8 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
89949018
// pointer. This is the only concession made to non-i32 return values. See
89959019
// the FIXME above.
89969020

8997-
if (!rty_is_nil) { bcx.build.Store(r, rptr); }
9021+
if (!rty_is_nil && !uses_retptr) { bcx.build.Store(r, rptr); }
9022+
89989023
for (tup(ValueRef, ty::t) d in drop_args) {
89999024
bcx = drop_ty(bcx, d._0, d._1).bcx;
90009025
}

src/lib/ivec.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import uint::next_power_of_two;
77
type operator2[T,U,V] = fn(&T, &U) -> V;
88

99
native "rust-intrinsic" mod rusti {
10-
fn ivec_len[T](&T[] v) -> uint;
10+
fn ivec_len_2[T](&T[] v) -> uint;
1111
}
1212

1313
native "rust" mod rustrt {
@@ -32,7 +32,7 @@ fn to_ptr[T](&T[] v) -> *T {
3232
}
3333

3434
fn len[T](&T[mutable?] v) -> uint {
35-
ret rusti::ivec_len(v);
35+
ret rusti::ivec_len_2(v);
3636
}
3737

3838
type init_op[T] = fn(uint) -> T;

src/rt/intrinsics/intrinsics.cpp

+28-7
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,44 @@ rust_intrinsic_ivec_len(rust_task *task, type_desc *ty, rust_ivec *v)
2727
return fill / ty->size;
2828
}
2929

30-
extern "C" void *
31-
rust_intrinsic_ptr_offset(rust_task *task, type_desc *ty, void *ptr,
32-
uintptr_t count)
30+
extern "C" void
31+
rust_intrinsic_vec_len_2(rust_task *task, size_t *retptr, type_desc *ty,
32+
rust_vec *v)
33+
{
34+
*retptr = v->fill / ty->size;
35+
}
36+
37+
extern "C" void
38+
rust_intrinsic_ivec_len_2(rust_task *task, size_t *retptr, type_desc *ty,
39+
rust_ivec *v)
40+
{
41+
size_t fill;
42+
if (v->fill)
43+
fill = v->fill;
44+
else if (v->payload.ptr)
45+
fill = v->payload.ptr->fill;
46+
else
47+
fill = 0;
48+
*retptr = fill / ty->size;
49+
}
50+
51+
extern "C" void
52+
rust_intrinsic_ptr_offset(rust_task *task, void **retptr, type_desc *ty,
53+
void *ptr, uintptr_t count)
3354
{
34-
return &((uint8_t *)ptr)[ty->size * count];
55+
*retptr = &((uint8_t *)ptr)[ty->size * count];
3556
}
3657

3758
extern "C" void
38-
rust_intrinsic_cast(rust_task *task, type_desc *t1, type_desc *t2, void *dest,
39-
void *src)
59+
rust_intrinsic_cast(rust_task *task, void *retptr, type_desc *t1,
60+
type_desc *t2, void *src)
4061
{
4162
if (t1->size != t2->size) {
4263
upcall_fail(task, "attempt to cast values of differing sizes",
4364
__FILE__, __LINE__);
4465
return;
4566
}
4667

47-
memmove(dest, src, t1->size);
68+
memmove(retptr, src, t1->size);
4869
}
4970

src/rt/intrinsics/intrinsics.ll.in

+44-5
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,55 @@ if.end17: ; preds = %if.else, %entry, %i
100100
ret i32 %div
101101
}
102102

103-
define linkonce_odr i8* @rust_intrinsic_ptr_offset(%struct.rust_task* nocapture %task, %struct.type_desc* nocapture %ty, i8* %ptr, i32 %count) nounwind readonly {
103+
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 {
104+
entry:
105+
%fill = getelementptr inbounds %struct.rust_vec* %v, i32 0, i32 2
106+
%tmp1 = load i32* %fill, align 4, !tbaa !0
107+
%size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
108+
%tmp3 = load i32* %size, align 4, !tbaa !0
109+
%div = udiv i32 %tmp1, %tmp3
110+
store i32 %div, i32* %retptr, align 4, !tbaa !0
111+
ret void
112+
}
113+
114+
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 {
115+
entry:
116+
%fill1 = getelementptr inbounds %struct.rust_ivec* %v, i32 0, i32 0
117+
%tmp2 = load i32* %fill1, align 4, !tbaa !0
118+
%tobool = icmp eq i32 %tmp2, 0
119+
br i1 %tobool, label %if.else, label %if.end17
120+
121+
if.else: ; preds = %entry
122+
%ptr = getelementptr inbounds %struct.rust_ivec* %v, i32 0, i32 2, i32 0
123+
%tmp7 = load %struct.rust_ivec_heap** %ptr, align 4, !tbaa !3
124+
%tobool8 = icmp eq %struct.rust_ivec_heap* %tmp7, null
125+
br i1 %tobool8, label %if.end17, label %if.then9
126+
127+
if.then9: ; preds = %if.else
128+
%fill14 = getelementptr inbounds %struct.rust_ivec_heap* %tmp7, i32 0, i32 0
129+
%tmp15 = load i32* %fill14, align 4, !tbaa !0
130+
br label %if.end17
131+
132+
if.end17: ; preds = %if.else, %entry, %if.then9
133+
%fill.0 = phi i32 [ %tmp15, %if.then9 ], [ %tmp2, %entry ], [ 0, %if.else ]
134+
%size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
135+
%tmp20 = load i32* %size, align 4, !tbaa !0
136+
%div = udiv i32 %fill.0, %tmp20
137+
store i32 %div, i32* %retptr, align 4, !tbaa !0
138+
ret void
139+
}
140+
141+
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 {
104142
entry:
105143
%size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
106144
%tmp1 = load i32* %size, align 4, !tbaa !0
107145
%mul = mul i32 %tmp1, %count
108146
%arrayidx = getelementptr inbounds i8* %ptr, i32 %mul
109-
ret i8* %arrayidx
147+
store i8* %arrayidx, i8** %retptr, align 4, !tbaa !3
148+
ret void
110149
}
111150

112-
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) {
151+
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) {
113152
entry:
114153
%size = getelementptr inbounds %struct.type_desc* %t1, i32 0, i32 1
115154
%tmp1 = load i32* %size, align 4, !tbaa !0
@@ -119,11 +158,11 @@ entry:
119158
br i1 %cmp, label %if.end, label %if.then
120159

121160
if.then: ; preds = %entry
122-
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)
161+
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)
123162
br label %return
124163

125164
if.end: ; preds = %entry
126-
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %tmp1, i32 1, i1 false)
165+
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %retptr, i8* %src, i32 %tmp1, i32 1, i1 false)
127166
br label %return
128167

129168
return: ; preds = %if.end, %if.then

src/test/run-pass/interior-vec.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
// xfail-stage0
22

3-
import rusti::ivec_len;
3+
import rusti::ivec_len_2;
44

55
native "rust-intrinsic" mod rusti {
6-
fn ivec_len[T](&T[] v) -> uint;
6+
fn ivec_len_2[T](&T[] v) -> uint;
77
}
88

99
fn main() {
1010
let int[] v = ~[];
11-
assert (ivec_len(v) == 0u); // zero-length
11+
assert (ivec_len_2(v) == 0u); // zero-length
1212
auto x = ~[ 1, 2 ];
13-
assert (ivec_len(x) == 2u); // on stack
13+
assert (ivec_len_2(x) == 2u); // on stack
1414
auto y = ~[ 1, 2, 3, 4, 5 ];
15-
assert (ivec_len(y) == 5u); // on heap
15+
assert (ivec_len_2(y) == 5u); // on heap
1616

1717
v += ~[];
18-
assert (ivec_len(v) == 0u); // zero-length append
18+
assert (ivec_len_2(v) == 0u); // zero-length append
1919
x += ~[ 3 ];
20-
assert (ivec_len(x) == 3u); // on-stack append
20+
assert (ivec_len_2(x) == 3u); // on-stack append
2121
y += ~[ 6, 7, 8, 9 ];
22-
assert (ivec_len(y) == 9u); // on-heap append
22+
assert (ivec_len_2(y) == 9u); // on-heap append
2323

2424
auto vv = v + v;
25-
assert (ivec_len(vv) == 0u); // zero-length add
25+
assert (ivec_len_2(vv) == 0u); // zero-length add
2626
auto xx = x + ~[ 4 ];
27-
assert (ivec_len(xx) == 4u); // on-stack add
27+
assert (ivec_len_2(xx) == 4u); // on-stack add
2828
auto yy = y + ~[ 10, 11 ];
29-
assert (ivec_len(yy) == 11u); // on-heap add
29+
assert (ivec_len_2(yy) == 11u); // on-heap add
3030
}
3131

0 commit comments

Comments
 (0)