Auto merge of #27999 - dotdash:lt, r=eddyb

The major change here is in the tiny commit at the end and makes it so that we no longer emit lifetime intrinsics for allocas for function arguments. They are live for the whole function anyway, so the intrinsics add no value. This makes the resulting IR more clear, and reduces the peak memory usage and LLVM times by about 1-4%, depending on the crate.

The remaining changes are just preparatory cleanups and fixes for missing lifetime intrinsics.
This commit is contained in:
bors 2015-08-27 20:09:15 +00:00
commit abfa081c10
11 changed files with 72 additions and 68 deletions

View file

@ -875,8 +875,10 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
fn compare_str<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
lhs_data: ValueRef,
lhs_len: ValueRef,
rhs_data: ValueRef,
rhs_len: ValueRef,
rhs_t: Ty<'tcx>,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
@ -884,10 +886,6 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
None,
&format!("comparison of `{}`", rhs_t),
StrEqFnLangItem);
let lhs_data = Load(cx, expr::get_dataptr(cx, lhs));
let lhs_len = Load(cx, expr::get_meta(cx, lhs));
let rhs_data = Load(cx, expr::get_dataptr(cx, rhs));
let rhs_len = Load(cx, expr::get_meta(cx, rhs));
callee::trans_lang_call(cx, did, &[lhs_data, lhs_len, rhs_data, rhs_len], None, debug_loc)
}
@ -899,7 +897,13 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
match rhs_t.sty {
ty::TyRef(_, mt) => match mt.ty.sty {
ty::TyStr => compare_str(cx, lhs, rhs, rhs_t, debug_loc),
ty::TyStr => {
let lhs_data = Load(cx, expr::get_dataptr(cx, lhs));
let lhs_len = Load(cx, expr::get_meta(cx, lhs));
let rhs_data = Load(cx, expr::get_dataptr(cx, rhs));
let rhs_len = Load(cx, expr::get_meta(cx, rhs));
compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc)
}
ty::TyArray(ty, _) | ty::TySlice(ty) => match ty.sty {
ty::TyUint(ast::TyU8) => {
// NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item,
@ -907,24 +911,24 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
let pat_len = val_ty(rhs).element_type().array_length();
let ty_str_slice = cx.tcx().mk_static_str();
let rhs_str = alloc_ty(cx, ty_str_slice, "rhs_str");
Store(cx, expr::get_dataptr(cx, rhs), expr::get_dataptr(cx, rhs_str));
Store(cx, C_uint(cx.ccx(), pat_len), expr::get_meta(cx, rhs_str));
let rhs_data = GEPi(cx, rhs, &[0, 0]);
let rhs_len = C_uint(cx.ccx(), pat_len);
let lhs_str;
let lhs_data;
let lhs_len;
if val_ty(lhs) == val_ty(rhs) {
// Both the discriminant and the pattern are thin pointers
lhs_str = alloc_ty(cx, ty_str_slice, "lhs_str");
Store(cx, expr::get_dataptr(cx, lhs), expr::get_dataptr(cx, lhs_str));
Store(cx, C_uint(cx.ccx(), pat_len), expr::get_meta(cx, lhs_str));
}
else {
lhs_data = GEPi(cx, lhs, &[0, 0]);
lhs_len = C_uint(cx.ccx(), pat_len);
} else {
// The discriminant is a fat pointer
let llty_str_slice = type_of::type_of(cx.ccx(), ty_str_slice).ptr_to();
lhs_str = PointerCast(cx, lhs, llty_str_slice);
let lhs_str = PointerCast(cx, lhs, llty_str_slice);
lhs_data = Load(cx, expr::get_dataptr(cx, lhs_str));
lhs_len = Load(cx, expr::get_meta(cx, lhs_str));
}
compare_str(cx, lhs_str, rhs_str, rhs_t, debug_loc)
compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc)
},
_ => cx.sess().bug("only byte strings supported in compare_values"),
},
@ -1192,8 +1196,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let unsized_ty = def.struct_variant().fields.last().map(|field| {
monomorphize::field_ty(bcx.tcx(), substs, field)
}).unwrap();
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
let scratch = alloca_no_lifetime(bcx, llty, "__struct_field_fat_ptr");
let scratch = alloc_ty(bcx, unsized_ty, "__struct_field_fat_ptr");
let data = adt::trans_field_ptr(bcx, &*repr, struct_val, 0, arg_count);
let len = Load(bcx, expr::get_meta(bcx, val.val));
Store(bcx, data, expr::get_dataptr(bcx, scratch));
@ -1520,12 +1523,8 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat,
match bm {
ast::BindByValue(_) if !moves_by_default || reassigned =>
{
llmatch = alloca_no_lifetime(bcx,
llvariable_ty.ptr_to(),
"__llmatch");
let llcopy = alloca_no_lifetime(bcx,
llvariable_ty,
&bcx.name(name));
llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch");
let llcopy = alloca(bcx, llvariable_ty, &bcx.name(name));
trmode = if moves_by_default {
TrByMoveIntoCopy(llcopy)
} else {
@ -1536,15 +1535,11 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat,
// in this case, the final type of the variable will be T,
// but during matching we need to store a *T as explained
// above
llmatch = alloca_no_lifetime(bcx,
llvariable_ty.ptr_to(),
&bcx.name(name));
llmatch = alloca(bcx, llvariable_ty.ptr_to(), &bcx.name(name));
trmode = TrByMoveRef;
}
ast::BindByRef(_) => {
llmatch = alloca_no_lifetime(bcx,
llvariable_ty,
&bcx.name(name));
llmatch = alloca(bcx, llvariable_ty, &bcx.name(name));
trmode = TrByRef;
}
};
@ -1745,6 +1740,7 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
// Subtle: be sure that we *populate* the memory *before*
// we schedule the cleanup.
call_lifetime_start(bcx, llval);
let bcx = populate(arg, bcx, datum);
bcx.fcx.schedule_lifetime_end(cleanup_scope, llval);
bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty, lvalue.dropflag_hint(bcx));

