Skip to content
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

Emit LLVM lifetime intrinsics to improve stack usage and codegen in general #15863

Merged
merged 1 commit into from
Jul 22, 2014
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
1 change: 1 addition & 0 deletions src/librustc/middle/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1603,6 +1603,7 @@ fn mk_binding_alloca<'a,A>(bcx: &'a Block<'a>,
// Subtle: be sure that we *populate* the memory *before*
// we schedule the cleanup.
let bcx = populate(arg, bcx, llval, var_ty);
bcx.fcx.schedule_lifetime_end(cleanup_scope, llval);
bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty);

// Now that memory is initialized and has cleanup scheduled,
Expand Down
34 changes: 33 additions & 1 deletion src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,34 @@ pub fn with_cond<'a>(
next_cx
}

pub fn call_lifetime_start(cx: &Block, ptr: ValueRef) {
if cx.sess().opts.optimize == config::No {
return;
}

let _icx = push_ctxt("lifetime_start");
let ccx = cx.ccx();

let llsize = C_u64(ccx, machine::llsize_of_alloc(ccx, val_ty(ptr).element_type()));
let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
let lifetime_start = ccx.get_intrinsic(&"llvm.lifetime.start");
Call(cx, lifetime_start, [llsize, ptr], []);
}

pub fn call_lifetime_end(cx: &Block, ptr: ValueRef) {
if cx.sess().opts.optimize == config::No {
return;
}

let _icx = push_ctxt("lifetime_end");
let ccx = cx.ccx();

let llsize = C_u64(ccx, machine::llsize_of_alloc(ccx, val_ty(ptr).element_type()));
let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
let lifetime_end = ccx.get_intrinsic(&"llvm.lifetime.end");
Call(cx, lifetime_end, [llsize, ptr], []);
}

pub fn call_memcpy(cx: &Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
let _icx = push_ctxt("call_memcpy");
let ccx = cx.ccx();
Expand Down Expand Up @@ -1157,6 +1185,8 @@ pub fn alloca_maybe_zeroed(cx: &Block, ty: Type, name: &str, zero: bool) -> Valu
let b = cx.fcx.ccx.builder();
b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
memzero(&b, p, ty);
} else {
call_lifetime_start(cx, p);
}
p
}
Expand All @@ -1169,7 +1199,9 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
}
}
debuginfo::clear_source_location(cx.fcx);
return ArrayAlloca(cx, ty, v);
let p = ArrayAlloca(cx, ty, v);
call_lifetime_start(cx, p);
p
}

// Creates and returns space for, or returns the argument representing, the
Expand Down
32 changes: 32 additions & 0 deletions src/librustc/middle/trans/cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,20 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
self.trans_cleanups_to_exit_scope(ReturnExit)
}

fn schedule_lifetime_end(&self,
cleanup_scope: ScopeId,
val: ValueRef) {
let drop = box LifetimeEnd {
ptr: val,
};

debug!("schedule_lifetime_end({:?}, val={})",
cleanup_scope,
self.ccx.tn.val_to_string(val));

self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
}

fn schedule_drop_mem(&self,
cleanup_scope: ScopeId,
val: ValueRef,
Expand Down Expand Up @@ -902,6 +916,21 @@ impl Cleanup for FreeValue {
}
}

pub struct LifetimeEnd {
ptr: ValueRef,
}

impl Cleanup for LifetimeEnd {
fn clean_on_unwind(&self) -> bool {
false
}

fn trans<'a>(&self, bcx: &'a Block<'a>) -> &'a Block<'a> {
base::call_lifetime_end(bcx, self.ptr);
bcx
}
}

pub fn temporary_scope(tcx: &ty::ctxt,
id: ast::NodeId)
-> ScopeId {
Expand Down Expand Up @@ -957,6 +986,9 @@ pub trait CleanupMethods<'a> {
cleanup_scope: ast::NodeId,
exit: uint) -> BasicBlockRef;
fn return_exit_block(&'a self) -> BasicBlockRef;
fn schedule_lifetime_end(&self,
cleanup_scope: ScopeId,
val: ValueRef);
fn schedule_drop_mem(&self,
cleanup_scope: ScopeId,
val: ValueRef,
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/trans/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,9 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
ifn!("llvm.umul.with.overflow.i32" fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
ifn!("llvm.umul.with.overflow.i64" fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});

ifn!("llvm.lifetime.start" fn(t_i64,i8p) -> void);
ifn!("llvm.lifetime.end" fn(t_i64, i8p) -> void);

ifn!("llvm.expect.i1" fn(i1, i1) -> i1);

// Some intrinsics were introduced in later versions of LLVM, but they have
Expand Down
6 changes: 5 additions & 1 deletion src/librustc/middle/trans/datum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub fn lvalue_scratch_datum<'a, A>(bcx: &'a Block<'a>,

// 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);

DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue))
Expand Down Expand Up @@ -169,7 +170,10 @@ fn add_rvalue_clean(mode: RvalueMode,
ty: ty::t) {
match mode {
ByValue => { fcx.schedule_drop_immediate(scope, val, ty); }
ByRef => { fcx.schedule_drop_mem(scope, val, ty); }
ByRef => {
fcx.schedule_lifetime_end(scope, val);
fcx.schedule_drop_mem(scope, val, ty);
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1145,8 +1145,9 @@ pub fn trans_adt<'a>(bcx: &'a Block<'a>,
let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
let e_ty = expr_ty_adjusted(bcx, &**e);
bcx = trans_into(bcx, &**e, SaveIn(dest));
fcx.schedule_drop_mem(cleanup::CustomScope(custom_cleanup_scope),
dest, e_ty);
let scope = cleanup::CustomScope(custom_cleanup_scope);
fcx.schedule_lifetime_end(scope, dest);
fcx.schedule_drop_mem(scope, dest, e_ty);
}

for base in optbase.iter() {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/trans/tvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ pub fn trans_slice_vstore<'a>(
let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to();
let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty);
let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
fcx.schedule_lifetime_end(cleanup_scope, llfixed_casted);
fcx.schedule_drop_mem(cleanup_scope, llfixed_casted, fixed_ty);

// Generate the content into the backing array.
Expand Down Expand Up @@ -364,10 +365,9 @@ pub fn write_content<'a>(
i, bcx.val_to_string(lleltptr));
bcx = expr::trans_into(bcx, &**element,
SaveIn(lleltptr));
fcx.schedule_drop_mem(
cleanup::CustomScope(temp_scope),
lleltptr,
vt.unit_ty);
let scope = cleanup::CustomScope(temp_scope);
fcx.schedule_lifetime_end(scope, lleltptr);
fcx.schedule_drop_mem(scope, lleltptr, vt.unit_ty);
}
fcx.pop_custom_cleanup_scope(temp_scope);
}
Expand Down