about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-08-03 18:48:17 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-08-03 18:49:44 -0700
commit51a5a4ad0e2501b260a8059a72e4b0eebe78d6f9 (patch)
treef20c14d139f490c7f6e8642f47b831531f8ecd4d /src/rustc
parent488ece05b59b68a7d25c1fc59388438a78bb0b52 (diff)
downloadrust-51a5a4ad0e2501b260a8059a72e4b0eebe78d6f9.tar.gz
rust-51a5a4ad0e2501b260a8059a72e4b0eebe78d6f9.zip
rustc: Translate repeated vector syntax
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/trans/base.rs9
-rw-r--r--src/rustc/middle/trans/tvec.rs90
-rw-r--r--src/rustc/middle/ty.rs21
-rw-r--r--src/rustc/middle/typeck/check.rs24
4 files changed, 99 insertions, 45 deletions
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 9730c7e968d..13f3cf72f5f 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -3636,8 +3636,13 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
           }
           ast::expr_lit(lit) { return trans_lit(bcx, e, *lit, dest); }
           ast::expr_vec(args, _) {
-            return tvec::trans_evec(bcx, args, ast::vstore_fixed(none),
-                                 e.id, dest);
+            return tvec::trans_evec(bcx, tvec::individual_evec(args),
+                                    ast::vstore_fixed(none), e.id, dest);
+          }
+          ast::expr_repeat(element, count_expr, _) {
+            let count = ty::eval_repeat_count(bcx.tcx(), count_expr, e.span);
+            return tvec::trans_evec(bcx, tvec::repeating_evec(element, count),
+                                    ast::vstore_fixed(none), e.id, dest);
           }
           ast::expr_binary(op, lhs, rhs) {
             return trans_binary(bcx, op, lhs, rhs, dest, e);
diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs
index 0f99fe9b2f7..f85ca19a4b6 100644
--- a/src/rustc/middle/trans/tvec.rs
+++ b/src/rustc/middle/trans/tvec.rs
@@ -5,7 +5,7 @@ import back::abi;
 import base::{call_memmove,
               INIT, copy_val, load_if_immediate, get_tydesc,
               sub_block, do_spill_noroot,
-              dest, bcx_icx, non_gc_box_cast};
+              dest, bcx_icx, non_gc_box_cast, move_val, lval_owned};
 import syntax::codemap::span;
 import shape::llsize_of;
 import build::*;
@@ -118,18 +118,39 @@ fn make_drop_glue_unboxed(bcx: block, vptr: ValueRef, vec_ty: ty::t) ->
     } else { bcx }
 }
 
