about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-03-09 20:14:19 -0800
committerGraydon Hoare <graydon@mozilla.com>2011-03-09 20:14:19 -0800
commit8e8c336f93becbc394b99e978cc3d8145e7e9d7c (patch)
treeb08227e7d271db47d1b428bd0a31a3c736718b04 /src
parentfb246e4e478b487da3a0ad36583217b32f483116 (diff)
Implement deep structural comparison through boxes and sequences.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile2
-rw-r--r--src/comp/middle/trans.rs205
-rw-r--r--src/comp/middle/ty.rs8
-rw-r--r--src/test/run-pass/box-compare.rs5
-rw-r--r--src/test/run-pass/seq-compare.rs15
5 files changed, 167 insertions, 68 deletions
diff --git a/src/Makefile b/src/Makefile
index 209e1b90833..0bddc0de415 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -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 \
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 00e7e6d839a..172f731be65 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.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);
     }
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 958d0b78ef1..bd3e3263820 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -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; }
diff --git a/src/test/run-pass/box-compare.rs b/src/test/run-pass/box-compare.rs
new file mode 100644
index 00000000000..5115d5109a9
--- /dev/null
+++ b/src/test/run-pass/box-compare.rs
@@ -0,0 +1,5 @@
+fn main() {
+  check (@1 < @3);
+  check (@@"hello " > @@"hello");
+  check (@@@"hello" != @@@"there");
+}
\ No newline at end of file
diff --git a/src/test/run-pass/seq-compare.rs b/src/test/run-pass/seq-compare.rs
new file mode 100644
index 00000000000..b3fe570193d
--- /dev/null
+++ b/src/test/run-pass/seq-compare.rs
@@ -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));
+}
\ No newline at end of file