aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2011-01-19 16:29:14 -0800
committerGraydon Hoare <[email protected]>2011-01-19 16:29:14 -0800
commit9d3ebd6a57b51f02788331f56681e8f593d82e60 (patch)
treef3c6ea5aeafedbd73c966b80d6901474b77e6302 /src
parentLook at the type params of an item_ty when resolving. (diff)
downloadrust-9d3ebd6a57b51f02788331f56681e8f593d82e60.tar.xz
rust-9d3ebd6a57b51f02788331f56681e8f593d82e60.zip
Implement dynamic GEP enough to permit expr_field to work on tup(T,T,T).
Diffstat (limited to 'src')
-rw-r--r--src/Makefile2
-rw-r--r--src/comp/middle/trans.rs106
-rw-r--r--src/comp/middle/ty.rs23
-rw-r--r--src/test/run-pass/generic-tup.rs10
4 files changed, 139 insertions, 2 deletions
diff --git a/src/Makefile b/src/Makefile
index 628b00cb..0e039d65 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -392,6 +392,7 @@ TEST_XFAILS_BOOT := $(TASK_XFAILS) \
test/run-pass/vec-slice.rs \
test/run-pass/fn-lval.rs \
test/run-pass/generic-recursive-tag.rs \
+ test/run-pass/generic-tup.rs \
test/run-pass/iter-ret.rs \
test/run-pass/lib-io.rs \
test/run-pass/mlist-cycle.rs \
@@ -440,6 +441,7 @@ TEST_XFAILS_RUSTC := $(filter-out \
fact.rs \
generic-fn-infer.rs \
generic-drop-glue.rs \
+ generic-tup.rs \
hello.rs \
int.rs \
i32-sub.rs \
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index c3c8ee11..a96c92cf 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -732,6 +732,108 @@ fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> ValueRef {
}
}
+// Replacement for the LLVM 'GEP' instruction when field-indexing into a
+// tuple-like structure (tup, rec, tag) with a static index. This one is
+// driven off ty.struct and knows what to do when it runs into a ty_param
+// stuck in the middle of the thing it's GEP'ing into. Much like size_of and
+// align_of, above.
+
+fn GEP_tup_like(@block_ctxt cx, @ty.t t,
+ ValueRef base, vec[int] ixs) -> ValueRef {
+
+ check (ty.type_is_tup_like(t));
+
+ // It might be a static-known type. Handle this.
+
+ if (! ty.type_has_dynamic_size(t)) {
+ let vec[ValueRef] v = vec();
+ for (int i in ixs) {
+ v += C_int(i);
+ }
+ ret cx.build.GEP(base, v);
+ }
+
+ // It is a dynamic-containing type that, if we convert directly to an LLVM
+ // TypeRef, will be all wrong; there's no proper LLVM type to represent
+ // it, and the lowering function will stick in i8* values for each
+ // ty_param, which is not right; the ty_params are all of some dynamic
+ // size.
+ //
+ // What we must do instead is sadder. We must look through the indices
+ // manually and split the input type into a prefix and a target. We then
+ // measure the prefix size, bump the input pointer by that amount, and
+ // cast to a pointer-to-target type.
+
+
+ // Given a type, an index vector and an element number N in that vector,
+ // calculate index X and the type that results by taking the first X-1
+ // elements of the type and splitting the Xth off. Return the prefix as
+ // well as the innermost Xth type.
+
+ fn split_type(@ty.t t, vec[int] ixs, uint n)
+ -> rec(vec[@ty.t] prefix, @ty.t target) {
+
+ let uint len = _vec.len[int](ixs);
+
+ // We don't support 0-index or 1-index GEPs. The former is nonsense
+ // and the latter would only be meaningful if we supported non-0
+ // values for the 0th index (we don't).
+
+ check (len > 1u);
+
+ if (n == 0u) {
+ // Since we're starting from a value that's a pointer to a
+ // *single* structure, the first index (in GEP-ese) should just be
+ // 0, to yield the pointee.
+ check (ixs.(n) == 0);
+ ret split_type(t, ixs, n+1u);
+ }
+
+ check (n < len);
+
+ let int ix = ixs.(n);
+ let vec[@ty.t] prefix = vec();
+ let int i = 0;
+ while (i < ix) {
+ append[@ty.t](prefix, ty.get_element_type(t, i as uint));
+ i +=1 ;
+ }
+
+ auto selected = ty.get_element_type(t, i as uint);
+
+ if (n == len-1u) {
+ // We are at the innermost index.
+ ret rec(prefix=prefix, target=selected);
+
+ } else {
+ // Not the innermost index; call self recursively to dig deeper.
+ // Once we get an inner result, append it current prefix and
+ // return to caller.
+ auto inner = split_type(selected, ixs, n+1u);
+ prefix += inner.prefix;
+ ret rec(prefix=prefix with inner);
+ }
+ }
+
+ // We make a fake prefix tuple-type here; luckily for measuring sizes
+ // the tuple parens are associative so it doesn't matter that we've
+ // flattened the incoming structure.
+
+ auto s = split_type(t, ixs, 0u);
+ auto prefix_ty = ty.plain_ty(ty.ty_tup(s.prefix));
+ auto sz = size_of(cx, prefix_ty);
+ auto raw = cx.build.PointerCast(base, T_ptr(T_i8()));
+ auto bumped = cx.build.GEP(raw, vec(sz));
+ alt (s.target.struct) {
+ case (ty.ty_param(_)) { ret bumped; }
+ case (_) {
+ auto ty = T_ptr(type_of(cx.fcx.ccx, s.target));
+ ret cx.build.PointerCast(bumped, ty);
+ }
+ }
+}
+
+
fn trans_malloc_inner(@block_ctxt cx, TypeRef llptr_ty) -> result {
auto llbody_ty = lib.llvm.llvm.LLVMGetElementType(llptr_ty);
// FIXME: need a table to collect tydesc globals.
@@ -1969,12 +2071,12 @@ impure fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
alt (t.struct) {
case (ty.ty_tup(?fields)) {
let uint ix = ty.field_num(cx.fcx.ccx.sess, sp, field);
- auto v = r.bcx.build.GEP(r.val, vec(C_int(0), C_int(ix as int)));
+ auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
ret lval_mem(r.bcx, v);
}
case (ty.ty_rec(?fields)) {
let uint ix = ty.field_idx(cx.fcx.ccx.sess, sp, field, fields);
- auto v = r.bcx.build.GEP(r.val, vec(C_int(0), C_int(ix as int)));
+ auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
ret lval_mem(r.bcx, v);
}
case (ty.ty_obj(?methods)) {
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 531e3f85..182e2521 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -361,6 +361,29 @@ fn type_is_structural(@t ty) -> bool {
fail;
}
+fn type_is_tup_like(@t ty) -> bool {
+ alt (ty.struct) {
+ case (ty_tup(_)) { ret true; }
+ case (ty_rec(_)) { ret true; }
+ case (ty_tag(_)) { ret true; }
+ case (_) { ret false; }
+ }
+ fail;
+}
+
+fn get_element_type(@t ty, uint i) -> @t {
+ check (type_is_tup_like(ty));
+ alt (ty.struct) {
+ case (ty_tup(?tys)) {
+ ret tys.(i);
+ }
+ case (ty_rec(?flds)) {
+ ret flds.(i).ty;
+ }
+ }
+ fail;
+}
+
fn type_is_boxed(@t ty) -> bool {
alt (ty.struct) {
case (ty_str) { ret true; }
diff --git a/src/test/run-pass/generic-tup.rs b/src/test/run-pass/generic-tup.rs
new file mode 100644
index 00000000..29a66371
--- /dev/null
+++ b/src/test/run-pass/generic-tup.rs
@@ -0,0 +1,10 @@
+
+fn get_third[T](&tup(T,T,T) t) -> T {
+ ret t._2;
+}
+
+fn main() {
+ log get_third(tup(1,2,3));
+ check (get_third(tup(1,2,3)) == 3);
+ check (get_third(tup(5u8,6u8,7u8)) == 7u8);
+} \ No newline at end of file