auto merge of #7763 : dotdash/rust/empty_blocks, r=pcwalton

These commits remove a bunch of empty or otherwise unnecessary blocks, reducing the size of the pre-optimization IR and improving its readability. `librustc.ll` created with `--passes ""` shrinks by about 120k lines which equals about 5% of the total size.
This commit is contained in:
bors 2013-07-13 11:07:31 -07:00
commit 8d0feb58e7
7 changed files with 165 additions and 100 deletions

View File

@ -1102,11 +1102,6 @@ pub fn trans_trace(bcx: block, sp_opt: Option<span>, trace_str: @str) {
Call(bcx, ccx.upcalls.trace, args);
}
pub fn build_return(bcx: block) {
let _icx = push_ctxt("build_return");
Br(bcx, bcx.fcx.llreturn);
}
pub fn ignore_lhs(_bcx: block, local: &ast::local) -> bool {
match local.node.pat.node {
ast::pat_wild => true, _ => false
@ -1364,6 +1359,42 @@ pub fn cleanup_and_leave(bcx: block,
}
}
pub fn cleanup_block(bcx: block, upto: Option<BasicBlockRef>) -> block{
let _icx = push_ctxt("cleanup_block");
let mut cur = bcx;
let mut bcx = bcx;
loop {
debug!("cleanup_block: %s", cur.to_str());
if bcx.sess().trace() {
trans_trace(
bcx, None,
(fmt!("cleanup_block(%s)", cur.to_str())).to_managed());
}
let mut cur_scope = cur.scope;
loop {
cur_scope = match cur_scope {
Some (inf) => {
bcx = trans_block_cleanups_(bcx, inf.cleanups.to_owned(), false);
inf.parent
}
None => break
}
}
match upto {
Some(bb) => { if cur.llbb == bb { break; } }
_ => ()
}
cur = match cur.parent {
Some(next) => next,
None => { assert!(upto.is_none()); break; }
};
}
bcx
}
pub fn cleanup_and_Br(bcx: block, upto: block, target: BasicBlockRef) {
let _icx = push_ctxt("cleanup_and_Br");
cleanup_and_leave(bcx, Some(upto.llbb), Some(target));
@ -1526,7 +1557,7 @@ pub fn alloca_maybe_zeroed(cx: block, ty: Type, name: &str, zero: bool) -> Value
return llvm::LLVMGetUndef(ty.to_ref());
}
}
let initcx = base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas);
let initcx = base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas());
let p = Alloca(initcx, ty, name);
if zero { memzero(initcx, p, ty); }
p
@ -1539,24 +1570,26 @@ pub fn arrayalloca(cx: block, ty: Type, v: ValueRef) -> ValueRef {
return llvm::LLVMGetUndef(ty.to_ref());
}
}
return ArrayAlloca(base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas), ty, v);
return ArrayAlloca(base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas()), ty, v);
}
pub struct BasicBlocks {
sa: BasicBlockRef,
rt: BasicBlockRef
}
// Creates the standard set of basic blocks for a function
pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks {
pub fn mk_staticallocas_basic_block(llfn: ValueRef) -> BasicBlockRef {
unsafe {
let cx = task_llcx();
BasicBlocks {
sa: str::as_c_str("static_allocas",
|buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)),
rt: str::as_c_str("return",
|buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf))
}
str::as_c_str("static_allocas",
|buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf))
}
}
pub fn mk_return_basic_block(llfn: ValueRef) -> BasicBlockRef {
unsafe {
let cx = task_llcx();
str::as_c_str("return",
|buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf))
}
}
@ -1568,7 +1601,7 @@ pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype,
alloca(raw_block(fcx, false, fcx.get_llstaticallocas()), lloutputtype,
"__make_return_pointer")
}
}
@ -1596,8 +1629,6 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
id,
param_substs.repr(ccx.tcx));
let llbbs = mk_standard_basic_blocks(llfndecl);
let substd_output_type = match param_substs {
None => output_type,
Some(substs) => {
@ -1611,9 +1642,9 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
llvm::LLVMGetUndef(Type::i8p().to_ref())
},
llretptr: None,
llstaticallocas: llbbs.sa,
llstaticallocas: None,
llloadenv: None,
llreturn: llbbs.rt,
llreturn: None,
llself: None,
personality: None,
loop_ret: None,
@ -1757,16 +1788,24 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
// and builds the return block.
pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) {
pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) {
let _icx = push_ctxt("finish_fn");
tie_up_header_blocks(fcx, lltop);
build_return_block(fcx);
let ret_cx = match fcx.llreturn {
Some(llreturn) => {
if !last_bcx.terminated {
Br(last_bcx, llreturn);
}
raw_block(fcx, false, llreturn)
}
None => last_bcx
};
build_return_block(fcx, ret_cx);
}
// Builds the return block for a function.
pub fn build_return_block(fcx: fn_ctxt) {
let ret_cx = raw_block(fcx, false, fcx.llreturn);
pub fn build_return_block(fcx: fn_ctxt, ret_cx: block) {
// Return the value if this function immediate; otherwise, return void.
if fcx.llretptr.is_some() && fcx.has_immediate_return_value {
Ret(ret_cx, Load(ret_cx, fcx.llretptr.get()))
@ -1777,14 +1816,24 @@ pub fn build_return_block(fcx: fn_ctxt) {
pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
let _icx = push_ctxt("tie_up_header_blocks");
match fcx.llloadenv {
let llnext = match fcx.llloadenv {
Some(ll) => {
Br(raw_block(fcx, false, fcx.llstaticallocas), ll);
unsafe {
llvm::LLVMMoveBasicBlockBefore(ll, lltop);
}
Br(raw_block(fcx, false, ll), lltop);
ll
}
None => {
Br(raw_block(fcx, false, fcx.llstaticallocas), lltop);
None => lltop
};
match fcx.llstaticallocas {
Some(ll) => {
unsafe {
llvm::LLVMMoveBasicBlockBefore(ll, llnext);
}
Br(raw_block(fcx, false, ll), llnext);
}
None => ()
}
}
@ -1854,16 +1903,21 @@ pub fn trans_closure(ccx: @mut CrateContext,
}
finish(bcx);
cleanup_and_Br(bcx, bcx_top, fcx.llreturn);
match fcx.llreturn {
Some(llreturn) => cleanup_and_Br(bcx, bcx_top, llreturn),
None => bcx = cleanup_block(bcx, Some(bcx_top.llbb))
};
// Put return block after all other blocks.
// This somewhat improves single-stepping experience in debugger.
unsafe {
llvm::LLVMMoveBasicBlockAfter(fcx.llreturn, bcx.llbb);
for fcx.llreturn.iter().advance |&llreturn| {
llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb);
}
}
// Insert the mandatory first few basic blocks before lltop.
finish_fn(fcx, lltop);
finish_fn(fcx, lltop, bcx);
}
// trans_fn: creates an LLVM function corresponding to a source language
@ -2046,8 +2100,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
let arg_ty = arg_tys[i];
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
}
build_return(bcx);
finish_fn(fcx, lltop);
finish_fn(fcx, lltop, bcx);
}
pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def,
@ -2288,8 +2341,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
let args = ~[llenvarg];
Call(bcx, main_llfn, args);
build_return(bcx);
finish_fn(fcx, lltop);
finish_fn(fcx, lltop, bcx);
return llfdecl;
}

