rustc: Allocate derived tydescs before dynamically sized allocas

This commit is contained in:
Patrick Walton 2011-06-18 18:43:07 -07:00
parent 877f001512
commit 4f13879218

View File

@ -191,20 +191,28 @@
// administrative activities that have to happen in only one place in
// the function, due to LLVM's quirks.
// A block for all the function's allocas, so that LLVM will coalesce
// them into a single alloca call.
mutable BasicBlockRef llallocas,
// A block for all the function's static allocas, so that LLVM will
// coalesce them into a single alloca call.
mutable BasicBlockRef llstaticallocas,
// A block containing code that copies incoming arguments to space
// already allocated by code in the llallocas block. (LLVM requires
// that arguments be copied to local allocas before allowing most any
// operation to be performed on them.)
// already allocated by code in one of the llallocas blocks. (LLVM
// requires that arguments be copied to local allocas before allowing
// most any operation to be performed on them.)
mutable BasicBlockRef llcopyargs,
// A block containing derived tydescs received from the runtime. See
// description of derived_tydescs, below.
// The first block containing derived tydescs received from the
// runtime. See description of derived_tydescs, below.
mutable BasicBlockRef llderivedtydescs_first,
// The last block of the llderivedtydescs group.
mutable BasicBlockRef llderivedtydescs,
// A block for all of the dynamically sized allocas. This must be
// after llderivedtydescs, because these sometimes depend on
// information computed from derived tydescs.
mutable BasicBlockRef lldynamicallocas,
// FIXME: Is llcopyargs actually the block containing the allocas for
// incoming function arguments? Or is it merely the block containing
// code that copies incoming args to space already alloca'd by code in
@ -1173,11 +1181,11 @@ fn align_of(&@block_ctxt cx, &ty::t t) -> result {
}
fn alloca(&@block_ctxt cx, TypeRef t) -> ValueRef {
ret new_builder(cx.fcx.llallocas).Alloca(t);
ret new_builder(cx.fcx.llstaticallocas).Alloca(t);
}
fn array_alloca(&@block_ctxt cx, TypeRef t, ValueRef n) -> ValueRef {
ret new_builder(cx.fcx.llallocas).ArrayAlloca(t, n);
ret new_builder(cx.fcx.lldynamicallocas).ArrayAlloca(t, n);
}
@ -3556,7 +3564,7 @@ fn alloc(&@block_ctxt cx, ty::t unit_ty) -> alloc_result {
auto bcx;
if (dynamic) {
bcx = llallocas_block_ctxt(cx.fcx);
bcx = llderivedtydescs_block_ctxt(cx.fcx);
} else {
bcx = cx;
}
@ -3565,26 +3573,25 @@ fn alloc(&@block_ctxt cx, ty::t unit_ty) -> alloc_result {
auto rslt = size_of(bcx, unit_ty);
bcx = rslt.bcx;
llunitsz = rslt.val;
if (dynamic) { bcx.fcx.llallocas = bcx.llbb; }
if (dynamic) { cx.fcx.llderivedtydescs = bcx.llbb; }
auto llalen = bcx.build.Mul(llunitsz,
C_uint(abi::ivec_default_length));
auto llptr;
auto llunitty = type_of_or_i8(bcx, unit_ty);
auto bcx_result;
if (dynamic) {
auto llarraysz = bcx.build.Add(llsize_of(T_opaque_ivec()),
llalen);
auto llvecptr = array_alloca(bcx, T_i8(), llarraysz);
llptr = bcx.build.PointerCast(llvecptr, T_ptr(T_opaque_ivec()));
bcx_result = cx;
llptr = bcx_result.build.PointerCast(llvecptr,
T_ptr(T_opaque_ivec()));
} else {
llptr = alloca(bcx, T_ivec(llunitty));
}
auto bcx_result;
if (dynamic) {
bcx_result = cx;
} else {
bcx_result = bcx;
}
@ -6753,10 +6760,10 @@ fn trans_block_cleanups(&@block_ctxt cx, &@block_ctxt cleanup_cx) ->
}
}
fn llallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
fn llstaticallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
let vec[cleanup] cleanups = [];
ret @rec(llbb=fcx.llallocas,
build=new_builder(fcx.llallocas),
ret @rec(llbb=fcx.llstaticallocas,
build=new_builder(fcx.llstaticallocas),
parent=parent_none,
kind=SCOPE_BLOCK,
mutable cleanups=cleanups,
@ -6764,16 +6771,40 @@ fn llallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
fcx=fcx);
}
fn llderivedtydescs_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
let vec[cleanup] cleanups = [];
ret @rec(llbb=fcx.llderivedtydescs,
build=new_builder(fcx.llderivedtydescs),
parent=parent_none,
kind=SCOPE_BLOCK,
mutable cleanups=cleanups,
sp=fcx.sp,
fcx=fcx);
}
fn lldynamicallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
let vec[cleanup] cleanups = [];
ret @rec(llbb=fcx.lldynamicallocas,
build=new_builder(fcx.lldynamicallocas),
parent=parent_none,
kind=SCOPE_BLOCK,
mutable cleanups=cleanups,
sp=fcx.sp,
fcx=fcx);
}
fn alloc_ty(&@block_ctxt cx, &ty::t t) -> result {
auto val = C_int(0);
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
// NB: we have to run this particular 'size_of' in a
// block_ctxt built on the llallocas block for the fn,
// block_ctxt built on the llderivedtydescs 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;
auto n = size_of(llderivedtydescs_block_ctxt(cx.fcx), t);
cx.fcx.llderivedtydescs = n.bcx.llbb;
val = array_alloca(cx, T_i8(), n.val);
} else { val = alloca(cx, type_of(cx.fcx.lcx.ccx, cx.sp, t)); }
// NB: since we've pushed all size calculations in this
@ -6862,13 +6893,14 @@ fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt {
}
// Creates the standard trio of basic blocks: allocas, copy-args, and derived
// tydescs.
// Creates the standard quartet of basic blocks: static allocas, copy args,
// derived tydescs, and dynamic allocas.
fn mk_standard_basic_blocks(ValueRef llfn) ->
tup(BasicBlockRef, BasicBlockRef, BasicBlockRef) {
ret tup(llvm::LLVMAppendBasicBlock(llfn, str::buf("allocas")),
tup(BasicBlockRef, BasicBlockRef, BasicBlockRef, BasicBlockRef) {
ret tup(llvm::LLVMAppendBasicBlock(llfn, str::buf("static_allocas")),
llvm::LLVMAppendBasicBlock(llfn, str::buf("copy_args")),
llvm::LLVMAppendBasicBlock(llfn, str::buf("derived_tydescs")));
llvm::LLVMAppendBasicBlock(llfn, str::buf("derived_tydescs")),
llvm::LLVMAppendBasicBlock(llfn, str::buf("dynamic_allocas")));
}
@ -6893,9 +6925,11 @@ fn new_fn_ctxt(@local_ctxt cx, &span sp, ValueRef llfndecl) -> @fn_ctxt {
lltaskptr=lltaskptr,
llenv=llenv,
llretptr=llretptr,
mutable llallocas=llbbs._0,
mutable llstaticallocas=llbbs._0,
mutable llcopyargs=llbbs._1,
mutable llderivedtydescs_first=llbbs._2,
mutable llderivedtydescs=llbbs._2,
mutable lldynamicallocas=llbbs._3,
mutable llself=none[val_self_pair],
mutable lliterbody=none[ValueRef],
llargs=llargs,
@ -6973,7 +7007,7 @@ fn create_llargs_for_fn_args(&@fn_ctxt cx, ast::proto proto,
// allocas immediately upon entry; this permits us to GEP into structures we
// were passed and whatnot. Apparently mem2reg will mop up.
fn copy_any_self_to_alloca(@fn_ctxt fcx, option::t[ty_self_pair] ty_self) {
auto bcx = llallocas_block_ctxt(fcx);
auto bcx = llstaticallocas_block_ctxt(fcx);
alt ({ fcx.llself }) {
case (some(?pair)) {
alt (ty_self) {
@ -7045,7 +7079,7 @@ fn ret_ty_of_fn(&@crate_ctxt ccx, ast::ann ann) -> ty::t {
}
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, val_self_pair llself) {
auto bcx = llallocas_block_ctxt(fcx);
auto bcx = llstaticallocas_block_ctxt(fcx);
let vec[ty::t] field_tys = [];
for (ast::obj_field f in bcx.fcx.lcx.obj_fields) {
field_tys += [node_ann_type(bcx.fcx.lcx.ccx, f.ann)];
@ -7088,20 +7122,22 @@ fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, val_self_pair llself) {
i = 0;
for (ast::obj_field f in fcx.lcx.obj_fields) {
auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, [0, i]);
bcx = llallocas_block_ctxt(fcx);
bcx = llstaticallocas_block_ctxt(fcx);
auto llfield = rslt.val;
fcx.llobjfields.insert(f.id, llfield);
i += 1;
}
fcx.llallocas = bcx.llbb;
fcx.llstaticallocas = bcx.llbb;
}
// Ties up the llallocas -> llcopyargs -> llderivedtydescs -> lltop edges.
// Ties up the llstaticallocas -> llcopyargs -> llderivedtydescs ->
// lldynamicallocas -> lltop edges.
fn finish_fn(&@fn_ctxt fcx, BasicBlockRef lltop) {
new_builder(fcx.llallocas).Br(fcx.llcopyargs);
new_builder(fcx.llcopyargs).Br(fcx.llderivedtydescs);
new_builder(fcx.llderivedtydescs).Br(lltop);
new_builder(fcx.llstaticallocas).Br(fcx.llcopyargs);
new_builder(fcx.llcopyargs).Br(fcx.llderivedtydescs_first);
new_builder(fcx.llderivedtydescs).Br(fcx.lldynamicallocas);
new_builder(fcx.lldynamicallocas).Br(lltop);
}