View file

@ -1020,17 +1020,10 @@ pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, name: &str) ->
let ccx = bcx.ccx();
let ty = type_of::type_of(ccx, t);
assert!(!t.has_param_types());
let val = alloca(bcx, ty, name);
return val;
alloca(bcx, ty, name)
}
pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
let p = alloca_no_lifetime(cx, ty, name);
call_lifetime_start(cx, p);
p
}
pub fn alloca_no_lifetime(cx: Block, ty: Type, name: &str) -> ValueRef {
let _icx = push_ctxt("alloca");
if cx.unreachable.get() {
unsafe {
@ -1742,7 +1735,9 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
expr::SaveIn(d) => d,
expr::Ignore => {
if !type_is_zero_size(ccx, result_ty) {
alloc_ty(bcx, result_ty, "constructor_result")
let llresult = alloc_ty(bcx, result_ty, "constructor_result");
call_lifetime_start(bcx, llresult);
llresult
} else {
C_undef(type_of::type_of(ccx, result_ty).ptr_to())
}

View file

@ -725,7 +725,9 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
let llty = type_of::type_of(ccx, ret_ty);
Some(common::C_undef(llty.ptr_to()))
} else {
Some(alloc_ty(bcx, ret_ty, "__llret"))
let llresult = alloc_ty(bcx, ret_ty, "__llret");
call_lifetime_start(bcx, llresult);
Some(llresult)
}
} else {
None

View file

@ -730,8 +730,9 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
let prev_bcx = self.new_block(true, "resume", None);
let personality = self.personality.get().expect(
"create_landing_pad() should have set this");
build::Resume(prev_bcx,
build::Load(prev_bcx, personality));
let lp = build::Load(prev_bcx, personality);
base::call_lifetime_end(prev_bcx, personality);
build::Resume(prev_bcx, lp);
prev_llbb = prev_bcx.llbb;
break;
}
@ -883,6 +884,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
}
None => {
let addr = base::alloca(pad_bcx, common::val_ty(llretval), "");
base::call_lifetime_start(pad_bcx, addr);
self.personality.set(Some(addr));
build::Store(pad_bcx, llretval, addr);
}

View file

@ -504,7 +504,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
output: ty::FnOutput<'tcx>,
name: &str) -> ValueRef {
if self.needs_ret_allocas {
base::alloca_no_lifetime(bcx, match output {
base::alloca(bcx, match output {
ty::FnConverging(output_type) => type_of::type_of(bcx.ccx(), output_type),
ty::FnDiverging => Type::void(bcx.ccx())
}, name)

View file

@ -101,7 +101,6 @@ use trans::cleanup;
use trans::cleanup::{CleanupMethods, DropHintDatum, DropHintMethods};
use trans::expr;
use trans::tvec;
use trans::type_of;
use middle::ty::Ty;
use std::fmt;
@ -302,12 +301,10 @@ pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
-> DatumBlock<'blk, 'tcx, Lvalue> where
F: FnOnce(A, Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
{
let llty = type_of::type_of(bcx.ccx(), ty);
let scratch = alloca(bcx, llty, name);
let scratch = alloc_ty(bcx, ty, name);
// Subtle. Populate the scratch memory *before* scheduling cleanup.
let bcx = populate(arg, bcx, scratch);
bcx.fcx.schedule_lifetime_end(scope, scratch);
bcx.fcx.schedule_drop_mem(scope, scratch, ty, None);
DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue::new("datum::lvalue_scratch_datum")))
@ -322,8 +319,8 @@ pub fn rvalue_scratch_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ty: Ty<'tcx>,
name: &str)
-> Datum<'tcx, Rvalue> {
let llty = type_of::type_of(bcx.ccx(), ty);
let scratch = alloca(bcx, llty, name);
let scratch = alloc_ty(bcx, ty, name);
call_lifetime_start(bcx, scratch);
Datum::new(scratch, ty, Rvalue::new(ByRef))
}
@ -500,7 +497,12 @@ impl<'tcx> Datum<'tcx, Rvalue> {
ByValue => {
lvalue_scratch_datum(
bcx, self.ty, name, scope, self,
|this, bcx, llval| this.store_to(bcx, llval))
|this, bcx, llval| {
call_lifetime_start(bcx, llval);
let bcx = this.store_to(bcx, llval);
bcx.fcx.schedule_lifetime_end(scope, llval);
bcx
})
}
}
}