View File

@ -704,7 +704,7 @@ pub fn trans_call_inner(in_cx: block,
Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
}
}
base::cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
base::cleanup_and_leave(bcx, None, Some(bcx.fcx.get_llreturn()));
Unreachable(bcx);
bcx
}

View File

@ -178,13 +178,13 @@ pub struct fn_ctxt_ {
// the function, due to LLVM's quirks.
// A block for all the function's static allocas, so that LLVM
// will coalesce them into a single alloca call.
llstaticallocas: BasicBlockRef,
llstaticallocas: Option<BasicBlockRef>,
// A block containing code that copies incoming arguments to space
// 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.)
llloadenv: Option<BasicBlockRef>,
llreturn: BasicBlockRef,
llreturn: Option<BasicBlockRef>,
// The 'self' value currently in use in this function, if there
// is one.
//
@ -251,6 +251,21 @@ impl fn_ctxt_ {
}
}
pub fn get_llstaticallocas(&mut self) -> BasicBlockRef {
if self.llstaticallocas.is_none() {
self.llstaticallocas = Some(base::mk_staticallocas_basic_block(self.llfn));
}
self.llstaticallocas.get()
}
pub fn get_llreturn(&mut self) -> BasicBlockRef {
if self.llreturn.is_none() {
self.llreturn = Some(base::mk_return_basic_block(self.llfn));
}
self.llreturn.get()
}
}
pub type fn_ctxt = @mut fn_ctxt_;

View File

