aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-11-24 16:55:45 -0800
committerGraydon Hoare <[email protected]>2010-11-24 16:56:01 -0800
commitf809375b163bb108d9193f456f44ca663874380b (patch)
treea69731ced25908781c280ef893c073d534edea9f /src
parentmove expr_call translation into helper function. (diff)
downloadrust-f809375b163bb108d9193f456f44ca663874380b.tar.xz
rust-f809375b163bb108d9193f456f44ca663874380b.zip
Sketch out type-directed structural drop and copy, including vector types.
Diffstat (limited to 'src')
-rw-r--r--src/comp/lib/llvm.rs10
-rw-r--r--src/comp/middle/trans.rs224
-rw-r--r--src/comp/middle/typeck.rs31
3 files changed, 237 insertions, 28 deletions
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index da48c6b5..0db40e89 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -1019,6 +1019,16 @@ obj builder(BuilderRef B) {
ret phi;
}
+ fn AddIncomingToPhi(ValueRef phi,
+ vec[ValueRef] vals,
+ vec[BasicBlockRef] bbs) {
+ check (_vec.len[ValueRef](vals) == _vec.len[BasicBlockRef](bbs));
+ llvm.LLVMAddIncoming(phi,
+ _vec.buf[ValueRef](vals),
+ _vec.buf[BasicBlockRef](bbs),
+ _vec.len[ValueRef](vals));
+ }
+
fn Call(ValueRef Fn, vec[ValueRef] Args) -> ValueRef {
ret llvm.LLVMBuildCall(B, Fn,
_vec.buf[ValueRef](Args),
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index f323d306..6f0e6a63 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -479,38 +479,202 @@ fn decr_refcnt_and_if_zero(@block_ctxt cx,
ret res(next_cx, phi);
}
-fn type_is_scalar(@ast.ty t) -> bool {
- alt (t.node) {
- case (ast.ty_nil) { ret true; }
- case (ast.ty_bool) { ret true; }
- case (ast.ty_int) { ret true; }
- case (ast.ty_uint) { ret true; }
- case (ast.ty_machine(_)) { ret true; }
- case (ast.ty_char) { ret true; }
+type val_and_ty_fn =
+ fn(@block_ctxt cx, ValueRef v, @typeck.ty t) -> result;
+
+// Iterates through the elements of a tup, rec or tag.
+fn iter_structural_ty(@block_ctxt cx,
+ ValueRef v,
+ @typeck.ty t,
+ val_and_ty_fn f)
+ -> result {
+ let result r = res(cx, C_nil());
+ alt (t.struct) {
+ case (typeck.ty_tup(?args)) {
+ let int i = 0;
+ for (tup(bool, @typeck.ty) arg in args) {
+ auto elt = r.bcx.build.GEP(v, vec(C_int(0), C_int(i)));
+ r = f(r.bcx, elt, arg._1);
+ i += 1;
+ }
+ }
+ // FIXME: handle records and tags when we support them.
}
- ret false;
+ ret r;
}
-fn trans_copy_ty(@block_ctxt cx,
- bool is_init,
- ValueRef dst,
- ValueRef src,
- @ast.ty t) -> result {
- if (type_is_scalar(t)) {
- ret res(cx, cx.build.Store(src, dst));
+// Iterates through the elements of a vec or str.
+fn iter_sequence(@block_ctxt cx,
+ ValueRef v,
+ @typeck.ty ty,
+ val_and_ty_fn f) -> result {
+
+ fn iter_sequence_body(@block_ctxt cx,
+ ValueRef v,
+ @typeck.ty elt_ty,
+ val_and_ty_fn f,
+ bool trailing_null) -> result {
+
+ auto p0 = cx.build.GEP(v, vec(C_int(0),
+ C_int(abi.vec_elt_data)));
+ auto lenptr = cx.build.GEP(v, vec(C_int(0),
+ C_int(abi.vec_elt_fill)));
+ auto len = cx.build.Load(lenptr);
+ if (trailing_null) {
+ len = cx.build.Sub(len, C_int(1));
+ }
+
+ auto r = res(cx, C_nil());
+
+ auto cond_cx = new_sub_block_ctxt(cx, "sequence-iter cond");
+ auto body_cx = new_sub_block_ctxt(cx, "sequence-iter body");
+ auto next_cx = new_sub_block_ctxt(cx, "next");
+
+ auto ix = cond_cx.build.Phi(T_int(), vec(C_int(0)), vec(cx.llbb));
+ auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntEQ, ix, len);
+ cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);
+
+ auto elt = body_cx.build.GEP(p0, vec(ix));
+ auto body_res = f(body_cx, elt, elt_ty);
+ auto next_ix = body_res.bcx.build.Add(ix, C_int(1));
+ cond_cx.build.AddIncomingToPhi(ix, vec(next_ix),
+ vec(body_res.bcx.llbb));
+
+ body_res.bcx.build.Br(cond_cx.llbb);
+ ret res(next_cx, C_nil());
+ }
+
+ alt (ty.struct) {
+ case (typeck.ty_vec(?et)) {
+ ret iter_sequence_body(cx, v, et, f, false);
+ }
+ case (typeck.ty_str) {
+ auto et = typeck.plain_ty(typeck.ty_machine(common.ty_u8));
+ ret iter_sequence_body(cx, v, et, f, false);
+ }
}
+ cx.fcx.ccx.sess.bug("bad type in trans.iter_sequence");
+ fail;
+}
+
+fn incr_all_refcnts(@block_ctxt cx,
+ ValueRef v,
+ @typeck.ty t) -> result {
- alt (t.node) {
- case (ast.ty_str) {
- let result r = res(cx, C_nil());
- if (is_init) {
- r = trans_drop_str(cx, dst);
+ if (typeck.type_is_boxed(t)) {
+ ret incr_refcnt(cx, v);
+
+ } else if (typeck.type_is_binding(t)) {
+ cx.fcx.ccx.sess.unimpl("binding type in trans.incr_all_refcnts");
+
+ } else if (typeck.type_is_structural(t)) {
+ ret iter_structural_ty(cx, v, t,
+ bind incr_all_refcnts(_, _, _));
+ }
+}
+
+fn drop_ty(@block_ctxt cx,
+ ValueRef v,
+ @typeck.ty t) -> result {
+
+ alt (t.struct) {
+ case (typeck.ty_str) {
+ ret decr_refcnt_and_if_zero(cx, v,
+ bind trans_non_gc_free(_, v),
+ "free string",
+ T_int(), C_int(0));
+ }
+
+ case (typeck.ty_vec(_)) {
+ fn hit_zero(@block_ctxt cx, ValueRef v,
+ @typeck.ty t) -> result {
+ auto res = iter_sequence(cx, v, t, bind drop_ty(_,_,_));
+ // FIXME: switch gc/non-gc on stratum of the type.
+ ret trans_non_gc_free(res.bcx, v);
+ }
+ ret decr_refcnt_and_if_zero(cx, v,
+ bind hit_zero(_, v, t),
+ "free vector",
+ T_int(), C_int(0));
+ }
+
+ case (typeck.ty_box(_)) {
+ fn hit_zero(@block_ctxt cx, ValueRef v,
+ @typeck.ty elt_ty) -> result {
+ auto res = drop_ty(cx,
+ cx.build.GEP(v, vec(C_int(0))),
+ elt_ty);
+ // FIXME: switch gc/non-gc on stratum of the type.
+ ret trans_non_gc_free(res.bcx, v);
+ }
+ ret incr_refcnt(cx, v);
+ }
+
+ case (_) {
+ if (typeck.type_is_structural(t)) {
+ ret iter_structural_ty(cx, v, t,
+ bind drop_ty(_, _, _));
+
+ } else if (typeck.type_is_binding(t)) {
+ cx.fcx.ccx.sess.unimpl("binding type in trans.drop_ty");
+
+ } else if (typeck.type_is_scalar(t) ||
+ typeck.type_is_nil(t)) {
+ ret res(cx, C_nil());
}
- r = incr_refcnt(r.bcx, src);
- ret res(r.bcx, r.bcx.build.Store(src, dst));
}
}
- cx.fcx.ccx.sess.unimpl("ty variant in trans_copy_ty");
+ cx.fcx.ccx.sess.bug("bad type in trans.drop_ty");
+ fail;
+}
+
+fn build_memcpy(@block_ctxt cx,
+ ValueRef dst,
+ ValueRef src,
+ TypeRef llty) -> result {
+ auto memcpy = cx.fcx.ccx.fn_names.get("llvm.memcpy");
+ auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
+ auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
+ auto size = lib.llvm.llvm.LLVMSizeOf(llty);
+ auto align = lib.llvm.llvm.LLVMAlignOf(llty);
+ auto volatile = C_integral(0, T_i1());
+ ret res(cx, cx.build.Call(memcpy,
+ vec(dst_ptr, src_ptr,
+ size, align, volatile)));
+}
+
+fn copy_ty(@block_ctxt cx,
+ bool is_init,
+ ValueRef dst,
+ ValueRef src,
+ @typeck.ty t) -> result {
+ if (typeck.type_is_scalar(t)) {
+ ret res(cx, cx.build.Store(src, dst));
+
+ } else if (typeck.type_is_nil(t)) {
+ ret res(cx, C_nil());
+
+ } else if (typeck.type_is_binding(t)) {
+ cx.fcx.ccx.sess.unimpl("binding type in trans.copy_ty");
+
+ } else if (typeck.type_is_boxed(t)) {
+ auto r = incr_refcnt(cx, src);
+ if (! is_init) {
+ r = drop_ty(r.bcx, dst, t);
+ }
+ ret res(r.bcx, r.bcx.build.Store(src, dst));
+
+ } else if (typeck.type_is_structural(t)) {
+ auto r = incr_all_refcnts(cx, src, t);
+ if (! is_init) {
+ r = drop_ty(r.bcx, dst, t);
+ }
+ auto llty = type_of(cx.fcx.ccx, t);
+ r = build_memcpy(r.bcx, dst, src, llty);
+ }
+
+ cx.fcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
+ typeck.ty_to_str(t));
fail;
}
@@ -1023,13 +1187,12 @@ impure fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
}
}
- case (ast.expr_assign(?dst, ?src, _)) {
+ case (ast.expr_assign(?dst, ?src, ?ann)) {
auto lhs_res = trans_lval(cx, *dst);
check (lhs_res._1);
auto rhs_res = trans_expr(lhs_res._0.bcx, *src);
- // FIXME: call trans_copy_ty once we have a ty here.
- ret res(rhs_res.bcx,
- rhs_res.bcx.build.Store(rhs_res.val, lhs_res._0.val));
+ auto t = node_ann_type(cx.fcx.ccx, ann);
+ ret copy_ty(rhs_res.bcx, true, lhs_res._0.val, rhs_res.val, t);
}
case (ast.expr_call(?f, ?args, _)) {
@@ -1451,7 +1614,12 @@ fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
fn declare_intrinsics(ModuleRef llmod) {
let vec[TypeRef] T_trap_args = vec();
+ // FIXME: switch this to 64-bit memcpy when targeting a 64-bit system.
+ let vec[TypeRef] T_memcpy_args = vec(T_ptr(T_i8()),
+ T_ptr(T_i8()),
+ T_i32(), T_i32(), T_i1());
decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void()));
+ decl_cdecl_fn(llmod, "llvm.memcpy", T_fn(T_memcpy_args, T_void()));
}
fn trans_crate(session.session sess, @ast.crate crate, str output) {
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index c7bd36b7..530bdc06 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -412,6 +412,37 @@ fn mode_is_alias(ast.mode m) -> bool {
}
}
+fn type_is_nil(@ty t) -> bool {
+ alt (t.struct) {
+ case (ty_nil) { ret true; }
+ }
+ ret false;
+}
+
+fn type_is_structural(@ty t) -> bool {
+ alt (t.struct) {
+ // FIXME: cover rec and tag when we support them.
+ case (ty_tup(_)) { ret true; }
+ }
+ ret false;
+}
+
+fn type_is_binding(@ty t) -> bool {
+ alt (t.struct) {
+ // FIXME: cover obj when we support it.
+ case (ty_fn(_,_)) { ret true; }
+ }
+ ret false;
+}
+
+fn type_is_boxed(@ty t) -> bool {
+ alt (t.struct) {
+ case (ty_str) { ret true; }
+ case (ty_vec(_)) { ret true; }
+ }
+ ret false;
+}
+
fn type_is_scalar(@ty t) -> bool {
alt (t.struct) {
case (ty_bool) { ret true; }