Skip to content

Commit 9d6c251

Browse files
committed
auto merge of #9885 : thestinger/rust/vector, r=brson
The goal here is to avoid requiring a division or multiplication to compare against the length. The bounds check previously used an incorrect micro-optimization to replace the division by a multiplication, but now neither is necessary *for slices*. Unique/managed vectors will have to do a division to get the length until they are reworked/replaced.
2 parents fa03c94 + bd7610f commit 9d6c251

File tree

15 files changed

+236
-139
lines changed

15 files changed

+236
-139
lines changed

src/librustc/middle/trans/_match.rs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,8 +1025,7 @@ fn extract_vec_elems(bcx: @mut Block,
10251025
-> ExtractedBlock {
10261026
let _icx = push_ctxt("match::extract_vec_elems");
10271027
let vec_datum = match_datum(bcx, val, pat_id);
1028-
let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span,
1029-
pat_id, 0);
1028+
let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, pat_id, 0);
10301029
let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));
10311030

10321031
let mut elems = do vec::from_fn(elem_count) |i| {
@@ -1043,13 +1042,9 @@ fn extract_vec_elems(bcx: @mut Block,
10431042
};
10441043
if slice.is_some() {
10451044
let n = slice.unwrap();
1046-
let slice_offset = Mul(bcx, vt.llunit_size,
1047-
C_int(bcx.ccx(), n as int)
1048-
);
1049-
let slice_begin = tvec::pointer_add(bcx, base, slice_offset);
1050-
let slice_len_offset = Mul(bcx, vt.llunit_size,
1051-
C_int(bcx.ccx(), (elem_count - 1u) as int)
1052-
);
1045+
let slice_byte_offset = Mul(bcx, vt.llunit_size, C_uint(bcx.ccx(), n));
1046+
let slice_begin = tvec::pointer_add_byte(bcx, base, slice_byte_offset);
1047+
let slice_len_offset = C_uint(bcx.ccx(), elem_count - 1u);
10531048
let slice_len = Sub(bcx, len, slice_len_offset);
10541049
let slice_ty = ty::mk_evec(bcx.tcx(),
10551050
ty::mt {ty: vt.unit_ty, mutbl: ast::MutImmutable},
@@ -1059,9 +1054,7 @@ fn extract_vec_elems(bcx: @mut Block,
10591054
Store(bcx, slice_begin,
10601055
GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])
10611056
);
1062-
Store(bcx, slice_len,
1063-
GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])
1064-
);
1057+
Store(bcx, slice_len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
10651058
elems[n] = scratch.val;
10661059
scratch.add_clean(bcx);
10671060
}
@@ -1647,10 +1640,8 @@ fn compile_submatch_continue(mut bcx: @mut Block,
16471640
vec_len(*) => {
16481641
let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));
16491642
let unboxed = load_if_immediate(bcx, val, vt.vec_ty);
1650-
let (_, len) = tvec::get_base_and_len(
1651-
bcx, unboxed, vt.vec_ty
1652-
);
1653-
test_val = SDiv(bcx, len, vt.llunit_size);
1643+
let (_, len) = tvec::get_base_and_len(bcx, unboxed, vt.vec_ty);
1644+
test_val = len;
16541645
kind = compare_vec_len;
16551646
}
16561647
}

src/librustc/middle/trans/base.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use middle::trans::glue;
5454
use middle::trans::inline;
5555
use middle::trans::llrepr::LlvmRepr;
5656
use middle::trans::machine;
57-
use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_alloc};
57+
use middle::trans::machine::{llalign_of_min, llsize_of};
5858
use middle::trans::meth;
5959
use middle::trans::monomorphize;
6060
use middle::trans::tvec;
@@ -745,7 +745,7 @@ pub fn iter_structural_ty(cx: @mut Block, av: ValueRef, t: ty::t,
745745
}
746746
ty::ty_estr(ty::vstore_fixed(_)) |
747747
ty::ty_evec(_, ty::vstore_fixed(_)) => {
748-
let (base, len) = tvec::get_base_and_len(cx, av, t);
748+
let (base, len) = tvec::get_base_and_byte_len(cx, av, t);
749749
cx = tvec::iter_vec_raw(cx, base, t, len, f);
750750
}
751751
ty::ty_tup(ref args) => {
@@ -2910,7 +2910,7 @@ pub fn decl_gc_metadata(ccx: &mut CrateContext, llmod_id: &str) {
29102910
}
29112911
}
29122912