@ -67,13 +67,8 @@ pub fn trans_if(bcx: block,
expr::trans_to_datum(bcx, cond).to_result();
let then_bcx_in = scope_block(bcx, thn.info(), "then");
let else_bcx_in = scope_block(bcx, els.info(), "else");
let cond_val = bool_to_i1(bcx, cond_val);
CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);
debug!("then_bcx_in=%s, else_bcx_in=%s",
then_bcx_in.to_str(), else_bcx_in.to_str());
let then_bcx_out = trans_block(then_bcx_in, thn, dest);
let then_bcx_out = trans_block_cleanups(then_bcx_out,
@ -83,9 +78,10 @@ pub fn trans_if(bcx: block,
// because trans_expr will create another scope block
// context for the block, but we've already got the
// 'else' context
let else_bcx_out = match els {
let (else_bcx_in, next_bcx) = match els {
Some(elexpr) => {
match elexpr.node {
let else_bcx_in = scope_block(bcx, els.info(), "else");
let else_bcx_out = match elexpr.node {
ast::expr_if(_, _, _) => {
let elseif_blk = ast_util::block_from_expr(elexpr);
trans_block(else_bcx_in, &elseif_blk, dest)
@ -95,14 +91,25 @@ pub fn trans_if(bcx: block,
}
// would be nice to have a constraint on ifs
_ => bcx.tcx().sess.bug("strange alternative in if")
}
}
_ => else_bcx_in
};
let else_bcx_out = trans_block_cleanups(else_bcx_out,
block_cleanups(else_bcx_in));
return join_blocks(bcx, [then_bcx_out, else_bcx_out]);
};
let else_bcx_out = trans_block_cleanups(else_bcx_out,
block_cleanups(else_bcx_in));
(else_bcx_in, join_blocks(bcx, [then_bcx_out, else_bcx_out]))
}
_ => {
let next_bcx = sub_block(bcx, "next");
Br(then_bcx_out, next_bcx.llbb);
(next_bcx, next_bcx)
}
};
debug!("then_bcx_in=%s, else_bcx_in=%s",
then_bcx_in.to_str(), else_bcx_in.to_str());
CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);
next_bcx
}
pub fn join_blocks(parent_bcx: block, in_cxs: &[block]) -> block {
@ -279,7 +286,7 @@ pub fn trans_break_cont(bcx: block,
// This is a return from a loop body block
None => {
Store(bcx, C_bool(!to_end), bcx.fcx.llretptr.get());
cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
cleanup_and_leave(bcx, None, Some(bcx.fcx.get_llreturn()));
Unreachable(bcx);
return bcx;
}
@ -328,7 +335,7 @@ pub fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
}
_ => ()
}
cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
cleanup_and_leave(bcx, None, Some(bcx.fcx.get_llreturn()));
Unreachable(bcx);
return bcx;
}

View File

