diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 05992c431dac..d1a9e387d00e 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -984,6 +984,8 @@ pub mod llvm { pub unsafe fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef; #[fast_ffi] pub unsafe fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef; + #[fast_ffi] + pub unsafe fn LLVMInstructionEraseFromParent(Inst: ValueRef); /* Operations on call sites */ #[fast_ffi] diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 5536fa6daa73..2512b6e3ece8 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -41,7 +41,7 @@ use middle::trans::_match; use middle::trans::adt; use middle::trans::base; use middle::trans::build::*; -use middle::trans::builder::noname; +use middle::trans::builder::{Builder, noname}; use middle::trans::callee; use middle::trans::common::*; use middle::trans::consts; @@ -1503,11 +1503,12 @@ pub fn memcpy_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) { } pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) { + if cx.unreachable { return; } let _icx = push_ctxt("zero_mem"); let bcx = cx; let ccx = cx.ccx(); let llty = type_of::type_of(ccx, t); - memzero(bcx, llptr, llty); + memzero(&B(bcx), llptr, llty); } // Always use this function instead of storing a zero constant to the memory @@ -1515,9 +1516,9 @@ pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) { // allocation for large data structures, and the generated code will be // awful. (A telltale sign of this is large quantities of // `mov [byte ptr foo],0` in the generated code.) -pub fn memzero(cx: block, llptr: ValueRef, ty: Type) { +pub fn memzero(b: &Builder, llptr: ValueRef, ty: Type) { let _icx = push_ctxt("memzero"); - let ccx = cx.ccx(); + let ccx = b.ccx; let intrinsic_key = match ccx.sess.targ_cfg.arch { X86 | Arm | Mips => "llvm.memset.p0i8.i32", @@ -1525,12 +1526,12 @@ pub fn memzero(cx: block, llptr: ValueRef, ty: Type) { }; let llintrinsicfn = ccx.intrinsics.get_copy(&intrinsic_key); - let llptr = PointerCast(cx, llptr, Type::i8().ptr_to()); + let llptr = b.pointercast(llptr, Type::i8().ptr_to()); let llzeroval = C_u8(0); - let size = IntCast(cx, machine::llsize_of(ccx, ty), ccx.int_type); + let size = machine::llsize_of(ccx, ty); let align = C_i32(llalign_of_min(ccx, ty) as i32); let volatile = C_i1(false); - Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]); + b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile]); } pub fn alloc_ty(bcx: block, t: ty::t, name: &str) -> ValueRef { @@ -1553,9 +1554,12 @@ pub fn alloca_maybe_zeroed(cx: block, ty: Type, name: &str, zero: bool) -> Value return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); } } - let initcx = base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas()); - let p = Alloca(initcx, ty, name); - if zero { memzero(initcx, p, ty); } + let p = Alloca(cx, ty, name); + if zero { + let b = cx.fcx.ccx.builder(); + b.position_before(cx.fcx.alloca_insert_pt.get()); + memzero(&b, p, ty); + } p } @@ -1566,7 +1570,7 @@ 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.get_llstaticallocas()), ty, v); + return ArrayAlloca(cx, ty, v); } pub struct BasicBlocks { @@ -1597,8 +1601,8 @@ 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.get_llstaticallocas()), lloutputtype, - "__make_return_pointer") + let bcx = fcx.entry_bcx.get(); + Alloca(bcx, lloutputtype, "__make_return_pointer") } } } @@ -1616,6 +1620,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, output_type: ty::t, skip_retptr: bool, param_substs: Option<@param_substs>, + opt_node_info: Option, sp: Option) -> fn_ctxt { for param_substs.iter().advance |p| { p.validate(); } @@ -1639,8 +1644,8 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, llvm::LLVMGetUndef(Type::i8p().to_ref()) }, llretptr: None, - llstaticallocas: None, - llloadenv: None, + entry_bcx: None, + alloca_insert_pt: None, llreturn: None, llself: None, personality: None, @@ -1658,6 +1663,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, fcx.llenv = unsafe { llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint) }; + + unsafe { + let entry_bcx = top_scope_block(fcx, opt_node_info); + Load(entry_bcx, C_null(Type::i8p())); + + fcx.entry_bcx = Some(entry_bcx); + fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb)); + } + if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) { fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type)); } @@ -1670,7 +1684,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext, output_type: ty::t, sp: Option) -> fn_ctxt { - new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, sp) + new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, None, sp) } // NB: must keep 4 fns in sync: @@ -1785,9 +1799,8 @@ 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, last_bcx: block) { +pub fn finish_fn(fcx: fn_ctxt, last_bcx: block) { let _icx = push_ctxt("finish_fn"); - tie_up_header_blocks(fcx, lltop); let ret_cx = match fcx.llreturn { Some(llreturn) => { @@ -1799,6 +1812,7 @@ pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) { None => last_bcx }; build_return_block(fcx, ret_cx); + fcx.cleanup(); } // Builds the return block for a function. @@ -1811,29 +1825,6 @@ 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"); - let llnext = match fcx.llloadenv { - Some(ll) => { - unsafe { - llvm::LLVMMoveBasicBlockBefore(ll, lltop); - } - Br(raw_block(fcx, false, ll), lltop); - ll - } - None => lltop - }; - match fcx.llstaticallocas { - Some(ll) => { - unsafe { - llvm::LLVMMoveBasicBlockBefore(ll, llnext); - } - Br(raw_block(fcx, false, ll), llnext); - } - None => () - } -} - pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, } // trans_closure: Builds an LLVM function out of a source function. @@ -1866,6 +1857,7 @@ pub fn trans_closure(ccx: @mut CrateContext, output_type, false, param_substs, + body.info(), Some(body.span)); let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs); @@ -1877,9 +1869,8 @@ pub fn trans_closure(ccx: @mut CrateContext, // Create the first basic block in the function and keep a handle on it to // pass to finish_fn later. - let bcx_top = top_scope_block(fcx, body.info()); + let bcx_top = fcx.entry_bcx.get(); let mut bcx = bcx_top; - let lltop = bcx.llbb; let block_ty = node_id_type(bcx, body.id); let arg_tys = ty::ty_fn_args(node_id_type(bcx, id)); @@ -1915,7 +1906,7 @@ pub fn trans_closure(ccx: @mut CrateContext, } // Insert the mandatory first few basic blocks before lltop. - finish_fn(fcx, lltop, bcx); + finish_fn(fcx, bcx); } // trans_fn: creates an LLVM function corresponding to a source language @@ -2085,12 +2076,12 @@ pub fn trans_enum_variant_or_tuple_like_struct( result_ty, false, param_substs, + None, None); let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args); - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; + let bcx = fcx.entry_bcx.get(); let arg_tys = ty::ty_fn_args(ctor_ty); insert_synthetic_type_entries(bcx, fn_args, arg_tys); @@ -2108,7 +2099,7 @@ pub fn trans_enum_variant_or_tuple_like_struct( let arg_ty = arg_tys[i]; memcpy_ty(bcx, lldestptr, llarg, arg_ty); } - finish_fn(fcx, lltop, bcx); + finish_fn(fcx, bcx); } pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def, @@ -2336,9 +2327,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, // be updated if this assertion starts to fail. assert!(fcx.has_immediate_return_value); - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; - + let bcx = fcx.entry_bcx.get(); // Call main. let llenvarg = unsafe { let env_arg = fcx.env_arg_pos(); @@ -2347,7 +2336,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, let args = ~[llenvarg]; Call(bcx, main_llfn, args); - finish_fn(fcx, lltop, bcx); + finish_fn(fcx, bcx); return llfdecl; } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index 7861f658f53e..a8c7efb2ad43 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -318,14 +318,18 @@ pub fn ArrayMalloc(cx: block, Ty: Type, Val: ValueRef) -> ValueRef { pub fn Alloca(cx: block, Ty: Type, name: &str) -> ValueRef { unsafe { if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); } - B(cx).alloca(Ty, name) + let b = cx.fcx.ccx.builder(); + b.position_before(cx.fcx.alloca_insert_pt.get()); + b.alloca(Ty, name) } } pub fn ArrayAlloca(cx: block, Ty: Type, Val: ValueRef) -> ValueRef { unsafe { if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); } - B(cx).array_alloca(Ty, Val) + let b = cx.fcx.ccx.builder(); + b.position_before(cx.fcx.alloca_insert_pt.get()); + b.array_alloca(Ty, Val) } } diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 7507f19ec200..cdde96393a14 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -11,7 +11,7 @@ use back::abi; use back::link::{mangle_internal_name_by_path_and_seq}; -use lib::llvm::{llvm, ValueRef}; +use lib::llvm::ValueRef; use middle::moves; use middle::trans::base::*; use middle::trans::build::*; @@ -25,7 +25,6 @@ use util::ppaux::ty_to_str; use middle::trans::type_::Type; -use std::str; use std::vec; use syntax::ast; use syntax::ast_map::path_name; @@ -331,23 +330,7 @@ pub fn load_environment(fcx: fn_ctxt, return; } - let llloadenv = match fcx.llloadenv { - Some(ll) => ll, - None => { - let ll = - str::as_c_str("load_env", - |buf| - unsafe { - llvm::LLVMAppendBasicBlockInContext(fcx.ccx.llcx, - fcx.llfn, - buf) - }); - fcx.llloadenv = Some(ll); - ll - } - }; - - let bcx = raw_block(fcx, false, llloadenv); + let bcx = fcx.entry_bcx.get(); // Load a pointer to the closure data, skipping over the box header: let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index d90614ebc021..f53f15a83d71 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -174,17 +174,14 @@ pub struct fn_ctxt_ { // always be Some. llretptr: Option, + entry_bcx: Option, + // These elements: "hoisted basic blocks" containing // 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 static allocas, so that LLVM - // will coalesce them into a single alloca call. - 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 - // allowing most any operation to be performed on them.) - llloadenv: Option, + // A marker for the place where we want to insert the function's static + // allocas, so that LLVM will coalesce them into a single alloca call. + alloca_insert_pt: Option, llreturn: Option, // The 'self' value currently in use in this function, if there // is one. @@ -252,12 +249,12 @@ 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)); + pub fn cleanup(&mut self) { + unsafe { + llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt.get()); } - - self.llstaticallocas.get() + // Remove the cycle between fcx and bcx, so memory can be freed + self.entry_bcx = None; } pub fn get_llreturn(&mut self) -> BasicBlockRef { diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 355e2f57b2c3..08fbfdee9eac 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -149,8 +149,7 @@ fn build_shim_fn_(ccx: @mut CrateContext, // Declare the body of the shim function: let fcx = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None); - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; + let bcx = fcx.entry_bcx.get(); let llargbundle = get_param(llshimfn, 0u); let llargvals = arg_builder(bcx, tys, llargbundle); @@ -162,13 +161,12 @@ fn build_shim_fn_(ccx: @mut CrateContext, // Don't finish up the function in the usual way, because this doesn't // follow the normal Rust calling conventions. - tie_up_header_blocks(fcx, lltop); - let ret_cx = match fcx.llreturn { Some(llreturn) => raw_block(fcx, false, llreturn), None => bcx }; RetVoid(ret_cx); + fcx.cleanup(); return llshimfn; } @@ -192,19 +190,15 @@ fn build_wrap_fn_(ccx: @mut CrateContext, ret_builder: wrap_ret_builder) { let _icx = push_ctxt("foreign::build_wrap_fn_"); let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None); + let bcx = fcx.entry_bcx.get(); // Patch up the return type if it's not immediate and we're returning via // 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.get_llstaticallocas()), - lloutputtype, - "")); + fcx.llretptr = Some(alloca(bcx, lloutputtype, "")); } - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; - // Allocate the struct and write the arguments into it. let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle"); arg_builder(bcx, tys, llwrapfn, llargbundle); @@ -215,10 +209,6 @@ fn build_wrap_fn_(ccx: @mut CrateContext, Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]); ret_builder(bcx, tys, llargbundle); - // Perform a custom version of `finish_fn`. First, tie up the header - // blocks. - tie_up_header_blocks(fcx, lltop); - // Then return according to the C ABI. let return_context = match fcx.llreturn { Some(llreturn) => raw_block(fcx, false, llreturn), @@ -239,6 +229,7 @@ fn build_wrap_fn_(ccx: @mut CrateContext, let llretptr = BitCast(return_context, fcx.llretptr.get(), return_type.ptr_to()); Ret(return_context, Load(return_context, llretptr)); } + fcx.cleanup(); } // For each foreign function F, we generate a wrapper function W and a shim @@ -430,8 +421,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, debug!("build_direct_fn(%s)", link_name(ccx, item)); let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None); - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; + let bcx = fcx.entry_bcx.get(); let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc); let ty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(item.id)).ty; @@ -443,7 +433,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()); } - finish_fn(fcx, lltop, bcx); + finish_fn(fcx, bcx); } // FIXME (#2535): this is very shaky and probably gets ABIs wrong all @@ -456,8 +446,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, debug!("build_fast_ffi_fn(%s)", link_name(ccx, item)); let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None); - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; + let bcx = fcx.entry_bcx.get(); let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc); set_no_inline(fcx.llfn); set_fixed_stack_segment(fcx.llfn); @@ -471,7 +460,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()); } - finish_fn(fcx, lltop, bcx); + finish_fn(fcx, bcx); } fn build_wrap_fn(ccx: @mut CrateContext, @@ -619,6 +608,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, output_type, true, Some(substs), + None, Some(item.span)); set_always_inline(fcx.llfn); @@ -628,7 +618,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, set_fixed_stack_segment(fcx.llfn); } - let mut bcx = top_scope_block(fcx, None); + let mut bcx = fcx.entry_bcx.get(); let first_real_arg = fcx.arg_pos(0u); let nm = ccx.sess.str_of(item.ident); @@ -694,6 +684,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, } } + fcx.cleanup(); return; } @@ -942,6 +933,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, ccx.sess.span_bug(item.span, "unknown intrinsic"); } } + fcx.cleanup(); } /** diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 4a2072364e94..d3f5b9844c93 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -615,7 +615,7 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) -> block { // Zero out the struct unsafe { let ty = Type::from_ref(llvm::LLVMTypeOf(v)); - memzero(bcx, v, ty); + memzero(&B(bcx), v, ty); } } @@ -707,13 +707,12 @@ pub fn make_generic_glue_inner(ccx: @mut CrateContext, // llfn is expected be declared to take a parameter of the appropriate // type, so we don't need to explicitly cast the function parameter. - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; + let bcx = fcx.entry_bcx.get(); let rawptr0_arg = fcx.arg_pos(0u); let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) }; let bcx = helper(bcx, llrawptr0, t); - finish_fn(fcx, lltop, bcx); + finish_fn(fcx, bcx); return llfn; } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 49f9f4481b98..6df1df454ff4 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -303,7 +303,7 @@ impl Reflector { // llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint) }; - let mut bcx = top_scope_block(fcx, None); + let mut bcx = fcx.entry_bcx.get(); let arg = BitCast(bcx, arg, llptrty); let ret = adt::trans_get_discr(bcx, repr, arg); Store(bcx, ret, fcx.llretptr.get()); @@ -311,7 +311,7 @@ impl Reflector { Some(llreturn) => cleanup_and_Br(bcx, bcx, llreturn), None => bcx = cleanup_block(bcx, Some(bcx.llbb)) }; - finish_fn(fcx, bcx.llbb, bcx); + finish_fn(fcx, bcx); llfdecl }; diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index 5b6c3ed2f52f..48888760fc66 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -409,6 +409,7 @@ LLVMInsertBasicBlock LLVMInsertBasicBlockInContext LLVMInsertIntoBuilder LLVMInsertIntoBuilderWithName +LLVMInstructionEraseFromParent LLVMInt16Type LLVMInt16TypeInContext LLVMInt1Type