-fn trans_evec(bcx: block, args: ~[@ast::expr],
+enum evec_elements {
+    individual_evec(~[@ast::expr]),
+    repeating_evec(@ast::expr, uint)
+}
+
+fn trans_evec(bcx: block, elements: evec_elements,
               vst: ast::vstore, id: ast::node_id, dest: dest) -> block {
     let _icx = bcx.insn_ctxt(~"tvec::trans_evec");
     let ccx = bcx.ccx();
     let mut bcx = bcx;
+
+    // Handle the ignored case.
     if dest == base::ignore {
-        for vec::each(args) |arg| {
-            bcx = base::trans_expr(bcx, arg, base::ignore);
+        match elements {
+            individual_evec(args) => {
+                for vec::each(args) |arg| {
+                    bcx = base::trans_expr(bcx, arg, base::ignore);
+                }
+            }
+            repeating_evec(element, _) => {
+                bcx = base::trans_expr(bcx, element, base::ignore);
+            }
         }
         return bcx;
     }
 
+    // Figure out the number of elements we need.
+    let count;
+    match elements {
+        individual_evec(args) => count = args.len(),
+        repeating_evec(_, len) => count = len
+    }
+
     let vec_ty = node_id_type(bcx, id);
     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
     let llunitty = type_of::type_of(ccx, unit_ty);
@@ -151,13 +172,12 @@ fn trans_evec(bcx: block, args: ~[@ast::expr],
             {bcx: bcx, val: v, dataptr: v}
           }
           ast::vstore_slice(_) {
-            let n = vec::len(args);
             // Make a fake type to use for the cleanup
             let ty = ty::mk_evec(bcx.tcx(),
                                  {ty: unit_ty, mutbl: ast::m_mutbl},
-                                 ty::vstore_fixed(n));
+                                 ty::vstore_fixed(count));
 
-            let n = C_uint(ccx, n);
+            let n = C_uint(ccx, count);
             let vp = base::arrayalloca(bcx, llunitty, n);
             add_clean(bcx, vp, ty);
 
@@ -171,15 +191,13 @@ fn trans_evec(bcx: block, args: ~[@ast::expr],
             {bcx: bcx, val: p, dataptr: vp}
           }
           ast::vstore_uniq {
-            let {bcx, val} = alloc_vec(bcx, unit_ty, args.len(),
-                                       heap_exchange);
+            let {bcx, val} = alloc_vec(bcx, unit_ty, count, heap_exchange);
             add_clean_free(bcx, val, heap_exchange);
             let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val));
             {bcx: bcx, val: val, dataptr: dataptr}
           }
           ast::vstore_box {
-            let {bcx, val} = alloc_vec(bcx, unit_ty, args.len(),
-                                       heap_shared);
+            let {bcx, val} = alloc_vec(bcx, unit_ty, count, heap_shared);
             add_clean_free(bcx, val, heap_shared);
             let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val));
             {bcx: bcx, val: val, dataptr: dataptr}
