diff options
| -rw-r--r-- | src/comp/middle/trans.rs | 197 | ||||
| -rw-r--r-- | src/comp/rustc.rc | 2 | ||||
| -rw-r--r-- | src/test/bench/shootout/nbody.rs | 13 |
3 files changed, 151 insertions, 61 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 2d7c5559..28f79dbb 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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); } diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index f331eba0..174fdcfa 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -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; diff --git a/src/test/bench/shootout/nbody.rs b/src/test/bench/shootout/nbody.rs index 39c01ee7..f6f14f97 100644 --- a/src/test/bench/shootout/nbody.rs +++ b/src/test/bench/shootout/nbody.rs @@ -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(); |