View file

@ -246,9 +246,8 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Maybe just get the value directly, instead of loading it?
immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
} else {
let llty = type_of::type_of(bcx.ccx(), const_ty);
// HACK(eddyb) get around issues with lifetime intrinsics.
let scratch = alloca_no_lifetime(bcx, llty, "const");
let scratch = alloc_ty(bcx, const_ty, "const");
call_lifetime_start(bcx, scratch);
let lldest = if !const_ty.is_structural() {
// Cast pointer to slot, because constants have different types.
PointerCast(bcx, scratch, val_ty(global))
@ -403,10 +402,9 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
datum.to_rvalue_datum(bcx, "__coerce_source"));
let target = bcx.monomorphize(&target);
let llty = type_of::type_of(bcx.ccx(), target);
// HACK(eddyb) get around issues with lifetime intrinsics.
let scratch = alloca_no_lifetime(bcx, llty, "__coerce_target");
let scratch = alloc_ty(bcx, target, "__coerce_target");
call_lifetime_start(bcx, scratch);
let target_datum = Datum::new(scratch, target,
Rvalue::new(ByRef));
bcx = coerce_unsized(bcx, expr.span, source_datum, target_datum);
@ -1440,7 +1438,11 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
// temporary stack slot
let addr = match dest {
SaveIn(pos) => pos,
Ignore => alloc_ty(bcx, ty, "temp"),
Ignore => {
let llresult = alloc_ty(bcx, ty, "temp");
call_lifetime_start(bcx, llresult);
llresult
}
};
// This scope holds intermediates that must be cleaned should

View file

@ -296,10 +296,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Ensure that we always have the Rust value indirectly,
// because it makes bitcasting easier.
if !rust_indirect {
let scratch =
base::alloca(bcx,
type_of::type_of(ccx, passed_arg_tys[i]),
"__arg");
let scratch = base::alloc_ty(bcx, passed_arg_tys[i], "__arg");
if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) {
Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch));
Store(bcx, llargs_rust[i + offset + 1], expr::get_meta(bcx, scratch));
@ -432,6 +429,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// - Truncating foreign type to correct integral type and then
// bitcasting to the struct type yields invalid cast errors.
let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
base::call_lifetime_start(bcx, llscratch);
Store(bcx, llforeign_retval, llscratch);
let llscratch_i8 = BitCast(bcx, llscratch, Type::i8(ccx).ptr_to());
let llretptr_i8 = BitCast(bcx, llretptr, Type::i8(ccx).ptr_to());
@ -442,6 +440,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug!("llrust_size={}", llrust_size);
base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
C_uint(ccx, llrust_size), llalign as u32);
base::call_lifetime_end(bcx, llscratch);
}
}

View file

@ -184,9 +184,12 @@ pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
skip_dtor: bool)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("drop_ty_immediate");
let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
let vp = alloc_ty(bcx, t, "");
call_lifetime_start(bcx, vp);
store_ty(bcx, v, vp, t);
drop_ty_core(bcx, vp, t, debug_loc, skip_dtor, None)
let bcx = drop_ty_core(bcx, vp, t, debug_loc, skip_dtor, None);
call_lifetime_end(bcx, vp);
bcx
}
pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ValueRef {

View file

@ -393,7 +393,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
expr::SaveIn(d) => d,
expr::Ignore => {
if !type_is_zero_size(ccx, ret_ty) {
alloc_ty(bcx, ret_ty, "intrinsic_result")
let llresult = alloc_ty(bcx, ret_ty, "intrinsic_result");
call_lifetime_start(bcx, llresult);
llresult
} else {
C_undef(llret_ty.ptr_to())
}
@ -964,6 +966,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
match dest {
expr::Ignore => {
bcx = glue::drop_ty(bcx, llresult, ret_ty, call_debug_location);
call_lifetime_end(bcx, llresult);
}
expr::SaveIn(_) => {}
}

View file

@ -106,11 +106,11 @@ pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug!(" vt={}, count={}", vt.to_string(ccx), count);
let fixed_ty = bcx.tcx().mk_array(vt.unit_ty, count);
let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty);
// Always create an alloca even if zero-sized, to preserve
// the non-null invariant of the inner slice ptr
let llfixed = base::alloca(bcx, llfixed_ty, "");
let llfixed = base::alloc_ty(bcx, fixed_ty, "");
call_lifetime_start(bcx, llfixed);
if count > 0 {
// Arrange for the backing array to be cleaned up.