Skip to content

Commit 9d3ebd6

Browse files
committed
Implement dynamic GEP enough to permit expr_field to work on tup(T,T,T).
1 parent 35d53b7 commit 9d3ebd6

File tree

4 files changed

+139
-2
lines changed

4 files changed

+139
-2
lines changed

src/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ TEST_XFAILS_BOOT := $(TASK_XFAILS) \
392392
test/run-pass/vec-slice.rs \
393393
test/run-pass/fn-lval.rs \
394394
test/run-pass/generic-recursive-tag.rs \
395+
test/run-pass/generic-tup.rs \
395396
test/run-pass/iter-ret.rs \
396397
test/run-pass/lib-io.rs \
397398
test/run-pass/mlist-cycle.rs \
@@ -440,6 +441,7 @@ TEST_XFAILS_RUSTC := $(filter-out \
440441
fact.rs \
441442
generic-fn-infer.rs \
442443
generic-drop-glue.rs \
444+
generic-tup.rs \
443445
hello.rs \
444446
int.rs \
445447
i32-sub.rs \

src/comp/middle/trans.rs

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,108 @@ fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> ValueRef {
732732
}
733733
}
734734

735+
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
736+
// tuple-like structure (tup, rec, tag) with a static index. This one is
737+
// driven off ty.struct and knows what to do when it runs into a ty_param
738+
// stuck in the middle of the thing it's GEP'ing into. Much like size_of and
739+
// align_of, above.
740+
741+
fn GEP_tup_like(@block_ctxt cx, @ty.t t,
742+
ValueRef base, vec[int] ixs) -> ValueRef {
743+
744+
check (ty.type_is_tup_like(t));
745+
746+
// It might be a static-known type. Handle this.
747+
748+
if (! ty.type_has_dynamic_size(t)) {
749+
let vec[ValueRef] v = vec();
750+
for (int i in ixs) {
751+
v += C_int(i);
752+
}
753+
ret cx.build.GEP(base, v);
754+
}
755+
756+
// It is a dynamic-containing type that, if we convert directly to an LLVM
757+
// TypeRef, will be all wrong; there's no proper LLVM type to represent
758+
// it, and the lowering function will stick in i8* values for each
759+
// ty_param, which is not right; the ty_params are all of some dynamic
760+
// size.
761+
//
762+
// What we must do instead is sadder. We must look through the indices
763+
// manually and split the input type into a prefix and a target. We then
764+
// measure the prefix size, bump the input pointer by that amount, and
765+
// cast to a pointer-to-target type.
766+
767+
768+
// Given a type, an index vector and an element number N in that vector,
769+
// calculate index X and the type that results by taking the first X-1
770+
// elements of the type and splitting the Xth off. Return the prefix as
771+
// well as the innermost Xth type.
772+
773+
fn split_type(@ty.t t, vec[int] ixs, uint n)
774+
-> rec(vec[@ty.t] prefix, @ty.t target) {
775+
776+
let uint len = _vec.len[int](ixs);
777+
778+
// We don't support 0-index or 1-index GEPs. The former is nonsense
779+
// and the latter would only be meaningful if we supported non-0
780+
// values for the 0th index (we don't).
781+
782+
check (len > 1u);
783+
784+
if (n == 0u) {
785+
// Since we're starting from a value that's a pointer to a
786+
// *single* structure, the first index (in GEP-ese) should just be
787+
// 0, to yield the pointee.
788+
check (ixs.(n) == 0);
789+
ret split_type(t, ixs, n+1u);
790+
}
791+
792+
check (n < len);
793+
794+
let int ix = ixs.(n);
795+
let vec[@ty.t] prefix = vec();
796+
let int i = 0;
797+
while (i < ix) {
798+
append[@ty.t](prefix, ty.get_element_type(t, i as uint));
799+
i +=1 ;
800+
}
801+
802+
auto selected = ty.get_element_type(t, i as uint);
803+
804+
if (n == len-1u) {
805+
// We are at the innermost index.
806+
ret rec(prefix=prefix, target=selected);
807+
808+
} else {
809+
// Not the innermost index; call self recursively to dig deeper.
810+
// Once we get an inner result, append it current prefix and
811+
// return to caller.
812+
auto inner = split_type(selected, ixs, n+1u);
813+
prefix += inner.prefix;
814+
ret rec(prefix=prefix with inner);
815+
}
816+
}
817+
818+
// We make a fake prefix tuple-type here; luckily for measuring sizes
819+
// the tuple parens are associative so it doesn't matter that we've
820+
// flattened the incoming structure.
821+
822+
auto s = split_type(t, ixs, 0u);
823+
auto prefix_ty = ty.plain_ty(ty.ty_tup(s.prefix));
824+
auto sz = size_of(cx, prefix_ty);
825+
auto raw = cx.build.PointerCast(base, T_ptr(T_i8()));
826+
auto bumped = cx.build.GEP(raw, vec(sz));
827+
alt (s.target.struct) {
828+
case (ty.ty_param(_)) { ret bumped; }
829+
case (_) {
830+
auto ty = T_ptr(type_of(cx.fcx.ccx, s.target));
831+
ret cx.build.PointerCast(bumped, ty);
832+
}
833+
}
834+
}
835+
836+
735837
fn trans_malloc_inner(@block_ctxt cx, TypeRef llptr_ty) -> result {
736838
auto llbody_ty = lib.llvm.llvm.LLVMGetElementType(llptr_ty);
737839
// 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,
19692071
alt (t.struct) {
19702072
case (ty.ty_tup(?fields)) {
19712073
let uint ix = ty.field_num(cx.fcx.ccx.sess, sp, field);
1972-
auto v = r.bcx.build.GEP(r.val, vec(C_int(0), C_int(ix as int)));
2074+
auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
19732075
ret lval_mem(r.bcx, v);
19742076
}
19752077
case (ty.ty_rec(?fields)) {
19762078
let uint ix = ty.field_idx(cx.fcx.ccx.sess, sp, field, fields);
1977-
auto v = r.bcx.build.GEP(r.val, vec(C_int(0), C_int(ix as int)));
2079+
auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
19782080
ret lval_mem(r.bcx, v);
19792081
}
19802082
case (ty.ty_obj(?methods)) {

src/comp/middle/ty.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,29 @@ fn type_is_structural(@t ty) -> bool {
361361
fail;
362362
}
363363

364+
fn type_is_tup_like(@t ty) -> bool {
365+
alt (ty.struct) {
366+
case (ty_tup(_)) { ret true; }
367+
case (ty_rec(_)) { ret true; }
368+
case (ty_tag(_)) { ret true; }
369+
case (_) { ret false; }
370+
}
371+
fail;
372+
}
373+
374+
fn get_element_type(@t ty, uint i) -> @t {
375+
check (type_is_tup_like(ty));
376+
alt (ty.struct) {
377+
case (ty_tup(?tys)) {
378+
ret tys.(i);
379+
}
380+
case (ty_rec(?flds)) {
381+
ret flds.(i).ty;
382+
}
383+
}
384+
fail;
385+
}
386+
364387
fn type_is_boxed(@t ty) -> bool {
365388
alt (ty.struct) {
366389
case (ty_str) { ret true; }

src/test/run-pass/generic-tup.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
fn get_third[T](&tup(T,T,T) t) -> T {
3+
ret t._2;
4+
}
5+
6+
fn main() {
7+
log get_third(tup(1,2,3));
8+
check (get_third(tup(1,2,3)) == 3);
9+
check (get_third(tup(5u8,6u8,7u8)) == 7u8);
10+
}

0 commit comments

Comments
 (0)