From dcd5d14e6cbb32aeccae3d12951181c525070ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Sat, 13 Jul 2013 03:25:46 +0200 Subject: [PATCH 1/3] Avoid return blocks that have only a single predecessor Currently, we always create a dedicated "return" basic block, but when there's only a single predecessor for that block, it can be merged with that predecessor. We can achieve that merge by only creating the return block on demand, avoiding its creation when its not required. Reduces the pre-optimization size of librustc.ll created with --passes "" by about 90k lines which equals about 4%. --- src/librustc/middle/trans/base.rs | 89 ++++++++++++++++++------ src/librustc/middle/trans/callee.rs | 2 +- src/librustc/middle/trans/common.rs | 9 ++- src/librustc/middle/trans/controlflow.rs | 4 +- src/librustc/middle/trans/foreign.rs | 27 ++++--- src/librustc/middle/trans/glue.rs | 41 +++++------ src/librustc/middle/trans/reflect.rs | 9 ++- 7 files changed, 113 insertions(+), 68 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index c0336c8e60d5..bbd676c87b49 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1102,11 +1102,6 @@ pub fn trans_trace(bcx: block, sp_opt: Option, 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) -> 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)); @@ -1544,7 +1575,6 @@ pub fn arrayalloca(cx: block, ty: Type, v: ValueRef) -> ValueRef { pub struct BasicBlocks { sa: BasicBlockRef, - rt: BasicBlockRef } // Creates the standard set of basic blocks for a function @@ -1554,12 +1584,18 @@ pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks { 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)) } } } +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)) + } +} + // Creates and returns space for, or returns the argument representing, the // slot where the return value of the function must go. pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef { @@ -1613,7 +1649,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, llretptr: None, llstaticallocas: llbbs.sa, llloadenv: None, - llreturn: llbbs.rt, + llreturn: None, llself: None, personality: None, loop_ret: None, @@ -1757,16 +1793,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())) @@ -1854,16 +1898,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 +2095,7 @@ pub fn trans_enum_variant_or_tuple_like_struct( 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 +2336,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; } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 01bd69f24fc9..7b7989879a63 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -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 } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 1a45ce36af2f..2e016377e75c 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -184,7 +184,7 @@ pub struct fn_ctxt_ { // (LLVM requires that arguments be copied to local allocas before // allowing most any operation to be performed on them.) llloadenv: Option, - llreturn: BasicBlockRef, + llreturn: Option, // The 'self' value currently in use in this function, if there // is one. // @@ -251,6 +251,13 @@ impl fn_ctxt_ { } } + 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_; diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 6cbd6304847e..e9eb7ff086dd 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -279,7 +279,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 +328,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; } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 9019cd72ff8a..1ad5a543e661 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -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; @@ -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); } } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index b6f226683df9..418c89e603d0 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -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; } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index a3b544dbc619..dee40f32169e 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -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 }; From 5df2bb1bccd8394dbd73ffa52dea1151dcd0b0ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Sat, 13 Jul 2013 04:09:57 +0200 Subject: [PATCH 2/3] Avoid empty "static_allocas" blocks When there are no allocas, we don't need a block for them. --- src/librustc/middle/trans/base.rs | 37 ++++++++++++++++------------ src/librustc/middle/trans/common.rs | 10 +++++++- src/librustc/middle/trans/foreign.rs | 2 +- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index bbd676c87b49..1173fa494196 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1557,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 @@ -1570,21 +1570,18 @@ 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, } -// 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)), - } + str::as_c_str("static_allocas", + |buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)) } } @@ -1604,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") } } @@ -1632,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) => { @@ -1647,7 +1642,7 @@ 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: None, llself: None, @@ -1821,14 +1816,24 @@ pub fn build_return_block(fcx: fn_ctxt, ret_cx: block) { 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 => () } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 2e016377e75c..83029a90260f 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -178,7 +178,7 @@ 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, // 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 @@ -251,6 +251,14 @@ 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)); diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 1ad5a543e661..edf003e3e529 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -197,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, "")); } From 1d2e1a9ae5cc1affe54e3280cf272197a036beaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Sat, 13 Jul 2013 04:10:41 +0200 Subject: [PATCH 3/3] Avoid empty "else" blocks If an "if" expression has no "else", we don't have to create an LLVM basic block either. --- src/librustc/middle/trans/controlflow.rs | 35 ++++++++++++++---------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index e9eb7ff086dd..81260428f241 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -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 {