Skip to content

Special-casing iter_vec_raw to use a counter for zero-size types (Closes #9890). #10172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 30, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 97 additions & 71 deletions src/librustc/middle/trans/tvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use middle::trans::datum::*;
use middle::trans::expr::{Dest, Ignore, SaveIn};
use middle::trans::expr;
use middle::trans::glue;
use middle::trans::machine::{llsize_of, nonzero_llsize_of};
use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
use middle::trans::type_of;
use middle::ty;
use util::common::indenter;
Expand Down Expand Up @@ -144,16 +144,19 @@ pub struct VecTypes {
vec_ty: ty::t,
unit_ty: ty::t,
llunit_ty: Type,
llunit_size: ValueRef
llunit_size: ValueRef,
llunit_alloc_size: uint
}

impl VecTypes {
pub fn to_str(&self, ccx: &CrateContext) -> ~str {
format!("VecTypes \\{vec_ty={}, unit_ty={}, llunit_ty={}, llunit_size={}\\}",
format!("VecTypes \\{vec_ty={}, unit_ty={}, llunit_ty={}, llunit_size={}, \
llunit_alloc_size={}\\}",
ty_to_str(ccx.tcx, self.vec_ty),
ty_to_str(ccx.tcx, self.unit_ty),
ccx.tn.type_to_str(self.llunit_ty),
ccx.tn.val_to_str(self.llunit_size))
ccx.tn.val_to_str(self.llunit_size),
self.llunit_alloc_size)
}
}

Expand Down Expand Up @@ -416,48 +419,10 @@ pub fn write_content(bcx: @mut Block,
expr::trans_to_datum(bcx, element)
});

let next_bcx = sub_block(bcx, "expr_repeat: while next");
let loop_bcx = loop_scope_block(bcx, next_bcx, None, "expr_repeat", None);
let cond_bcx = scope_block(loop_bcx, None, "expr_repeat: loop cond");
let set_bcx = scope_block(loop_bcx, None, "expr_repeat: body: set");
let inc_bcx = scope_block(loop_bcx, None, "expr_repeat: body: inc");
Br(bcx, loop_bcx.llbb);

let loop_counter = {
// i = 0
let i = alloca(loop_bcx, bcx.ccx().int_type, "__i");
Store(loop_bcx, C_uint(bcx.ccx(), 0), i);

Br(loop_bcx, cond_bcx.llbb);
i
};

{ // i < count
let lhs = Load(cond_bcx, loop_counter);
let rhs = C_uint(bcx.ccx(), count);
let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs);

CondBr(cond_bcx, cond_val, set_bcx.llbb, next_bcx.llbb);
}

{ // v[i] = elem
let i = Load(set_bcx, loop_counter);
let lleltptr = InBoundsGEP(set_bcx, lldest, [i]);
let set_bcx = elem.copy_to(set_bcx, INIT, lleltptr);

Br(set_bcx, inc_bcx.llbb);
}

{ // i += 1
let i = Load(inc_bcx, loop_counter);
let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1));
Store(inc_bcx, plusone, loop_counter);

Br(inc_bcx, cond_bcx.llbb);
}

return next_bcx;

iter_vec_loop(bcx, lldest, vt,
C_uint(bcx.ccx(), count), |set_bcx, lleltptr, _| {
elem.copy_to(set_bcx, INIT, lleltptr)
})
}
}
}
Expand All @@ -478,11 +443,13 @@ pub fn vec_types(bcx: @mut Block, vec_ty: ty::t) -> VecTypes {
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
let llunit_ty = type_of::type_of(ccx, unit_ty);
let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);

VecTypes {vec_ty: vec_ty,
unit_ty: unit_ty,
llunit_ty: llunit_ty,
llunit_size: llunit_size}
llunit_size: llunit_size,
llunit_alloc_size: llunit_alloc_size}
}