2913-
pub fn create_module_map(ccx: &mut CrateContext) -> (ValueRef, uint, uint) {
2913+
pub fn create_module_map(ccx: &mut CrateContext) -> (ValueRef, uint) {
29142914
let str_slice_type = Type::struct_([Type::i8p(), ccx.int_type], false);
29152915
let elttype = Type::struct_([str_slice_type, ccx.int_type], false);
29162916
let maptype = Type::array(&elttype, ccx.module_data.len() as u64);
@@ -2942,7 +2942,7 @@ pub fn create_module_map(ccx: &mut CrateContext) -> (ValueRef, uint, uint) {
29422942
unsafe {
29432943
llvm::LLVMSetInitializer(map, C_array(elttype, elts));
29442944
}
2945-
return (map, keys.len(), llsize_of_alloc(ccx, elttype));
2945+
return (map, keys.len())
29462946
}
29472947

29482948

@@ -3004,19 +3004,17 @@ pub fn fill_crate_map(ccx: &mut CrateContext, map: ValueRef) {
30043004
lib::llvm::SetLinkage(vec_elements, lib::llvm::InternalLinkage);
30053005

30063006
llvm::LLVMSetInitializer(vec_elements, C_array(ccx.int_type, subcrates));
3007-
let (mod_map, mod_count, mod_struct_size) = create_module_map(ccx);
3007+
let (mod_map, mod_count) = create_module_map(ccx);
30083008

30093009
llvm::LLVMSetInitializer(map, C_struct(
30103010
[C_i32(2),
30113011
C_struct([
30123012
p2i(ccx, mod_map),
3013-
// byte size of the module map array, an entry consists of two integers
3014-
C_int(ccx, ((mod_count * mod_struct_size) as int))
3013+
C_uint(ccx, mod_count)
30153014
], false),
30163015
C_struct([
30173016
p2i(ccx, vec_elements),
3018-
// byte size of the subcrates array, an entry consists of an integer
3019-
C_int(ccx, (subcrates.len() * llsize_of_alloc(ccx, ccx.int_type)) as int)
3017+
C_uint(ccx, subcrates.len())
30203018
], false)
30213019
], false));
30223020
}

src/librustc/middle/trans/consts.rs

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -83,23 +83,18 @@ pub fn const_ptrcast(cx: &mut CrateContext, a: ValueRef, t: Type) -> ValueRef {
8383
}
8484
}
8585

86-
pub fn const_vec(cx: @mut CrateContext, e: &ast::Expr, es: &[@ast::Expr])
87-
-> (ValueRef, ValueRef, Type, bool) {
88-
unsafe {
89-
let vec_ty = ty::expr_ty(cx.tcx, e);
90-
let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
91-
let llunitty = type_of::type_of(cx, unit_ty);
92-
let unit_sz = machine::llsize_of(cx, llunitty);
93-
let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz);
94-
let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e)));
95-
// If the vector contains enums, an LLVM array won't work.
96-
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
97-
C_struct(vs, false)
98-
} else {
99-
C_array(llunitty, vs)
100-
};
101-
return (v, sz, llunitty, inlineable.iter().fold(true, |a, &b| a && b));
102-
}
86+
fn const_vec(cx: @mut CrateContext, e: &ast::Expr, es: &[@ast::Expr]) -> (ValueRef, Type, bool) {
87+
let vec_ty = ty::expr_ty(cx.tcx, e);
88+
let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
89+
let llunitty = type_of::type_of(cx, unit_ty);
90+
let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e)));
91+
// If the vector contains enums, an LLVM array won't work.
92+
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
93+
C_struct(vs, false)
94+
} else {
95+
C_array(llunitty, vs)
96+
};
97+
(v, llunitty, inlineable.iter().fold(true, |a, &b| a && b))
10398
}
10499

