Move all allocas to dedicated basic block at top of function, to keep frames finite. Un-comment next size in nbody.rs.

This commit is contained in:
Graydon Hoare 2011-03-28 18:04:52 -07:00
parent 2809e30d1d
commit 540d29f641
3 changed files with 151 additions and 61 deletions

View File

@ -114,6 +114,7 @@ state type fn_ctxt = rec(ValueRef llfn,
ValueRef lltaskptr,
ValueRef llenv,
ValueRef llretptr,
mutable BasicBlockRef llallocas,
mutable option.t[ValueRef] llself,
mutable option.t[ValueRef] lliterbody,
hashmap[ast.def_id, ValueRef] llargs,
@ -1047,6 +1048,15 @@ fn align_of(@block_ctxt cx, @ty.t t) -> result {
ret dynamic_align_of(cx, t);
}
fn alloca(@block_ctxt cx, TypeRef t) -> ValueRef {
ret new_builder(cx.fcx.llallocas).Alloca(t);
}
fn array_alloca(@block_ctxt cx, TypeRef t, ValueRef n) -> ValueRef {
ret new_builder(cx.fcx.llallocas).ArrayAlloca(t, n);
}
// Computes the size of the data part of a non-dynamically-sized tag.
fn static_size_of_tag(@crate_ctxt cx, @ty.t t) -> uint {
if (ty.type_has_dynamic_size(t)) {
@ -1144,7 +1154,7 @@ fn dynamic_size_of(@block_ctxt cx, @ty.t t) -> result {
auto bcx = cx;
// Compute max(variant sizes).
let ValueRef max_size = bcx.build.Alloca(T_int());
let ValueRef max_size = alloca(bcx, T_int());
bcx.build.Store(C_int(0), max_size);
auto ty_params = tag_ty_params(bcx.fcx.ccx, tid);
@ -1466,8 +1476,8 @@ fn get_tydesc(&@block_ctxt cx, @ty.t t) -> result {
auto root = cx.fcx.ccx.tydescs.get(t).tydesc;
auto tydescs = cx.build.Alloca(T_array(T_ptr(T_tydesc(cx.fcx.ccx.tn)),
1u /* for root*/ + n_params));
auto tydescs = alloca(cx, T_array(T_ptr(T_tydesc(cx.fcx.ccx.tn)),
1u /* for root*/ + n_params));
auto i = 0;
auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
@ -1593,6 +1603,7 @@ fn make_generic_glue(@crate_ctxt cx, @ty.t t, ValueRef llfn,
vec[ast.def_id] typaram_defs) -> ValueRef {
auto fcx = new_fn_ctxt(cx, llfn);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
auto re;
if (!ty.type_is_scalar(t)) {
@ -1623,6 +1634,10 @@ fn make_generic_glue(@crate_ctxt cx, @ty.t t, ValueRef llfn,
}
re.bcx.build.RetVoid();
// Tie up the llallocas -> lltop edge.
new_builder(fcx.llallocas).Br(lltop);
ret llfn;
}
@ -2597,7 +2612,7 @@ fn trans_compare(@block_ctxt cx0, ast.binop op, @ty.t t0,
* optimize combinations like that, at this level.
*/
auto flag = scx.build.Alloca(T_i1());
auto flag = alloca(scx, T_i1());
if (ty.type_is_sequence(t)) {
@ -3204,7 +3219,7 @@ fn trans_for_each(@block_ctxt cx,
}
// Create an array of bindings and copy in aliases to the upvars.
llbindingsptr = cx.build.Alloca(T_struct(llbindingtys));
llbindingsptr = alloca(cx, T_struct(llbindingtys));
auto i = 0u;
while (i < upvar_count) {
auto llbindingptr = cx.build.GEP(llbindingsptr,
@ -3220,7 +3235,7 @@ fn trans_for_each(@block_ctxt cx,
// Create an environment and populate it with the bindings.
auto llenvptrty = T_closure_ptr(cx.fcx.ccx.tn, T_ptr(T_nil()),
val_ty(llbindingsptr), 0u);
auto llenvptr = cx.build.Alloca(llvm.LLVMGetElementType(llenvptrty));
auto llenvptr = alloca(cx, llvm.LLVMGetElementType(llenvptrty));
auto llbindingsptrptr = cx.build.GEP(llenvptr,
vec(C_int(0),
@ -3251,6 +3266,7 @@ fn trans_for_each(@block_ctxt cx,
auto fcx = new_fn_ctxt(cx.fcx.ccx, lliterbody);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
// Populate the upvars from the environment.
auto llremoteenvptr = bcx.build.PointerCast(fcx.llenv, llenvptrty);
@ -3272,11 +3288,15 @@ fn trans_for_each(@block_ctxt cx,
// Treat the loop variable as an upvar as well. We copy it to an alloca
// as usual.
auto lllvar = llvm.LLVMGetParam(fcx.llfn, 3u);
auto lllvarptr = bcx.build.Alloca(val_ty(lllvar));
auto lllvarptr = alloca(bcx, val_ty(lllvar));
bcx.build.Store(lllvar, lllvarptr);
fcx.llupvars.insert(decl_id, lllvarptr);
auto res = trans_block(bcx, body);
// Tie up the llallocas -> lltop edge.
new_builder(fcx.llallocas).Br(lltop);
res.bcx.build.RetVoid();
@ -3286,8 +3306,8 @@ fn trans_for_each(@block_ctxt cx,
case (ast.expr_call(?f, ?args, ?ann)) {
auto pair = cx.build.Alloca(T_fn_pair(cx.fcx.ccx.tn,
iter_body_llty));
auto pair = alloca(cx, T_fn_pair(cx.fcx.ccx.tn,
iter_body_llty));
auto code_cell = cx.build.GEP(pair,
vec(C_int(0),
C_int(abi.fn_field_code)));
@ -3831,6 +3851,7 @@ fn trans_bind_thunk(@crate_ctxt cx,
auto fcx = new_fn_ctxt(cx, llthunk);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
auto llclosure_ptr_ty = type_of(cx, ty.plain_box_ty(closure_ty));
auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
@ -3944,6 +3965,9 @@ fn trans_bind_thunk(@crate_ctxt cx,
auto r = bcx.build.FastCall(lltargetfn, llargs);
bcx.build.RetVoid();
// Tie up the llallocas -> lltop edge.
new_builder(fcx.llallocas).Br(lltop);
ret llthunk;
}
@ -3987,7 +4011,7 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
} else {
auto bcx = f_res.res.bcx;
auto pair_t = node_type(cx.fcx.ccx, ann);
auto pair_v = bcx.build.Alloca(pair_t);
auto pair_v = alloca(bcx, pair_t);
// Translate the bound expressions.
let vec[@ty.t] bound_tys = vec();
@ -4245,7 +4269,7 @@ fn trans_args(@block_ctxt cx,
// Non-mem but we're trying to alias; synthesize an
// alloca, spill to it and pass its address.
auto llty = val_ty(lv.res.val);
auto llptr = lv.res.bcx.build.Alloca(llty);
auto llptr = alloca(lv.res.bcx, llty);
lv.res.bcx.build.Store(lv.res.val, llptr);
val = llptr;
}
@ -4695,7 +4719,7 @@ fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
"upcall_log_float",
vec(sub.val));
} else {
auto tmp = sub.bcx.build.Alloca(tr);
auto tmp = alloca(sub.bcx, tr);
sub.bcx.build.Store(sub.val, tmp);
auto v = vp2i(sub.bcx, tmp);
ret trans_upcall(sub.bcx,
@ -4751,7 +4775,7 @@ fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
alt (cx.fcx.lliterbody) {
case (some[ValueRef](?lli)) {
auto slot = cx.build.Alloca(val_ty(lli));
auto slot = alloca(cx, val_ty(lli));
cx.build.Store(lli, slot);
llcallee = cx.build.GEP(slot, vec(C_int(0),
@ -4764,7 +4788,7 @@ fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
}
}
auto bcx = cx;
auto dummy_retslot = bcx.build.Alloca(T_nil());
auto dummy_retslot = alloca(bcx, T_nil());
let vec[ValueRef] llargs = vec(dummy_retslot, cx.fcx.lltaskptr, llenv);
alt (e) {
case (none[@ast.expr]) { }
@ -5136,17 +5160,38 @@ iter block_locals(&ast.block b) -> @ast.local {
}
}
fn llallocas_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
let vec[cleanup] cleanups = vec();
ret @rec(llbb=fcx.llallocas,
build=new_builder(fcx.llallocas),
parent=parent_none,
kind=SCOPE_BLOCK,
mutable cleanups=cleanups,
fcx=fcx);
}
fn alloc_ty(@block_ctxt cx, @ty.t t) -> result {
auto val = C_int(0);
auto bcx = cx;
if (ty.type_has_dynamic_size(t)) {
auto n = size_of(bcx, t);
bcx = n.bcx;
val = bcx.build.ArrayAlloca(T_i8(), n.val);
// NB: we have to run this particular 'size_of' in a
// block_ctxt built on the llallocas block for the fn,
// so that the size dominates the array_alloca that
// comes next.
auto n = size_of(llallocas_block_ctxt(cx.fcx), t);
cx.fcx.llallocas = n.bcx.llbb;
val = array_alloca(cx, T_i8(), n.val);
} else {
val = bcx.build.Alloca(type_of(cx.fcx.ccx, t));
val = alloca(cx, type_of(cx.fcx.ccx, t));
}
ret res(bcx, val);
// NB: since we've pushed all size calculations in this
// function up to the alloca block, we actually return the
// block passed into us unmodified; it doesn't really
// have to be passed-and-returned here, but it fits
// past caller conventions and may well make sense again,
// so we leave it as-is.
ret res(cx, val);
}
fn alloc_local(@block_ctxt cx, @ast.local local) -> result {
@ -5211,10 +5256,14 @@ fn new_fn_ctxt(@crate_ctxt cx,
let hashmap[ast.def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
let hashmap[ast.def_id, ValueRef] lltydescs = new_def_hash[ValueRef]();
let BasicBlockRef llallocas =
llvm.LLVMAppendBasicBlock(llfndecl, _str.buf("allocas"));
ret @rec(llfn=llfndecl,
lltaskptr=lltaskptr,
llenv=llenv,
llretptr=llretptr,
mutable llallocas = llallocas,
mutable llself=none[ValueRef],
mutable lliterbody=none[ValueRef],
llargs=llargs,
@ -5277,39 +5326,49 @@ fn create_llargs_for_fn_args(&@fn_ctxt cx,
// allocas immediately upon entry; this permits us to GEP into structures we
// were passed and whatnot. Apparently mem2reg will mop up.
fn copy_args_to_allocas(@block_ctxt cx,
option.t[TypeRef] ty_self,
vec[ast.arg] args,
vec[ty.arg] arg_tys) {
fn copy_any_self_to_alloca(@fn_ctxt fcx,
option.t[TypeRef] ty_self) {
let uint arg_n = 0u;
auto bcx = llallocas_block_ctxt(fcx);
alt (cx.fcx.llself) {
alt (fcx.llself) {
case (some[ValueRef](?self_v)) {
alt (ty_self) {
case (some[TypeRef](?self_t)) {
auto alloca = cx.build.Alloca(self_t);
cx.build.Store(self_v, alloca);
cx.fcx.llself = some[ValueRef](alloca);
auto a = alloca(bcx, self_t);
bcx.build.Store(self_v, a);
fcx.llself = some[ValueRef](a);
}
}
}
case (_) {
}
}
}
fn copy_args_to_allocas(@fn_ctxt fcx,
vec[ast.arg] args,
vec[ty.arg] arg_tys) {
auto bcx = llallocas_block_ctxt(fcx);
let uint arg_n = 0u;
for (ast.arg aarg in args) {
if (aarg.mode != ast.alias) {
auto arg_t = type_of_arg(cx.fcx.ccx, arg_tys.(arg_n));
auto alloca = cx.build.Alloca(arg_t);
auto argval = cx.fcx.llargs.get(aarg.id);
cx.build.Store(argval, alloca);
auto arg_t = type_of_arg(fcx.ccx, arg_tys.(arg_n));
auto a = alloca(bcx, arg_t);
auto argval = fcx.llargs.get(aarg.id);
bcx.build.Store(argval, a);
// Overwrite the llargs entry for this arg with its alloca.
cx.fcx.llargs.insert(aarg.id, alloca);
fcx.llargs.insert(aarg.id, a);
}
arg_n += 1u;
}
fcx.llallocas = bcx.llbb;
}
fn is_terminated(@block_ctxt cx) -> bool {
@ -5340,8 +5399,8 @@ fn ret_ty_of_fn(ast.ann ann) -> @ty.t {
ret ret_ty_of_fn_ty(ty.ann_to_type(ann));
}
fn populate_fn_ctxt_from_llself(@block_ctxt cx, ValueRef llself) -> result {
auto bcx = cx;
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, ValueRef llself) {
auto bcx = llallocas_block_ctxt(fcx);
let vec[@ty.t] field_tys = vec();
@ -5379,7 +5438,7 @@ fn populate_fn_ctxt_from_llself(@block_ctxt cx, ValueRef llself) -> result {
// fields pointer to the appropriate LLVM type. If not, just leave it as
// i8 *.
if (!ty.type_has_dynamic_size(fields_tup_ty)) {
auto llfields_ty = type_of(bcx.fcx.ccx, fields_tup_ty);
auto llfields_ty = type_of(fcx.ccx, fields_tup_ty);
obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
} else {
obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8()));
@ -5388,25 +5447,25 @@ fn populate_fn_ctxt_from_llself(@block_ctxt cx, ValueRef llself) -> result {
let int i = 0;
for (ast.ty_param p in bcx.fcx.ccx.obj_typarams) {
for (ast.ty_param p in fcx.ccx.obj_typarams) {
let ValueRef lltyparam = bcx.build.GEP(obj_typarams,
vec(C_int(0),
C_int(i)));
lltyparam = bcx.build.Load(lltyparam);
bcx.fcx.lltydescs.insert(p.id, lltyparam);
fcx.lltydescs.insert(p.id, lltyparam);
i += 1;
}
i = 0;
for (ast.obj_field f in bcx.fcx.ccx.obj_fields) {
for (ast.obj_field f in fcx.ccx.obj_fields) {
auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, vec(0, i));
bcx = rslt.bcx;
bcx = llallocas_block_ctxt(fcx);
auto llfield = rslt.val;
cx.fcx.llobjfields.insert(f.id, llfield);
fcx.llobjfields.insert(f.id, llfield);
i += 1;
}
ret res(bcx, C_nil());
fcx.llallocas = bcx.llbb;
}
fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
@ -5419,25 +5478,31 @@ fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
create_llargs_for_fn_args(fcx, f.proto,
ty_self, ret_ty_of_fn(ann),
f.decl.inputs, ty_params);
auto bcx = new_top_block_ctxt(fcx);
copy_args_to_allocas(bcx, ty_self, f.decl.inputs,
arg_tys_of_fn(ann));
copy_any_self_to_alloca(fcx, ty_self);
alt (fcx.llself) {
case (some[ValueRef](?llself)) {
bcx = populate_fn_ctxt_from_llself(bcx, llself).bcx;
populate_fn_ctxt_from_llself(fcx, llself);
}
case (_) {
}
}
copy_args_to_allocas(fcx, f.decl.inputs, arg_tys_of_fn(ann));
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
auto res = trans_block(bcx, f.body);
if (!is_terminated(res.bcx)) {
// FIXME: until LLVM has a unit type, we are moving around
// C_nil values rather than their void type.
res.bcx.build.RetVoid();
}
// Tie up the llallocas -> lltop edge.
new_builder(fcx.llallocas).Br(lltop);
}
fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
@ -5504,10 +5569,11 @@ fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
none[TypeRef], ret_ty_of_fn(ann),
fn_args, ty_params);
auto bcx = new_top_block_ctxt(fcx);
let vec[ty.arg] arg_tys = arg_tys_of_fn(ann);
copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
copy_args_to_allocas(fcx, fn_args, arg_tys);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
auto llself_ty = type_of(cx, ret_ty_of_fn(ann));
auto pair = bcx.fcx.llretptr;
@ -5604,6 +5670,9 @@ fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
bcx.build.Store(p, pair_box);
}
bcx.build.RetVoid();
// Tie up the llallocas -> lltop edge.
new_builder(fcx.llallocas).Br(lltop);
}
fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
@ -5627,6 +5696,7 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
let ValueRef llfndecl = cx.item_ids.get(variant.id);
auto fcx = new_fn_ctxt(cx, llfndecl);
create_llargs_for_fn_args(fcx, ast.proto_fn,
none[TypeRef], ret_ty_of_fn(variant.ann),
fn_args, ty_params);
@ -5636,10 +5706,11 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
ty_param_substs += vec(plain_ty(ty.ty_param(tp.id)));
}
auto bcx = new_top_block_ctxt(fcx);
auto arg_tys = arg_tys_of_fn(variant.ann);
copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
copy_args_to_allocas(fcx, fn_args, arg_tys);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
// Cast the tag to a type we can GEP into.
auto lltagptr = bcx.build.PointerCast(fcx.llretptr,
@ -5682,6 +5753,9 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
bcx.build.RetVoid();
// Tie up the llallocas -> lltop edge.
new_builder(fcx.llallocas).Br(lltop);
}
// FIXME: this should do some structural hash-consing to avoid
@ -5851,6 +5925,7 @@ fn decl_native_fn_and_pair(@crate_ctxt cx,
// Build the wrapper.
auto fcx = new_fn_ctxt(cx, wrapper_fn);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
// Declare the function itself.
auto item = cx.native_items.get(id);
@ -5919,6 +5994,9 @@ fn decl_native_fn_and_pair(@crate_ctxt cx,
bcx.build.Store(r, rptr);
bcx.build.RetVoid();
// Tie up the llallocas -> lltop edge.
new_builder(fcx.llallocas).Br(lltop);
}
fn collect_native_item(&@crate_ctxt cx, @ast.native_item i) -> @crate_ctxt {
@ -6471,10 +6549,14 @@ fn trans_vec_append_glue(@crate_ctxt cx) {
let ValueRef llsrc_vec = llvm.LLVMGetParam(llfn, 4u);
let ValueRef llskipnull = llvm.LLVMGetParam(llfn, 5u);
let BasicBlockRef llallocas =
llvm.LLVMAppendBasicBlock(llfn, _str.buf("allocas"));
auto fcx = @rec(llfn=llfn,
lltaskptr=lltaskptr,
llenv=C_null(T_ptr(T_nil())),
llretptr=C_null(T_ptr(T_nil())),
mutable llallocas = llallocas,
mutable llself=none[ValueRef],
mutable lliterbody=none[ValueRef],
llargs=new_def_hash[ValueRef](),
@ -6485,13 +6567,14 @@ fn trans_vec_append_glue(@crate_ctxt cx) {
ccx=cx);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
auto lldst_vec = bcx.build.Load(lldst_vec_ptr);
// First the dst vec needs to grow to accommodate the src vec.
// To do this we have to figure out how many bytes to add.
auto llcopy_dst_ptr = bcx.build.Alloca(T_int());
auto llcopy_dst_ptr = alloca(bcx, T_int());
auto llnew_vec_res =
trans_upcall(bcx, "upcall_vec_grow",
vec(vp2i(bcx, lldst_vec),
@ -6508,7 +6591,7 @@ fn trans_vec_append_glue(@crate_ctxt cx) {
auto copy_dst_cx = new_sub_block_ctxt(bcx, "copy new <- dst");
auto copy_src_cx = new_sub_block_ctxt(bcx, "copy new <- src");
auto pp0 = bcx.build.Alloca(T_ptr(T_i8()));
auto pp0 = alloca(bcx, T_ptr(T_i8()));
bcx.build.Store(vec_p0(bcx, llnew_vec), pp0);
bcx.build.CondBr(bcx.build.TruncOrBitCast
@ -6576,6 +6659,9 @@ fn trans_vec_append_glue(@crate_ctxt cx) {
// Write new_vec back through the alias we were given.
copy_src_cx.build.Store(llnew_vec, lldst_vec_ptr);
copy_src_cx.build.RetVoid();
// Tie up the llallocas -> lltop edge.
new_builder(fcx.llallocas).Br(lltop);
}
@ -6640,7 +6726,6 @@ fn make_common_glue(str output) {
trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn, llmod);
check_module(llmod);
llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
llvm.LLVMDisposeModule(llmod);
}

View File

@ -48,8 +48,10 @@ auth front.creader.get_type = impure;
auth front.creader.impure_no_op = impure;
auth middle.metadata = unsafe;
auth middle.trans = unsafe;
auth middle.trans.copy_any_self_to_alloca = impure;
auth middle.trans.copy_args_to_allocas = impure;
auth middle.trans.trans_block = impure;
auth middle.trans.alloc_ty = impure;
auth lib.llvm = unsafe;
auth pretty.pprust = impure;

View File

@ -9,11 +9,14 @@ native "llvm" mod llvm {
fn main() {
let vec[int] inputs = vec(
50000
//these segfault :(
//500000,
//5000000,
//50000000
50000,
500000
//
// Leave these commented out to
// finish in a reasonable time
// during 'make check' under valgrind
// 5000000
// 50000000
);
let vec[Body.props] bodies = NBodySystem.MakeNBodySystem();