@@ -1583,24 +1583,30 @@ fn iter_structural_ty_full(@block_ctxt cx,
1583
1583
auto llunion_b_ptr = cx. build. GEP ( bv, vec( C_int ( 0 ) , C_int ( 1 ) ) ) ;
1584
1584
auto lldiscrim_b = cx. build. Load ( lldiscrim_b_ptr) ;
1585
1585
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" ) ;
1587
1593
unr_cx. build. Unreachable ( ) ;
1588
1594
1589
- auto llswitch = cx . build. Switch ( lldiscrim_a, unr_cx. llbb,
1595
+ auto llswitch = bcx . build. Switch ( lldiscrim_a, unr_cx. llbb,
1590
1596
n_variants) ;
1591
1597
1592
- auto next_cx = new_sub_block_ctxt( cx , "tag-iter-next" ) ;
1598
+ auto next_cx = new_sub_block_ctxt( bcx , "tag-iter-next" ) ;
1593
1599
1594
1600
auto i = 0 u;
1595
1601
for ( ast. variant variant in variants) {
1596
- auto variant_cx = new_sub_block_ctxt( cx ,
1602
+ auto variant_cx = new_sub_block_ctxt( bcx ,
1597
1603
"tag-iter-variant-" +
1598
1604
_uint. to_str( i, 10 u) ) ;
1599
1605
llvm. LLVMAddCase ( llswitch, C_int ( i as int) , variant_cx. llbb) ;
1600
1606
1601
1607
if ( _vec. len[ ast. variant_arg] ( variant. args) > 0 u) {
1602
1608
// 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) ) ;
1604
1610
1605
1611
auto fn_ty = ty. ann_to_type( variants. ( i) . ann) ;
1606
1612
alt ( fn_ty. struct ) {
@@ -1611,7 +1617,7 @@ fn iter_structural_ty_full(@block_ctxt cx,
1611
1617
auto llvarp_b = variant_cx. build.
1612
1618
TruncOrBitCast ( llunion_b_ptr, T_ptr ( llvarty) ) ;
1613
1619
1614
- auto ty_params = tag_ty_params( cx . fcx. ccx, tid) ;
1620
+ auto ty_params = tag_ty_params( bcx . fcx. ccx, tid) ;
1615
1621
1616
1622
auto j = 0 u;
1617
1623
for ( ty. arg a in args) {
@@ -2023,37 +2029,65 @@ fn trans_compare(@block_ctxt cx, ast.binop op, @ty.t t,
2023
2029
auto next = new_sub_block_ctxt( cx, "structural compare end" ) ;
2024
2030
cx. build. Br ( scx. llbb) ;
2025
2031
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
+
2027
2056
auto flag = scx. build. Alloca ( T_i1 ( ) ) ;
2028
- scx. build. Store ( C_integral ( 1 , T_i1 ( ) ) , flag) ;
2029
2057
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
+ }
2032
2068
2033
- fn inner( @block_ctxt next_cx ,
2069
+ fn inner( @block_ctxt last_cx ,
2034
2070
ValueRef flag,
2035
2071
ast. binop op,
2036
2072
@block_ctxt cx,
2037
2073
ValueRef av,
2038
2074
ValueRef bv,
2039
2075
@ty. t t) -> result {
2040
- // Compare av op bv
2076
+
2041
2077
auto cnt_cx = new_sub_block_ctxt( cx, "continue comparison" ) ;
2042
2078
auto stop_cx = new_sub_block_ctxt( cx, "stop comparison" ) ;
2043
2079
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) ;
2050
2083
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) ;
2051
2088
ret res( cnt_cx, C_nil ( ) ) ;
2052
2089
}
2053
2090
2054
- // FIXME: this is wrong for tag types; need to confirm discriminants
2055
- // are equal before blindly walking over elements.
2056
-
2057
2091
auto r = iter_structural_ty_full( scx, lhs, rhs, t,
2058
2092
bind inner( next, flag, op,
2059
2093
_, _, _, _) ) ;
0 commit comments