pub fn elements_required(bcx: @mut Block, content_expr: &ast::Expr) -> uint {
Expand Down Expand Up @@ -574,35 +541,94 @@ pub fn get_base_and_len(bcx: @mut Block, llval: ValueRef, vec_ty: ty::t) -> (Val

pub type iter_vec_block<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block;

pub fn iter_vec_loop(bcx: @mut Block,
data_ptr: ValueRef,
vt: &VecTypes,
count: ValueRef,
f: iter_vec_block
) -> @mut Block {
let _icx = push_ctxt("tvec::iter_vec_loop");

let next_bcx = sub_block(bcx, "iter_vec_loop: while next");
let loop_bcx = loop_scope_block(bcx, next_bcx, None, "iter_vec_loop", None);
let cond_bcx = scope_block(loop_bcx, None, "iter_vec_loop: loop cond");
let body_bcx = scope_block(loop_bcx, None, "iter_vec_loop: body: main");
let inc_bcx = scope_block(loop_bcx, None, "iter_vec_loop: loop inc");
Br(bcx, loop_bcx.llbb);

let loop_counter = {
// i = 0
let i = alloca(loop_bcx, bcx.ccx().int_type, "__i");
Store(loop_bcx, C_uint(bcx.ccx(), 0), i);

Br(loop_bcx, cond_bcx.llbb);
i
};

{ // i < count
let lhs = Load(cond_bcx, loop_counter);
let rhs = count;
let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs);

CondBr(cond_bcx, cond_val, body_bcx.llbb, next_bcx.llbb);
}

{ // loop body
let i = Load(body_bcx, loop_counter);
let lleltptr = if vt.llunit_alloc_size == 0 {
data_ptr
} else {
InBoundsGEP(body_bcx, data_ptr, [i])
};
let body_bcx = f(body_bcx, lleltptr, vt.unit_ty);

Br(body_bcx, inc_bcx.llbb);
}

{ // i += 1
let i = Load(inc_bcx, loop_counter);
let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1));
Store(inc_bcx, plusone, loop_counter);

Br(inc_bcx, cond_bcx.llbb);
}

next_bcx
}

pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t,
fill: ValueRef, f: iter_vec_block) -> @mut Block {
let _icx = push_ctxt("tvec::iter_vec_raw");

let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);

// Calculate the last pointer address we want to handle.
// FIXME (#3729): Optimize this when the size of the unit type is
// statically known to not use pointer casts, which tend to confuse
// LLVM.
let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);

// Now perform the iteration.
let header_bcx = base::sub_block(bcx, "iter_vec_loop_header");
Br(bcx, header_bcx.llbb);
let data_ptr =
Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
let not_yet_at_end =
ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body");
let next_bcx = base::sub_block(header_bcx, "iter_vec_next");
CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
let body_bcx = f(body_bcx, data_ptr, unit_ty);
AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
[C_int(bcx.ccx(), 1)]),
body_bcx.llbb);
Br(body_bcx, header_bcx.llbb);
return next_bcx;
let vt = vec_types(bcx, vec_ty);
if (vt.llunit_alloc_size == 0) {
// Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
iter_vec_loop(bcx, data_ptr, &vt, fill, f)
} else {
// Calculate the last pointer address we want to handle.
// FIXME (#3729): Optimize this when the size of the unit type is
// statically known to not use pointer casts, which tend to confuse
// LLVM.
let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);

// Now perform the iteration.
let header_bcx = base::sub_block(bcx, "iter_vec_loop_header");
Br(bcx, header_bcx.llbb);
let data_ptr =
Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
let not_yet_at_end =
ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body");
let next_bcx = base::sub_block(header_bcx, "iter_vec_next");
CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
let body_bcx = f(body_bcx, data_ptr, vt.unit_ty);
AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
[C_int(bcx.ccx(), 1)]),
body_bcx.llbb);
Br(body_bcx, header_bcx.llbb);
next_bcx

}
}

pub fn iter_vec_uniq(bcx: @mut Block, vptr: ValueRef, vec_ty: ty::t,
Expand Down
29 changes: 29 additions & 0 deletions src/test/run-pass/zero-size-type-destructors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

static mut destructions : int = 3;

pub fn foo() {
#[unsafe_no_drop_flag]
struct Foo;

impl Drop for Foo {
fn drop(&mut self) {
unsafe { destructions -= 1 };
}
};

let _x = [Foo, Foo, Foo];
}

pub fn main() {
foo();
assert!((unsafe { destructions } == 0));
}