@ -164,7 +164,10 @@ fn build_shim_fn_(ccx: @mut CrateContext,
// follow the normal Rust calling conventions.
tie_up_header_blocks(fcx, lltop);
let ret_cx = raw_block(fcx, false, fcx.llreturn);
let ret_cx = match fcx.llreturn {
Some(llreturn) => raw_block(fcx, false, llreturn),
None => bcx
};
RetVoid(ret_cx);
return llshimfn;
@ -194,7 +197,7 @@ fn build_wrap_fn_(ccx: @mut CrateContext,
// the C ABI.
if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) {
let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output);
fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.llstaticallocas),
fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.get_llstaticallocas()),
lloutputtype,
""));
}
@ -217,7 +220,10 @@ fn build_wrap_fn_(ccx: @mut CrateContext,
tie_up_header_blocks(fcx, lltop);
// Then return according to the C ABI.
let return_context = raw_block(fcx, false, fcx.llreturn);
let return_context = match fcx.llreturn {
Some(llreturn) => raw_block(fcx, false, llreturn),
None => bcx
};
let llfunctiontype = val_ty(llwrapfn);
let llfunctiontype = llfunctiontype.element_type();
@ -388,7 +394,6 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
tys.ret_def,
llargbundle,
llretval);
build_return(bcx);
}
let lname = link_name(ccx, foreign_item);
@ -438,8 +443,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
build_return(bcx);
finish_fn(fcx, lltop);
finish_fn(fcx, lltop, bcx);
}
// FIXME (#2535): this is very shaky and probably gets ABIs wrong all
@ -467,8 +471,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
build_return(bcx);
finish_fn(fcx, lltop);
finish_fn(fcx, lltop, bcx);
}
fn build_wrap_fn(ccx: @mut CrateContext,
@ -534,7 +537,6 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]);
Store(bcx, Load(bcx, llretptr), retptr);
}
build_return(bcx);
}
}
}
@ -629,8 +631,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
}
}
build_return(bcx);
finish_fn(fcx, lltop);
finish_fn(fcx, lltop, bcx);
return;
}
@ -1124,8 +1125,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
ccx.sess.span_bug(item.span, "unknown intrinsic");
}
}
build_return(bcx);
finish_fn(fcx, lltop);
finish_fn(fcx, lltop, bcx);
}
/**
@ -1257,8 +1257,6 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext,
// NB: The return pointer in the Rust ABI function is wired
// directly into the return slot in the shim struct.
}
build_return(bcx);
}
let shim_name = link::mangle_internal_name_by_path(
@ -1314,7 +1312,6 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext,
fn build_ret(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) {
let _icx = push_ctxt("foreign::foreign::wrap::build_ret");
tys.fn_ty.build_wrap_ret(bcx, tys.llsig.llarg_tys, llargbundle);
build_return(bcx);
}
}

View File

@ -348,9 +348,9 @@ pub fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint)
return cx;
}
pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
let _icx = push_ctxt("make_visit_glue");
let bcx = do with_scope(bcx, None, "visitor cleanup") |bcx| {
do with_scope(bcx, None, "visitor cleanup") |bcx| {
let mut bcx = bcx;
let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx());
let v = PointerCast(bcx, v, type_of::type_of(bcx.ccx(), object_ty).ptr_to());
@ -358,14 +358,13 @@ pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
// The visitor is a boxed object and needs to be dropped
add_clean(bcx, v, object_ty);
bcx
};
build_return(bcx);
}
}
pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_free_glue");
let bcx = match ty::get(t).sty {
match ty::get(t).sty {
ty::ty_box(body_mt) => {
let v = Load(bcx, v);
let body = GEPi(bcx, v, [0u, abi::box_field_body]);
@ -389,9 +388,7 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
tvec::make_uniq_free_glue(bcx, v, t)
}
ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
make_free_glue(bcx, v,
tvec::expand_boxed_vec_ty(bcx.tcx(), t));
return;
make_free_glue(bcx, v, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
}
ty::ty_closure(_) => {
closure::make_closure_glue(bcx, v, t, free_ty)
@ -400,8 +397,7 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
closure::make_opaque_cbox_free_glue(bcx, ck, v)
}
_ => bcx
};
build_return(bcx);
}
}
pub fn trans_struct_drop_flag(bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id,
@ -475,11 +471,11 @@ pub fn trans_struct_drop(mut bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::
bcx
}
pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) -> block {
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_drop_glue");
let ccx = bcx.ccx();
let bcx = match ty::get(t).sty {
match ty::get(t).sty {
ty::ty_box(_) | ty::ty_opaque_box |
ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) => {
decr_refcnt_maybe_free(bcx, Load(bcx, v0), Some(v0), t)
@ -542,8 +538,7 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
iter_structural_ty(bcx, v0, t, drop_ty)
} else { bcx }
}
};
build_return(bcx);
}
}
// box_ptr_ptr is optional, it is constructed if not supplied.
@ -569,10 +564,10 @@ pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef,
}
pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
let _icx = push_ctxt("make_take_glue");
// NB: v is a *pointer* to type t here, not a direct value.
let bcx = match ty::get(t).sty {
match ty::get(t).sty {
ty::ty_box(_) | ty::ty_opaque_box |
ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
@ -638,9 +633,7 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
iter_structural_ty(bcx, v, t, take_ty)
}
_ => bcx
};
build_return(bcx);
}
}
pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
@ -690,7 +683,7 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info {
return inf;
}
pub type glue_helper<'self> = &'self fn(block, ValueRef, ty::t);
pub type glue_helper<'self> = &'self fn(block, ValueRef, ty::t) -> block;
pub fn declare_generic_glue(ccx: &mut CrateContext, t: ty::t, llfnty: Type,
name: &str) -> ValueRef {
@ -723,11 +716,9 @@ pub fn make_generic_glue_inner(ccx: @mut CrateContext,
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) };
let llty = type_of(ccx, t);
let llrawptr0 = PointerCast(bcx, llrawptr0, llty.ptr_to());
helper(bcx, llrawptr0, t);
let bcx = helper(bcx, llrawptr0, t);
// This is from the general finish fn, but that emits a ret {} that we don't want
Br(raw_block(fcx, false, fcx.llstaticallocas), lltop);
RetVoid(raw_block(fcx, false, fcx.llreturn));
finish_fn(fcx, lltop, bcx);
return llfn;
}

View File

@ -299,12 +299,15 @@ impl Reflector {
//
llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
};
let bcx = top_scope_block(fcx, None);
let mut bcx = top_scope_block(fcx, None);
let arg = BitCast(bcx, arg, llptrty);
let ret = adt::trans_get_discr(bcx, repr, arg);
Store(bcx, ret, fcx.llretptr.get());
cleanup_and_Br(bcx, bcx, fcx.llreturn);
finish_fn(fcx, bcx.llbb);
match fcx.llreturn {
Some(llreturn) => cleanup_and_Br(bcx, bcx, llreturn),
None => bcx = cleanup_block(bcx, Some(bcx.llbb))
};
finish_fn(fcx, bcx.llbb, bcx);
llfdecl
};