mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-08 04:56:58 +00:00
Implement deep structural comparison through boxes and sequences.
This commit is contained in:
parent
fb246e4e47
commit
8e8c336f93
@ -402,6 +402,7 @@ TEST_XFAILS_BOOT := $(TASK_XFAILS) \
|
||||
$(NOMINAL_TAG_XFAILS) \
|
||||
$(CONST_TAG_XFAILS) \
|
||||
test/run-pass/arith-unsigned.rs \
|
||||
test/run-pass/box-compare.rs \
|
||||
test/run-pass/child-outlives-parent.rs \
|
||||
test/run-pass/clone-with-exterior.rs \
|
||||
test/run-pass/constrained-type.rs \
|
||||
@ -416,6 +417,7 @@ TEST_XFAILS_BOOT := $(TASK_XFAILS) \
|
||||
test/run-pass/lib-io.rs \
|
||||
test/run-pass/mlist-cycle.rs \
|
||||
test/run-pass/obj-as.rs \
|
||||
test/run-pass/seq-compare.rs \
|
||||
test/run-pass/task-comm.rs \
|
||||
test/run-pass/task-comm-3.rs \
|
||||
test/run-pass/vec-slice.rs \
|
||||
|
@ -890,6 +890,11 @@ fn umax(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
|
||||
ret cx.build.Select(cond, b, a);
|
||||
}
|
||||
|
||||
fn umin(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
|
||||
auto cond = cx.build.ICmp(lib.llvm.LLVMIntULT, a, b);
|
||||
ret cx.build.Select(cond, a, b);
|
||||
}
|
||||
|
||||
fn align_to(@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
|
||||
auto mask = cx.build.Sub(align, C_int(1));
|
||||
auto bumped = cx.build.Add(off, mask);
|
||||
@ -1774,7 +1779,7 @@ fn mk_plain_tag(ast.def_id tid) -> @ty.t {
|
||||
}
|
||||
|
||||
|
||||
type val_fn = fn(@block_ctxt cx, ValueRef v) -> result;
|
||||
type val_pair_fn = fn(@block_ctxt cx, ValueRef dst, ValueRef src) -> result;
|
||||
|
||||
type val_and_ty_fn = fn(@block_ctxt cx, ValueRef v, @ty.t t) -> result;
|
||||
|
||||
@ -1987,13 +1992,15 @@ fn iter_structural_ty_full(@block_ctxt cx,
|
||||
|
||||
// Iterates through a pointer range, until the src* hits the src_lim*.
|
||||
fn iter_sequence_raw(@block_ctxt cx,
|
||||
ValueRef dst, // elt*
|
||||
ValueRef src, // elt*
|
||||
ValueRef src_lim, // elt*
|
||||
ValueRef elt_sz,
|
||||
val_fn f) -> result {
|
||||
val_pair_fn f) -> result {
|
||||
|
||||
auto bcx = cx;
|
||||
|
||||
let ValueRef dst_int = vp2i(bcx, dst);
|
||||
let ValueRef src_int = vp2i(bcx, src);
|
||||
let ValueRef src_lim_int = vp2i(bcx, src_lim);
|
||||
|
||||
@ -2003,6 +2010,8 @@ fn iter_sequence_raw(@block_ctxt cx,
|
||||
|
||||
bcx.build.Br(cond_cx.llbb);
|
||||
|
||||
let ValueRef dst_curr = cond_cx.build.Phi(T_int(),
|
||||
vec(dst_int), vec(bcx.llbb));
|
||||
let ValueRef src_curr = cond_cx.build.Phi(T_int(),
|
||||
vec(src_int), vec(bcx.llbb));
|
||||
|
||||
@ -2011,14 +2020,18 @@ fn iter_sequence_raw(@block_ctxt cx,
|
||||
|
||||
cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);
|
||||
|
||||
auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
|
||||
auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
|
||||
|
||||
auto body_res = f(body_cx, src_curr_ptr);
|
||||
auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
|
||||
body_cx = body_res.bcx;
|
||||
|
||||
auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
|
||||
auto src_next = body_cx.build.Add(src_curr, elt_sz);
|
||||
body_cx.build.Br(cond_cx.llbb);
|
||||
|
||||
cond_cx.build.AddIncomingToPhi(dst_curr, vec(dst_next),
|
||||
vec(body_cx.llbb));
|
||||
cond_cx.build.AddIncomingToPhi(src_curr, vec(src_next),
|
||||
vec(body_cx.llbb));
|
||||
|
||||
@ -2034,15 +2047,16 @@ fn iter_sequence_inner(@block_ctxt cx,
|
||||
fn adaptor_fn(val_and_ty_fn f,
|
||||
@ty.t elt_ty,
|
||||
@block_ctxt cx,
|
||||
ValueRef v) -> result {
|
||||
ValueRef dst,
|
||||
ValueRef src) -> result {
|
||||
auto llty = type_of(cx.fcx.ccx, elt_ty);
|
||||
auto p = cx.build.PointerCast(v, T_ptr(llty));
|
||||
auto p = cx.build.PointerCast(src, T_ptr(llty));
|
||||
ret f(cx, load_scalar_or_boxed(cx, p, elt_ty), elt_ty);
|
||||
}
|
||||
|
||||
auto elt_sz = size_of(cx, elt_ty);
|
||||
be iter_sequence_raw(elt_sz.bcx, src, src_lim, elt_sz.val,
|
||||
bind adaptor_fn(f, elt_ty, _, _));
|
||||
be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
|
||||
bind adaptor_fn(f, elt_ty, _, _, _));
|
||||
}
|
||||
|
||||
|
||||
@ -2378,13 +2392,27 @@ fn trans_unary(@block_ctxt cx, ast.unop op,
|
||||
fail;
|
||||
}
|
||||
|
||||
fn trans_compare(@block_ctxt cx, ast.binop op, @ty.t t,
|
||||
ValueRef lhs, ValueRef rhs) -> result {
|
||||
fn trans_compare(@block_ctxt cx0, ast.binop op, @ty.t t0,
|
||||
ValueRef lhs0, ValueRef rhs0) -> result {
|
||||
|
||||
auto cx = cx0;
|
||||
|
||||
auto lhs_r = autoderef(cx, lhs0, t0);
|
||||
auto lhs = lhs_r.val;
|
||||
cx = lhs_r.bcx;
|
||||
|
||||
auto rhs_r = autoderef(cx, rhs0, t0);
|
||||
auto rhs = rhs_r.val;
|
||||
cx = rhs_r.bcx;
|
||||
|
||||
auto t = autoderefed_ty(t0);
|
||||
|
||||
if (ty.type_is_scalar(t)) {
|
||||
ret res(cx, trans_scalar_compare(cx, op, t, lhs, rhs));
|
||||
|
||||
} else if (ty.type_is_structural(t)) {
|
||||
} else if (ty.type_is_structural(t)
|
||||
|| ty.type_is_sequence(t)) {
|
||||
|
||||
auto scx = new_sub_block_ctxt(cx, "structural compare start");
|
||||
auto next = new_sub_block_ctxt(cx, "structural compare end");
|
||||
cx.build.Br(scx.llbb);
|
||||
@ -2415,28 +2443,52 @@ fn trans_compare(@block_ctxt cx, ast.binop op, @ty.t t,
|
||||
|
||||
auto flag = scx.build.Alloca(T_i1());
|
||||
|
||||
alt (op) {
|
||||
// ==, <= and >= default to true if they find == all the way.
|
||||
case (ast.eq) { scx.build.Store(C_integral(1, T_i1()), flag); }
|
||||
case (ast.le) { scx.build.Store(C_integral(1, T_i1()), flag); }
|
||||
case (ast.ge) { scx.build.Store(C_integral(1, T_i1()), flag); }
|
||||
case (_) {
|
||||
// ==, <= and >= default to false if they find == all the way.
|
||||
scx.build.Store(C_integral(0, T_i1()), flag);
|
||||
if (ty.type_is_sequence(t)) {
|
||||
|
||||
// If we hit == all the way through the minimum-shared-length
|
||||
// section, default to judging the relative sequence lengths.
|
||||
auto len_cmp =
|
||||
trans_integral_compare(scx, op, plain_ty(ty.ty_uint),
|
||||
vec_fill(scx, lhs),
|
||||
vec_fill(scx, rhs));
|
||||
scx.build.Store(len_cmp, flag);
|
||||
|
||||
} else {
|
||||
auto T = C_integral(1, T_i1());
|
||||
auto F = C_integral(0, T_i1());
|
||||
|
||||
alt (op) {
|
||||
// ==, <= and >= default to true if they find == all the way.
|
||||
case (ast.eq) { scx.build.Store(T, flag); }
|
||||
case (ast.le) { scx.build.Store(T, flag); }
|
||||
case (ast.ge) { scx.build.Store(T, flag); }
|
||||
case (_) {
|
||||
// < > default to false if they find == all the way.
|
||||
scx.build.Store(F, flag);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn inner(@block_ctxt last_cx,
|
||||
bool load_inner,
|
||||
ValueRef flag,
|
||||
ast.binop op,
|
||||
@block_ctxt cx,
|
||||
ValueRef av,
|
||||
ValueRef bv,
|
||||
ValueRef av0,
|
||||
ValueRef bv0,
|
||||
@ty.t t) -> result {
|
||||
|
||||
auto cnt_cx = new_sub_block_ctxt(cx, "continue comparison");
|
||||
auto stop_cx = new_sub_block_ctxt(cx, "stop comparison");
|
||||
|
||||
auto av = av0;
|
||||
auto bv = bv0;
|
||||
if (load_inner) {
|
||||
av = load_scalar_or_boxed(cx, av, t);
|
||||
bv = load_scalar_or_boxed(cx, bv, t);
|
||||
}
|
||||
|
||||
// First 'eq' comparison: if so, continue to next elts.
|
||||
auto eq_r = trans_compare(cx, ast.eq, t, av, bv);
|
||||
eq_r.bcx.build.CondBr(eq_r.val, cnt_cx.llbb, stop_cx.llbb);
|
||||
@ -2448,16 +2500,32 @@ fn trans_compare(@block_ctxt cx, ast.binop op, @ty.t t,
|
||||
ret res(cnt_cx, C_nil());
|
||||
}
|
||||
|
||||
auto r = iter_structural_ty_full(scx, lhs, rhs, t,
|
||||
bind inner(next, flag, op,
|
||||
_, _, _, _));
|
||||
auto r;
|
||||
if (ty.type_is_structural(t)) {
|
||||
r = iter_structural_ty_full(scx, lhs, rhs, t,
|
||||
bind inner(next, false, flag, op,
|
||||
_, _, _, _));
|
||||
} else {
|
||||
auto lhs_p0 = vec_p0(scx, lhs);
|
||||
auto rhs_p0 = vec_p0(scx, rhs);
|
||||
auto min_len = umin(scx, vec_fill(scx, lhs), vec_fill(scx, rhs));
|
||||
auto rhs_lim = scx.build.GEP(rhs_p0, vec(min_len));
|
||||
auto elt_ty = ty.sequence_element_type(t);
|
||||
auto elt_llsz_r = size_of(scx, elt_ty);
|
||||
scx = elt_llsz_r.bcx;
|
||||
r = iter_sequence_raw(scx, lhs, rhs, rhs_lim,
|
||||
elt_llsz_r.val,
|
||||
bind inner(next, true, flag, op,
|
||||
_, _, _, elt_ty));
|
||||
}
|
||||
|
||||
r.bcx.build.Br(next.llbb);
|
||||
auto v = next.build.Load(flag);
|
||||
ret res(next, v);
|
||||
|
||||
|
||||
} else {
|
||||
// FIXME: compare vec, str, box?
|
||||
// FIXME: compare obj, fn by pointer?
|
||||
cx.fcx.ccx.sess.unimpl("type in trans_compare");
|
||||
ret res(cx, C_bool(false));
|
||||
}
|
||||
@ -5670,6 +5738,45 @@ fn make_vec_append_glue(ModuleRef llmod, type_names tn) -> ValueRef {
|
||||
ret llfn;
|
||||
}
|
||||
|
||||
|
||||
fn vec_fill(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
||||
ret bcx.build.Load(bcx.build.GEP(v, vec(C_int(0),
|
||||
C_int(abi.vec_elt_fill))));
|
||||
}
|
||||
|
||||
fn put_vec_fill(@block_ctxt bcx, ValueRef v, ValueRef fill) -> ValueRef {
|
||||
ret bcx.build.Store(fill,
|
||||
bcx.build.GEP(v,
|
||||
vec(C_int(0),
|
||||
C_int(abi.vec_elt_fill))));
|
||||
}
|
||||
|
||||
fn vec_fill_adjusted(@block_ctxt bcx, ValueRef v,
|
||||
ValueRef skipnull) -> ValueRef {
|
||||
auto f = bcx.build.Load(bcx.build.GEP(v,
|
||||
vec(C_int(0),
|
||||
C_int(abi.vec_elt_fill))));
|
||||
ret bcx.build.Select(skipnull, bcx.build.Sub(f, C_int(1)), f);
|
||||
}
|
||||
|
||||
fn vec_p0(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
||||
auto p = bcx.build.GEP(v, vec(C_int(0),
|
||||
C_int(abi.vec_elt_data)));
|
||||
ret bcx.build.PointerCast(p, T_ptr(T_i8()));
|
||||
}
|
||||
|
||||
|
||||
fn vec_p1(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
||||
auto len = vec_fill(bcx, v);
|
||||
ret bcx.build.GEP(vec_p0(bcx, v), vec(len));
|
||||
}
|
||||
|
||||
fn vec_p1_adjusted(@block_ctxt bcx, ValueRef v,
|
||||
ValueRef skipnull) -> ValueRef {
|
||||
auto len = vec_fill_adjusted(bcx, v, skipnull);
|
||||
ret bcx.build.GEP(vec_p0(bcx, v), vec(len));
|
||||
}
|
||||
|
||||
fn trans_vec_append_glue(@crate_ctxt cx) {
|
||||
|
||||
auto llfn = cx.glues.vec_append_glue;
|
||||
@ -5700,45 +5807,6 @@ fn trans_vec_append_glue(@crate_ctxt cx) {
|
||||
// First the dst vec needs to grow to accommodate the src vec.
|
||||
// To do this we have to figure out how many bytes to add.
|
||||
|
||||
fn vec_fill(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
||||
ret bcx.build.Load(bcx.build.GEP(v, vec(C_int(0),
|
||||
C_int(abi.vec_elt_fill))));
|
||||
}
|
||||
|
||||
fn put_vec_fill(@block_ctxt bcx, ValueRef v, ValueRef fill) -> ValueRef {
|
||||
ret bcx.build.Store(fill,
|
||||
bcx.build.GEP(v,
|
||||
vec(C_int(0),
|
||||
C_int(abi.vec_elt_fill))));
|
||||
}
|
||||
|
||||
fn vec_fill_adjusted(@block_ctxt bcx, ValueRef v,
|
||||
ValueRef skipnull) -> ValueRef {
|
||||
auto f = bcx.build.Load(bcx.build.GEP(v,
|
||||
vec(C_int(0),
|
||||
C_int(abi.vec_elt_fill))));
|
||||
ret bcx.build.Select(skipnull, bcx.build.Sub(f, C_int(1)), f);
|
||||
}
|
||||
|
||||
fn vec_p0(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
||||
auto p = bcx.build.GEP(v, vec(C_int(0),
|
||||
C_int(abi.vec_elt_data)));
|
||||
ret bcx.build.PointerCast(p, T_ptr(T_i8()));
|
||||
}
|
||||
|
||||
|
||||
fn vec_p1(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
||||
auto len = vec_fill(bcx, v);
|
||||
ret bcx.build.GEP(vec_p0(bcx, v), vec(len));
|
||||
}
|
||||
|
||||
fn vec_p1_adjusted(@block_ctxt bcx, ValueRef v,
|
||||
ValueRef skipnull) -> ValueRef {
|
||||
auto len = vec_fill_adjusted(bcx, v, skipnull);
|
||||
ret bcx.build.GEP(vec_p0(bcx, v), vec(len));
|
||||
}
|
||||
|
||||
|
||||
auto llcopy_dst_ptr = bcx.build.Alloca(T_int());
|
||||
auto llnew_vec_res =
|
||||
trans_upcall(bcx, "upcall_vec_grow",
|
||||
@ -5780,16 +5848,17 @@ fn trans_vec_append_glue(@crate_ctxt cx) {
|
||||
C_int(abi.tydesc_field_size))));
|
||||
|
||||
fn take_one(ValueRef elt_tydesc,
|
||||
@block_ctxt cx, ValueRef v) -> result {
|
||||
call_tydesc_glue_full(cx, v,
|
||||
@block_ctxt cx,
|
||||
ValueRef dst, ValueRef src) -> result {
|
||||
call_tydesc_glue_full(cx, src,
|
||||
elt_tydesc,
|
||||
abi.tydesc_field_take_glue_off);
|
||||
ret res(cx, v);
|
||||
ret res(cx, src);
|
||||
}
|
||||
|
||||
auto bcx = iter_sequence_raw(cx, src, src_lim,
|
||||
auto bcx = iter_sequence_raw(cx, dst, src, src_lim,
|
||||
elt_llsz, bind take_one(elt_tydesc,
|
||||
_, _)).bcx;
|
||||
_, _, _)).bcx;
|
||||
|
||||
ret call_memcpy(bcx, dst, src, n_bytes);
|
||||
}
|
||||
|
@ -373,6 +373,14 @@ fn get_element_type(@t ty, uint i) -> @t {
|
||||
fail;
|
||||
}
|
||||
|
||||
fn type_is_box(@t ty) -> bool {
|
||||
alt (ty.struct) {
|
||||
case (ty_box(_)) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn type_is_boxed(@t ty) -> bool {
|
||||
alt (ty.struct) {
|
||||
case (ty_str) { ret true; }
|
||||
|
5
src/test/run-pass/box-compare.rs
Normal file
5
src/test/run-pass/box-compare.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
check (@1 < @3);
|
||||
check (@@"hello " > @@"hello");
|
||||
check (@@@"hello" != @@@"there");
|
||||
}
|
15
src/test/run-pass/seq-compare.rs
Normal file
15
src/test/run-pass/seq-compare.rs
Normal file
@ -0,0 +1,15 @@
|
||||
fn main() {
|
||||
check ("hello" < "hellr");
|
||||
check ("hello " > "hello");
|
||||
check ("hello" != "there");
|
||||
|
||||
check (vec(1,2,3,4) > vec(1,2,3));
|
||||
check (vec(1,2,3) < vec(1,2,3,4));
|
||||
check (vec(1,2,4,4) > vec(1,2,3,4));
|
||||
check (vec(1,2,3,4) < vec(1,2,4,4));
|
||||
check (vec(1,2,3) <= vec(1,2,3));
|
||||
check (vec(1,2,3) <= vec(1,2,3,3));
|
||||
check (vec(1,2,3,4) > vec(1,2,3));
|
||||
check (vec(1,2,3) == vec(1,2,3));
|
||||
check (vec(1,2,3) != vec(1,1,3));
|
||||
}
|
Loading…
Reference in New Issue
Block a user