Skip to content

Commit 956413c

Browse files
committed
---
yaml --- r: 953 b: refs/heads/master c: f809375 h: refs/heads/master i: 951: bedea18 v: v3
1 parent b10c8b6 commit 956413c

File tree

4 files changed

+238
-29
lines changed

4 files changed

+238
-29
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 96540ef0bb649f4bd5c90ff2b524e763b3b5db85
2+
refs/heads/master: f809375b163bb108d9193f456f44ca663874380b

trunk/src/comp/lib/llvm.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,16 @@ obj builder(BuilderRef B) {
10191019
ret phi;
10201020
}
10211021

1022+
fn AddIncomingToPhi(ValueRef phi,
1023+
vec[ValueRef] vals,
1024+
vec[BasicBlockRef] bbs) {
1025+
check (_vec.len[ValueRef](vals) == _vec.len[BasicBlockRef](bbs));
1026+
llvm.LLVMAddIncoming(phi,
1027+
_vec.buf[ValueRef](vals),
1028+
_vec.buf[BasicBlockRef](bbs),
1029+
_vec.len[ValueRef](vals));
1030+
}
1031+
10221032
fn Call(ValueRef Fn, vec[ValueRef] Args) -> ValueRef {
10231033
ret llvm.LLVMBuildCall(B, Fn,
10241034
_vec.buf[ValueRef](Args),

trunk/src/comp/middle/trans.rs

Lines changed: 196 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -479,38 +479,202 @@ fn decr_refcnt_and_if_zero(@block_ctxt cx,
479479
ret res(next_cx, phi);
480480
}
481481

482-
fn type_is_scalar(@ast.ty t) -> bool {
483-
alt (t.node) {
484-
case (ast.ty_nil) { ret true; }
485-
case (ast.ty_bool) { ret true; }
486-
case (ast.ty_int) { ret true; }
487-
case (ast.ty_uint) { ret true; }
488-
case (ast.ty_machine(_)) { ret true; }
489-
case (ast.ty_char) { ret true; }
482+
type val_and_ty_fn =
483+
fn(@block_ctxt cx, ValueRef v, @typeck.ty t) -> result;
484+
485+
// Iterates through the elements of a tup, rec or tag.
486+
fn iter_structural_ty(@block_ctxt cx,
487+
ValueRef v,
488+
@typeck.ty t,
489+
val_and_ty_fn f)
490+
-> result {
491+
let result r = res(cx, C_nil());
492+
alt (t.struct) {
493+
case (typeck.ty_tup(?args)) {
494+
let int i = 0;
495+
for (tup(bool, @typeck.ty) arg in args) {
496+
auto elt = r.bcx.build.GEP(v, vec(C_int(0), C_int(i)));
497+
r = f(r.bcx, elt, arg._1);
498+
i += 1;
499+
}
500+
}
501+
// FIXME: handle records and tags when we support them.
490502
}
491-
ret false;
503+
ret r;
492504
}
493505

494-
fn trans_copy_ty(@block_ctxt cx,
495-
bool is_init,
496-
ValueRef dst,
497-
ValueRef src,
498-
@ast.ty t) -> result {
499-
if (type_is_scalar(t)) {
500-
ret res(cx, cx.build.Store(src, dst));
506+
// Iterates through the elements of a vec or str.
507+
fn iter_sequence(@block_ctxt cx,
508+
ValueRef v,
509+
@typeck.ty ty,
510+
val_and_ty_fn f) -> result {
511+
512+
fn iter_sequence_body(@block_ctxt cx,
513+
ValueRef v,
514+
@typeck.ty elt_ty,
515+
val_and_ty_fn f,
516+
bool trailing_null) -> result {
517+
518+
auto p0 = cx.build.GEP(v, vec(C_int(0),
519+
C_int(abi.vec_elt_data)));
520+
auto lenptr = cx.build.GEP(v, vec(C_int(0),
521+
C_int(abi.vec_elt_fill)));
522+
auto len = cx.build.Load(lenptr);
523+
if (trailing_null) {
524+
len = cx.build.Sub(len, C_int(1));
525+
}
526+
527+
auto r = res(cx, C_nil());
528+
529+
auto cond_cx = new_sub_block_ctxt(cx, "sequence-iter cond");
530+
auto body_cx = new_sub_block_ctxt(cx, "sequence-iter body");
531+
auto next_cx = new_sub_block_ctxt(cx, "next");
532+
533+
auto ix = cond_cx.build.Phi(T_int(), vec(C_int(0)), vec(cx.llbb));
534+
auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntEQ, ix, len);
535+
cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);
536+
537+
auto elt = body_cx.build.GEP(p0, vec(ix));
538+
auto body_res = f(body_cx, elt, elt_ty);
539+
auto next_ix = body_res.bcx.build.Add(ix, C_int(1));
540+
cond_cx.build.AddIncomingToPhi(ix, vec(next_ix),
541+
vec(body_res.bcx.llbb));
542+
543+
body_res.bcx.build.Br(cond_cx.llbb);
544+
ret res(next_cx, C_nil());
545+
}
546+
547+
alt (ty.struct) {
548+
case (typeck.ty_vec(?et)) {
549+
ret iter_sequence_body(cx, v, et, f, false);
550+
}
551+
case (typeck.ty_str) {
552+
auto et = typeck.plain_ty(typeck.ty_machine(common.ty_u8));
553+
ret iter_sequence_body(cx, v, et, f, false);
554+
}
501555
}
556+
cx.fcx.ccx.sess.bug("bad type in trans.iter_sequence");
557+
fail;
558+
}
559+
560+
fn incr_all_refcnts(@block_ctxt cx,
561+
ValueRef v,
562+
@typeck.ty t) -> result {
502563

503-
alt (t.node) {
504-
case (ast.ty_str) {
505-
let result r = res(cx, C_nil());
506-
if (is_init) {
507-
r = trans_drop_str(cx, dst);
564+
if (typeck.type_is_boxed(t)) {
565+
ret incr_refcnt(cx, v);
566+
567+
} else if (typeck.type_is_binding(t)) {
568+
cx.fcx.ccx.sess.unimpl("binding type in trans.incr_all_refcnts");
569+
570+
} else if (typeck.type_is_structural(t)) {
571+
ret iter_structural_ty(cx, v, t,
572+
bind incr_all_refcnts(_, _, _));
573+
}
574+
}
575+
576+
fn drop_ty(@block_ctxt cx,
577+
ValueRef v,
578+
@typeck.ty t) -> result {
579+
580+
alt (t.struct) {
581+
case (typeck.ty_str) {
582+
ret decr_refcnt_and_if_zero(cx, v,
583+
bind trans_non_gc_free(_, v),
584+
"free string",
585+
T_int(), C_int(0));
586+
}
587+
588+
case (typeck.ty_vec(_)) {
589+
fn hit_zero(@block_ctxt cx, ValueRef v,
590+
@typeck.ty t) -> result {
591+
auto res = iter_sequence(cx, v, t, bind drop_ty(_,_,_));
592+
// FIXME: switch gc/non-gc on stratum of the type.
593+
ret trans_non_gc_free(res.bcx, v);
594+
}
595+
ret decr_refcnt_and_if_zero(cx, v,
596+
bind hit_zero(_, v, t),
597+
"free vector",
598+
T_int(), C_int(0));
599+
}
600+
601+
case (typeck.ty_box(_)) {
602+
fn hit_zero(@block_ctxt cx, ValueRef v,
603+
@typeck.ty elt_ty) -> result {
604+
auto res = drop_ty(cx,
605+
cx.build.GEP(v, vec(C_int(0))),
606+
elt_ty);
607+
// FIXME: switch gc/non-gc on stratum of the type.
608+
ret trans_non_gc_free(res.bcx, v);
609+
}
610+
ret incr_refcnt(cx, v);
611+
}
612+
613+
case (_) {
614+
if (typeck.type_is_structural(t)) {
615+
ret iter_structural_ty(cx, v, t,
616+
bind drop_ty(_, _, _));
617+
618+
} else if (typeck.type_is_binding(t)) {
619+
cx.fcx.ccx.sess.unimpl("binding type in trans.drop_ty");
620+
621+
} else if (typeck.type_is_scalar(t) ||
622+
typeck.type_is_nil(t)) {
623+
ret res(cx, C_nil());
508624
}
509-
r = incr_refcnt(r.bcx, src);
510-
ret res(r.bcx, r.bcx.build.Store(src, dst));
511625
}
512626
}
513-
cx.fcx.ccx.sess.unimpl("ty variant in trans_copy_ty");
627+
cx.fcx.ccx.sess.bug("bad type in trans.drop_ty");
628+
fail;
629+
}
630+
631+
fn build_memcpy(@block_ctxt cx,
632+
ValueRef dst,
633+
ValueRef src,
634+
TypeRef llty) -> result {
635+
auto memcpy = cx.fcx.ccx.fn_names.get("llvm.memcpy");
636+
auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
637+
auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
638+
auto size = lib.llvm.llvm.LLVMSizeOf(llty);
639+
auto align = lib.llvm.llvm.LLVMAlignOf(llty);
640+
auto volatile = C_integral(0, T_i1());
641+
ret res(cx, cx.build.Call(memcpy,
642+
vec(dst_ptr, src_ptr,
643+
size, align, volatile)));
644+
}
645+
646+
fn copy_ty(@block_ctxt cx,
647+
bool is_init,
648+
ValueRef dst,
649+
ValueRef src,
650+
@typeck.ty t) -> result {
651+
if (typeck.type_is_scalar(t)) {
652+
ret res(cx, cx.build.Store(src, dst));
653+
654+
} else if (typeck.type_is_nil(t)) {
655+
ret res(cx, C_nil());
656+
657+
} else if (typeck.type_is_binding(t)) {
658+
cx.fcx.ccx.sess.unimpl("binding type in trans.copy_ty");
659+
660+
} else if (typeck.type_is_boxed(t)) {
661+
auto r = incr_refcnt(cx, src);
662+
if (! is_init) {
663+
r = drop_ty(r.bcx, dst, t);
664+
}
665+
ret res(r.bcx, r.bcx.build.Store(src, dst));
666+
667+
} else if (typeck.type_is_structural(t)) {
668+
auto r = incr_all_refcnts(cx, src, t);
669+
if (! is_init) {
670+
r = drop_ty(r.bcx, dst, t);
671+
}
672+
auto llty = type_of(cx.fcx.ccx, t);
673+
r = build_memcpy(r.bcx, dst, src, llty);
674+
}
675+
676+
cx.fcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
677+
typeck.ty_to_str(t));
514678
fail;
515679
}
516680

@@ -1023,13 +1187,12 @@ impure fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
10231187
}
10241188
}
10251189

1026-
case (ast.expr_assign(?dst, ?src, _)) {
1190+
case (ast.expr_assign(?dst, ?src, ?ann)) {
10271191
auto lhs_res = trans_lval(cx, *dst);
10281192
check (lhs_res._1);
10291193
auto rhs_res = trans_expr(lhs_res._0.bcx, *src);
1030-
// FIXME: call trans_copy_ty once we have a ty here.
1031-
ret res(rhs_res.bcx,
1032-
rhs_res.bcx.build.Store(rhs_res.val, lhs_res._0.val));
1194+
auto t = node_ann_type(cx.fcx.ccx, ann);
1195+
ret copy_ty(rhs_res.bcx, true, lhs_res._0.val, rhs_res.val, t);
10331196
}
10341197

10351198
case (ast.expr_call(?f, ?args, _)) {
@@ -1451,7 +1614,12 @@ fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
14511614

14521615
fn declare_intrinsics(ModuleRef llmod) {
14531616
let vec[TypeRef] T_trap_args = vec();
1617+
// FIXME: switch this to 64-bit memcpy when targeting a 64-bit system.
1618+
let vec[TypeRef] T_memcpy_args = vec(T_ptr(T_i8()),
1619+
T_ptr(T_i8()),
1620+
T_i32(), T_i32(), T_i1());
14541621
decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void()));
1622+
decl_cdecl_fn(llmod, "llvm.memcpy", T_fn(T_memcpy_args, T_void()));
14551623
}
14561624

14571625
fn trans_crate(session.session sess, @ast.crate crate, str output) {

trunk/src/comp/middle/typeck.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,37 @@ fn mode_is_alias(ast.mode m) -> bool {
412412
}
413413
}
414414

415+
fn type_is_nil(@ty t) -> bool {
416+
alt (t.struct) {
417+
case (ty_nil) { ret true; }
418+
}
419+
ret false;
420+
}
421+
422+
fn type_is_structural(@ty t) -> bool {
423+
alt (t.struct) {
424+
// FIXME: cover rec and tag when we support them.
425+
case (ty_tup(_)) { ret true; }
426+
}
427+
ret false;
428+
}
429+
430+
fn type_is_binding(@ty t) -> bool {
431+
alt (t.struct) {
432+
// FIXME: cover obj when we support it.
433+
case (ty_fn(_,_)) { ret true; }
434+
}
435+
ret false;
436+
}
437+
438+
fn type_is_boxed(@ty t) -> bool {
439+
alt (t.struct) {
440+
case (ty_str) { ret true; }
441+
case (ty_vec(_)) { ret true; }
442+
}
443+
ret false;
444+
}
445+
415446
fn type_is_scalar(@ty t) -> bool {
416447
alt (t.struct) {
417448
case (ty_bool) { ret true; }

0 commit comments

Comments
 (0)