Skip to content

Commit 7f2398e

Browse files
committed
Implement structured compare for rec, tup, tag. Un-XFAIL structured-compare.rs.
1 parent f239ecb commit 7f2398e

File tree

2 files changed

+55
-22
lines changed

2 files changed

+55
-22
lines changed

src/Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,6 @@ TEST_XFAILS_RUSTC := $(CONST_TAG_XFAILS) \
505505
spawn.rs \
506506
str-append.rs \
507507
str-concat.rs \
508-
structured-compare.rs \
509508
syntax-extension-fmt.rs \
510509
syntax-extension-shell.rs \
511510
task-comm-0.rs \

src/comp/middle/trans.rs

+55-21
Original file line numberDiff line numberDiff line change
@@ -1583,24 +1583,30 @@ fn iter_structural_ty_full(@block_ctxt cx,
15831583
auto llunion_b_ptr = cx.build.GEP(bv, vec(C_int(0), C_int(1)));
15841584
auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
15851585

1586-
auto unr_cx = new_sub_block_ctxt(cx, "tag-iter-unr");
1586+
// NB: we must hit the discriminant first so that structural
1587+
// comparison know not to proceed when the discriminants differ.
1588+
auto bcx = cx;
1589+
bcx = f(bcx, lldiscrim_a, lldiscrim_b,
1590+
plain_ty(ty.ty_int)).bcx;
1591+
1592+
auto unr_cx = new_sub_block_ctxt(bcx, "tag-iter-unr");
15871593
unr_cx.build.Unreachable();
15881594

1589-
auto llswitch = cx.build.Switch(lldiscrim_a, unr_cx.llbb,
1595+
auto llswitch = bcx.build.Switch(lldiscrim_a, unr_cx.llbb,
15901596
n_variants);
15911597

1592-
auto next_cx = new_sub_block_ctxt(cx, "tag-iter-next");
1598+
auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
15931599

15941600
auto i = 0u;
15951601
for (ast.variant variant in variants) {
1596-
auto variant_cx = new_sub_block_ctxt(cx,
1602+
auto variant_cx = new_sub_block_ctxt(bcx,
15971603
"tag-iter-variant-" +
15981604
_uint.to_str(i, 10u));
15991605
llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);
16001606

16011607
if (_vec.len[ast.variant_arg](variant.args) > 0u) {
16021608
// N-ary variant.
1603-
auto llvarty = type_of_variant(cx.fcx.ccx, variants.(i));
1609+
auto llvarty = type_of_variant(bcx.fcx.ccx, variants.(i));
16041610

16051611
auto fn_ty = ty.ann_to_type(variants.(i).ann);
16061612
alt (fn_ty.struct) {
@@ -1611,7 +1617,7 @@ fn iter_structural_ty_full(@block_ctxt cx,
16111617
auto llvarp_b = variant_cx.build.
16121618
TruncOrBitCast(llunion_b_ptr, T_ptr(llvarty));
16131619

1614-
auto ty_params = tag_ty_params(cx.fcx.ccx, tid);
1620+
auto ty_params = tag_ty_params(bcx.fcx.ccx, tid);
16151621

16161622
auto j = 0u;
16171623
for (ty.arg a in args) {
@@ -2023,37 +2029,65 @@ fn trans_compare(@block_ctxt cx, ast.binop op, @ty.t t,
20232029
auto next = new_sub_block_ctxt(cx, "structural compare end");
20242030
cx.build.Br(scx.llbb);
20252031

2026-
// Start with the assumptioin that our predicate holds.
2032+
/*
2033+
* We're doing lexicographic comparison here. We start with the
2034+
* assumption that the two input elements are equal. Depending on
2035+
* operator, this means that the result is either true or false;
2036+
* equality produces 'true' for ==, <= and >=. It produces 'false' for
2037+
* !=, < and >.
2038+
*
2039+
* We then move one element at a time through the structure checking
2040+
* for pairwise element equality. If we have equality, our assumption
2041+
* about overall sequence equality is not modified, so we have to move
2042+
* to the next element.
2043+
*
2044+
* If we do not have pairwise element equality, we have reached an
2045+
* element that 'decides' the lexicographic comparison. So we exit the
2046+
* loop with a flag that indicates the true/false sense of that
2047+
* decision, by testing the element again with the operator we're
2048+
* interested in.
2049+
*
2050+
* When we're lucky, LLVM should be able to fold some of these two
2051+
* tests together (as they're applied to the same operands and in some
2052+
* cases are sometimes redundant). But we don't bother trying to
2053+
* optimize combinations like that, at this level.
2054+
*/
2055+
20272056
auto flag = scx.build.Alloca(T_i1());
2028-
scx.build.Store(C_integral(1, T_i1()), flag);
20292057

2030-
// Attempt to prove otherwise by assuming true, comparing each element
2031-
// and writing 0 + early-exiting if any comparisons fail.
2058+
alt (op) {
2059+
// ==, <= and >= default to true if they find == all the way.
2060+
case (ast.eq) { scx.build.Store(C_integral(1, T_i1()), flag); }
2061+
case (ast.le) { scx.build.Store(C_integral(1, T_i1()), flag); }
2062+
case (ast.ge) { scx.build.Store(C_integral(1, T_i1()), flag); }
2063+
case (_) {
2064+
// ==, <= and >= default to false if they find == all the way.
2065+
scx.build.Store(C_integral(0, T_i1()), flag);
2066+
}
2067+
}
20322068

2033-
fn inner(@block_ctxt next_cx,
2069+
fn inner(@block_ctxt last_cx,
20342070
ValueRef flag,
20352071
ast.binop op,
20362072
@block_ctxt cx,
20372073
ValueRef av,
20382074
ValueRef bv,
20392075
@ty.t t) -> result {
2040-
// Compare av op bv
2076+
20412077
auto cnt_cx = new_sub_block_ctxt(cx, "continue comparison");
20422078
auto stop_cx = new_sub_block_ctxt(cx, "stop comparison");
20432079

2044-
auto r = trans_compare(cx, op, t, av, bv);
2045-
2046-
// if true, then carry on, else write 0 to flag, branch to 'next'.
2047-
r.bcx.build.CondBr(r.val, cnt_cx.llbb, stop_cx.llbb);
2048-
stop_cx.build.Store(C_integral(0, T_i1()), flag);
2049-
stop_cx.build.Br(next_cx.llbb);
2080+
// First 'eq' comparison: if so, continue to next elts.
2081+
auto eq_r = trans_compare(cx, ast.eq, t, av, bv);
2082+
eq_r.bcx.build.CondBr(eq_r.val, cnt_cx.llbb, stop_cx.llbb);
20502083

2084+
// Second 'op' comparison: find out how this elt-pair decides.
2085+
auto stop_r = trans_compare(stop_cx, op, t, av, bv);
2086+
stop_r.bcx.build.Store(stop_r.val, flag);
2087+
stop_r.bcx.build.Br(last_cx.llbb);
20512088
ret res(cnt_cx, C_nil());
20522089
}
20532090

2054-
// FIXME: this is wrong for tag types; need to confirm discriminants
2055-
// are equal before blindly walking over elements.
2056-
20572091
auto r = iter_structural_ty_full(scx, lhs, rhs, t,
20582092
bind inner(next, flag, op,
20592093
_, _, _, _));

0 commit comments

Comments
 (0)