@@ -192,12 +210,38 @@ fn trans_evec(bcx: block, args: ~[@ast::expr],
     debug!{"trans_evec: v: %s, dataptr: %s",
            val_str(ccx.tn, val),
            val_str(ccx.tn, dataptr)};
-    for vec::each(args) |e| {
-        let lleltptr = InBoundsGEP(bcx, dataptr, ~[C_uint(ccx, i)]);
-        bcx = base::trans_expr_save_in(bcx, e, lleltptr);
-        add_clean_temp_mem(bcx, lleltptr, unit_ty);
-        vec::push(temp_cleanups, lleltptr);
-        i += 1u;
+    match elements {
+        individual_evec(args) => {
+            for vec::each(args) |e| {
+                let lleltptr = InBoundsGEP(bcx, dataptr, ~[C_uint(ccx, i)]);
+                bcx = base::trans_expr_save_in(bcx, e, lleltptr);
+                add_clean_temp_mem(bcx, lleltptr, unit_ty);
+                vec::push(temp_cleanups, lleltptr);
+                i += 1u;
+            }
+        }
+        repeating_evec(e, len) => {
+            // We make temporary space in the hope that this will be
+            // friendlier to LLVM alias analysis.
+            let lltmpspace = base::alloca(bcx, llunitty);
+            bcx = base::trans_expr_save_in(bcx, e, lltmpspace);
+            add_clean_temp_mem(bcx, lltmpspace, unit_ty);
+            vec::push(temp_cleanups, lltmpspace);
+            for len.timesi |i| {
+                let lleltptr = InBoundsGEP(bcx, dataptr, ~[C_uint(ccx, i)]);
+                if i == len - 1 {
+                    // Move the last one in.
+                    bcx = move_val(bcx, INIT, lleltptr,
+                                   lval_owned(bcx, lltmpspace), unit_ty);
+                } else {
+                    // Copy all but the last one in.
+                    let llval = load_if_immediate(bcx, lltmpspace, unit_ty);
+                    bcx = copy_val(bcx, INIT, lleltptr, llval, unit_ty);
+                }
+                add_clean_temp_mem(bcx, lleltptr, unit_ty);
+                vec::push(temp_cleanups, lleltptr);
+            }
+        }
     }
 
     for vec::each(temp_cleanups) |cln| { revoke_clean(bcx, cln); }
@@ -219,13 +263,17 @@ fn trans_evec(bcx: block, args: ~[@ast::expr],
 fn trans_vstore(bcx: block, e: @ast::expr,
                 v: ast::vstore, dest: dest) -> block {
     alt e.node {
-      ast::expr_lit(@{node: ast::lit_str(s), span: _}) {
+      ast::expr_lit(@{node: ast::lit_str(s), span: _}) => {
         return trans_estr(bcx, s, some(v), dest);
       }
-      ast::expr_vec(es, mutbl) {
-        return trans_evec(bcx, es, v, e.id, dest);
+      ast::expr_vec(es, mutbl) => {
+        return trans_evec(bcx, individual_evec(es), v, e.id, dest);
       }
-      _ {
+      ast::expr_repeat(element, count_expr, mutbl) => {
+        let count = ty::eval_repeat_count(bcx.tcx(), count_expr, e.span);
+        return trans_evec(bcx, repeating_evec(element, count), v, e.id, dest);
+      }
+      _ => {
         bcx.sess().span_bug(e.span, ~"vstore on non-sequence type");
       }
     }
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 0d587e60af2..29dbccc43f5 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -169,6 +169,7 @@ export terr_proto_mismatch;
 export terr_ret_style_mismatch;
 export purity_to_str;
 export param_tys_in_type;
+export eval_repeat_count;
 
 // Data types
 
@@ -3170,6 +3171,26 @@ fn normalize_ty(cx: ctxt, t: t) -> t {
     return t_norm;
 }
 
+// Returns the repeat count for a repeating vector expression.
+fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr, span: span) -> uint {
+    match const_eval::eval_const_expr(tcx, count_expr) {
+        const_eval::const_int(count) => return count as uint,
+        const_eval::const_uint(count) => return count as uint,
+        const_eval::const_float(count) => {
+            tcx.sess.span_err(span,
+                              ~"expected signed or unsigned integer for \
+                                repeat count but found float");
+            return count as uint;
+        }
+        const_eval::const_str(_) => {
+            tcx.sess.span_err(span,
+                              ~"expected signed or unsigned integer for \
+                                repeat count but found string");
+            return 0;
+        }
+    }
+}
+
 // Local Variables:
 // mode: rust
 // fill-column: 78;
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index dd557f93b9f..1297a39c520 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -1150,26 +1150,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
                  is_loop_body, some(fcx));
     }
 
-    fn eval_repeat_count(fcx: @fn_ctxt, count_expr: @ast::expr, span: span)
-                      -> uint {
-        let tcx = fcx.ccx.tcx;
-        match const_eval::eval_const_expr(tcx, count_expr) {
-            const_eval::const_int(count) => return count as uint,
-            const_eval::const_uint(count) => return count as uint,
-            const_eval::const_float(count) => {
-                tcx.sess.span_err(span,
-                                  ~"expected signed or unsigned integer for \
-                                    repeat count but found float");
-                return count as uint;
-            }
-            const_eval::const_str(_) => {
-                tcx.sess.span_err(span,
-                                  ~"expected signed or unsigned integer for \
-                                    repeat count but found string");
-                return 0;
-            }
-        }
-    }
 
     // Check field access expressions
     fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool,
@@ -1284,7 +1264,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
             ty::mk_evec(tcx, {ty: t, mutbl: mutbl}, tt)
           }
           ast::expr_repeat(element, count_expr, mutbl) => {
-            let count = eval_repeat_count(fcx, count_expr, expr.span);
+            let count = ty::eval_repeat_count(tcx, count_expr, expr.span);
             fcx.write_ty(count_expr.id, ty::mk_uint(tcx));
             let tt = ast_expr_vstore_to_vstore(fcx, ev, count, vst);
             let t: ty::t = fcx.infcx.next_ty_var();
@@ -1642,7 +1622,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         fcx.write_ty(id, typ);
       }
       ast::expr_repeat(element, count_expr, mutbl) {
-        let count = eval_repeat_count(fcx, count_expr, expr.span);
+        let count = ty::eval_repeat_count(tcx, count_expr, expr.span);
         fcx.write_ty(count_expr.id, ty::mk_uint(tcx));
         let t: ty::t = fcx.infcx.next_ty_var();
         bot |= check_expr_with(fcx, element, t);