105100
fn const_addr_of(cx: &mut CrateContext, cv: ValueRef) -> ValueRef {
@@ -225,9 +220,8 @@ pub fn const_expr(cx: @mut CrateContext, e: &ast::Expr) -> (ValueRef, bool) {
225220
assert_eq!(abi::slice_elt_len, 1);
226221

227222
match ty::get(ty).sty {
228-
ty::ty_evec(_, ty::vstore_fixed(*)) => {
229-
let size = machine::llsize_of(cx, val_ty(llconst));
230-
llconst = C_struct([llptr, size], false);
223+
ty::ty_evec(_, ty::vstore_fixed(len)) => {
224+
llconst = C_struct([llptr, C_uint(cx, len)], false);
231225
}
232226
_ => {}
233227
}
@@ -412,14 +406,8 @@ fn const_expr_unadjusted(cx: @mut CrateContext,
412406
(bv, C_uint(cx, u)),
413407

414408
ty::vstore_slice(_) => {
415-
let unit_ty = ty::sequence_element_type(cx.tcx, bt);
416-
let llunitty = type_of::type_of(cx, unit_ty);
417-
let unit_sz = machine::llsize_of(cx, llunitty);
418-
419409
let e1 = const_get_elt(cx, bv, [0]);
420-
(const_deref_ptr(cx, e1),
421-
llvm::LLVMConstUDiv(const_get_elt(cx, bv, [1]),
422-
unit_sz))
410+
(const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
423411
},
424412
_ => cx.sess.span_bug(base.span,
425413
"index-expr base must be fixed-size or slice")
@@ -538,7 +526,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext,
538526
}
539527
}
540528
ast::ExprVec(ref es, ast::MutImmutable) => {
541-
let (v, _, _, inlineable) = const_vec(cx, e, *es);
529+
let (v, _, inlineable) = const_vec(cx, e, *es);
542530
(v, inlineable)
543531
}
544532
ast::ExprVstore(sub, ast::ExprVstoreSlice) => {
@@ -550,7 +538,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext,
550538
}
551539
}
552540
ast::ExprVec(ref es, ast::MutImmutable) => {
553-
let (cv, sz, llunitty, _) = const_vec(cx, e, *es);
541+
let (cv, llunitty, _) = const_vec(cx, e, *es);
554542
let llty = val_ty(cv);
555543
let gv = do "const".with_c_str |name| {
556544
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
@@ -559,7 +547,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext,
559547
llvm::LLVMSetGlobalConstant(gv, True);
560548
SetLinkage(gv, PrivateLinkage);
561549
let p = const_ptrcast(cx, gv, llunitty);
562-
(C_struct([p, sz], false), false)
550+
(C_struct([p, C_uint(cx, es.len())], false), false)
563551
}
564552
_ => cx.sess.span_bug(e.span, "bad const-slice expr")
565553
}

src/librustc/middle/trans/datum.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -770,12 +770,36 @@ impl Datum {
770770
DatumBlock { bcx: bcx, datum: datum }
771771
}
772772

773+
pub fn get_vec_base_and_byte_len(&self,
774+
mut bcx: @mut Block,
775+
span: Span,
776+
expr_id: ast::NodeId,
777+
derefs: uint)
778+
-> (@mut Block, ValueRef, ValueRef) {
779+
//! Converts a vector into the slice pair. Performs rooting
780+
//! and write guards checks.
781+
782+
// only imp't for @[] and @str, but harmless
783+
bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs);
784+
let (base, len) = self.get_vec_base_and_byte_len_no_root(bcx);
785+
(bcx, base, len)
786+
}
787+
788+
pub fn get_vec_base_and_byte_len_no_root(&self, bcx: @mut Block)
789+
-> (ValueRef, ValueRef) {
790+
//! Converts a vector into the slice pair. Des not root
791+
//! nor perform write guard checks.
792+
793+
let llval = self.to_appropriate_llval(bcx);
794+
tvec::get_base_and_byte_len(bcx, llval, self.ty)
795+
}
796+
773797
pub fn get_vec_base_and_len(&self,
774-
mut bcx: @mut Block,
775-
span: Span,
776-
expr_id: ast::NodeId,
777-
derefs: uint)
778-
-> (@mut Block, ValueRef, ValueRef) {
798+
mut bcx: @mut Block,
799+
span: Span,
800+
expr_id: ast::NodeId,
801+
derefs: uint)
802+
-> (@mut Block, ValueRef, ValueRef) {
779803
//! Converts a vector into the slice pair. Performs rooting
780804
//! and write guards checks.
781805
@@ -786,7 +810,7 @@ impl Datum {
786810
}
787811

788812
pub fn get_vec_base_and_len_no_root(&self, bcx: @mut Block)
789-
-> (ValueRef, ValueRef) {
813+
-> (ValueRef, ValueRef) {
790814
//! Converts a vector into the slice pair. Des not root
791815
//! nor perform write guard checks.
792816

src/librustc/middle/trans/debuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1867,7 +1867,7 @@ fn vec_slice_metadata(cx: &mut CrateContext,
18671867
offset: ComputedMemberOffset,
18681868
},
18691869
MemberDescription {
1870-
name: @"size_in_bytes",
1870+
name: @"length",
18711871
llvm_type: member_llvm_types[1],
18721872
type_metadata: type_metadata(cx, ty::mk_uint(), span),
18731873
offset: ComputedMemberOffset,

src/librustc/middle/trans/expr.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ pub fn trans_to_datum(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock {
274274
ty::vstore_slice(ty::re_static));
275275

276276
let scratch = scratch_datum(bcx, slice_ty, "__adjust", false);
277+
277278
Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
278279
Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
279280
DatumBlock {bcx: bcx, datum: scratch}
@@ -972,21 +973,16 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock {
972973

973974
let vt = tvec::vec_types(bcx, base_datum.ty);
974975
base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
975-
let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
976-
base::maybe_name_value(bcx.ccx(), scaled_ix, "scaled_ix");
977976

978977
let (bcx, base, len) =
979-
base_datum.get_vec_base_and_len(bcx, index_expr.span,
980-
index_expr.id, 0);
978+
base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id, 0);
981979

982980
debug2!("trans_index: base {}", bcx.val_to_str(base));
983981
debug2!("trans_index: len {}", bcx.val_to_str(len));
984982

985-
let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
983+
let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
986984
let bcx = do with_cond(bcx, bounds_check) |bcx| {
987-
let unscaled_len = UDiv(bcx, len, vt.llunit_size);
988-
controlflow::trans_fail_bounds_check(bcx, index_expr.span,
989-
ix_val, unscaled_len)
985+
controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
990986
};
991987
let elt = InBoundsGEP(bcx, base, [ix_val]);
992988
let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());

src/librustc/middle/trans/tvec.rs

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ pub fn get_dataptr(bcx: @mut Block, vptr: ValueRef) -> ValueRef {
7777
GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
7878
}
7979

80-
pub fn pointer_add(bcx: @mut Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
81-
let _icx = push_ctxt("tvec::pointer_add");
80+
pub fn pointer_add_byte(bcx: @mut Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
81+
let _icx = push_ctxt("tvec::pointer_add_byte");
8282
let old_ty = val_ty(ptr);
8383
let bptr = PointerCast(bcx, ptr, Type::i8p());
8484
return PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty);
@@ -237,8 +237,7 @@ pub fn trans_slice_vstore(bcx: @mut Block,
237237
Ignore => {}
238238
SaveIn(lldest) => {
239239
Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
240-
let lllen = Mul(bcx, llcount, vt.llunit_size);
241-
Store(bcx, lllen, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
240+
Store(bcx, llcount, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
242241
}
243242
}
244243

@@ -502,15 +501,14 @@ pub fn elements_required(bcx: @mut Block, content_expr: &ast::Expr) -> uint {
502501
}
503502
}
504503

505-
pub fn get_base_and_len(bcx: @mut Block,
506-
llval: ValueRef,
504+
pub fn get_base_and_byte_len(bcx: @mut Block, llval: ValueRef,
507505
vec_ty: ty::t) -> (ValueRef, ValueRef) {
508506
//!
509507
//
510508
// Converts a vector into the slice pair. The vector should be stored in
511509
// `llval` which should be either immediate or by-ref as appropriate for
512510
// the vector type. If you have a datum, you would probably prefer to
513-
// call `Datum::get_base_and_len()` which will handle any conversions for
511+
// call `Datum::get_base_and_byte_len()` which will handle any conversions for
514512
// you.
515513

516514
let ccx = bcx.ccx();
@@ -529,7 +527,8 @@ pub fn get_base_and_len(bcx: @mut Block,
529527
}
530528
ty::vstore_slice(_) => {
531529
let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
532-
let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
530+
let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
531+
let len = Mul(bcx, count, vt.llunit_size);
533532
(base, len)
534533
}
535534
ty::vstore_uniq | ty::vstore_box => {
@@ -539,6 +538,40 @@ pub fn get_base_and_len(bcx: @mut Block,
539538
}
540539
}
541540

541+
pub fn get_base_and_len(bcx: @mut Block, llval: ValueRef, vec_ty: ty::t) -> (ValueRef, ValueRef) {
542+
//!
543+
//
544+
// Converts a vector into the slice pair. The vector should be stored in
545+
// `llval` which should be either immediate or by-ref as appropriate for
546+
// the vector type. If you have a datum, you would probably prefer to
547+
// call `Datum::get_base_and_len()` which will handle any conversions for
548+
// you.
549+
550+
let ccx = bcx.ccx();
551+
let vt = vec_types(bcx, vec_ty);
552+
553+
let vstore = match ty::get(vt.vec_ty).sty {
554+
ty::ty_estr(vst) | ty::ty_evec(_, vst) => vst,
555+
_ => ty::vstore_uniq
556+
};
557+
558+
match vstore {
559+
ty::vstore_fixed(n) => {
560+
let base = GEPi(bcx, llval, [0u, 0u]);
561+
(base, C_uint(ccx, n))
562+
}
563+
ty::vstore_slice(_) => {
564+
let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
565+
let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
566+
(base, count)
567+
}
568+
ty::vstore_uniq | ty::vstore_box => {
569+
let body = get_bodyptr(bcx, llval, vec_ty);
570+
(get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size))
571+
}
572+
}
573+
}
574+
542575
pub type iter_vec_block<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block;
543576

544577
pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t,
@@ -551,7 +584,7 @@ pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t,
551584
// FIXME (#3729): Optimize this when the size of the unit type is
552585
// statically known to not use pointer casts, which tend to confuse
553586
// LLVM.
554-
let data_end_ptr = pointer_add(bcx, data_ptr, fill);
587+
let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
555588

556589
// Now perform the iteration.
557590
let header_bcx = base::sub_block(bcx, "iter_vec_loop_header");

0 commit comments

Comments
 (0)